[
  {
    "path": ".gitconfig",
    "content": "[core]\n    hooksPath = git_hooks\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "* @imp2002\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "---\nversion: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/.github/workflows/\"\n    schedule:\n      interval: \"weekly\"\n\n  - package-ecosystem: \"cargo\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n...\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "# Pull Request Template\n\n## Description\n\nPlease include a summary of the change and which issue (if any) is fixed.\nA brief description of the algorithm and your implementation method can be helpful too. If the implemented method/algorithm is not so\nwell-known, it would be helpful to add a link to an article explaining it with more details.\n\n## Type of change\n\nPlease delete options that are not relevant.\n\n- [ ] Bug fix (non-breaking change which fixes an issue)\n- [ ] New feature (non-breaking change which adds functionality)\n- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)\n\n## Checklist:\n\n- [ ] I ran bellow commands using the latest version of **rust nightly**.\n- [ ] I ran `cargo clippy --all -- -D warnings` just before my last commit and fixed any issue that was found.\n- [ ] I ran `cargo fmt` just before my last commit.\n- [ ] I ran `cargo test` just before my last commit and all tests passed.\n- [ ] I added my algorithm to the corresponding `mod.rs` file within its own folder, and in any parent folder(s).\n- [ ] I added my algorithm to `DIRECTORY.md` with the correct link.\n- [ ] I checked `COUNTRIBUTING.md` and my code follows its guidelines.\n\nPlease make sure that if there is a test that takes too long to run ( > 300ms), you `#[ignore]` that or\ntry to optimize your code or make the test easier to run. We have this rule because we have hundreds of\ntests to run; If each one of them took 300ms, we would have to wait for a long time.\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: build\n\n'on':\n  pull_request:\n  workflow_dispatch:\n  schedule:\n    - cron: '51 2 * * 4'\n\npermissions:\n  contents: read\n\njobs:\n  fmt:\n    name: cargo fmt\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6\n    - name: cargo fmt\n      run: cargo fmt --all -- --check\n\n  clippy:\n    name: cargo clippy\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6\n    - name: cargo clippy\n      run: cargo clippy --all --all-targets -- -D warnings\n\n  test:\n    name: cargo test\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6\n    - name: cargo test\n      run: cargo test\n"
  },
  {
    "path": ".github/workflows/code_ql.yml",
    "content": "---\nname: code_ql\n\n'on':\n  workflow_dispatch:\n  push:\n    branches:\n      - master\n  pull_request:\n  schedule:\n    - cron: '10 7 * * 1'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: 'ubuntu-latest'\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language:\n          - actions\n          - rust\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v4\n        with:\n          languages: ${{ matrix.language }}\n          build-mode: none\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v4\n        with:\n          category: \"/language:${{matrix.language}}\"\n...\n"
  },
  {
    "path": ".github/workflows/directory_workflow.yml",
    "content": "name: build_directory_md\non:\n  push:\n    branches: [master]\n\npermissions:\n  contents: read\n\njobs:\n  MainSequence:\n    name: DIRECTORY.md\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n      - uses: actions/setup-python@v6\n      - name: Setup Git Specs\n        run: |\n          git config --global user.name \"$GITHUB_ACTOR\"\n          git config --global user.email \"$GITHUB_ACTOR@users.noreply.github.com\"\n          git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY\n      - name: Update DIRECTORY.md\n        run: |\n         cargo run --manifest-path=.github/workflows/scripts/build_directory/Cargo.toml\n      - name: Commit DIRECTORY.md\n        run: |\n         git add DIRECTORY.md\n         git commit -m \"Update DIRECTORY.md [skip actions]\" ||  true\n         git push origin HEAD:$GITHUB_REF || true\n"
  },
  {
    "path": ".github/workflows/scripts/build_directory/Cargo.toml",
    "content": "[package]\nname = \"build_directory\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": ".github/workflows/scripts/build_directory/src/lib.rs",
    "content": "use std::{\n    error::Error,\n    fs,\n    path::{Path, PathBuf},\n};\n\nstatic URL_BASE: &str = \"https://github.com/TheAlgorithms/Rust/blob/master\";\n\nfn good_filepaths(top_dir: &Path) -> Result<Vec<String>, Box<dyn Error>> {\n    let mut good_fs = Vec::new();\n    if top_dir.is_dir() {\n        for entry in fs::read_dir(top_dir)? {\n            let entry = entry?;\n            let path = entry.path();\n            if entry.file_name().to_str().unwrap().starts_with('.')\n                || entry.file_name().to_str().unwrap().starts_with('_')\n            {\n                continue;\n            }\n            if path.is_dir() {\n                let mut other = good_filepaths(&path)?;\n                good_fs.append(&mut other);\n            } else if entry.file_name().to_str().unwrap().ends_with(\".rs\")\n                && entry.file_name().to_str().unwrap() != \"mod.rs\"\n            {\n                good_fs.push(\n                    path.into_os_string()\n                        .into_string()\n                        .unwrap()\n                        .split_at(2)\n                        .1\n                        .to_string(),\n                );\n            }\n        }\n    }\n    good_fs.sort();\n    Ok(good_fs)\n}\n\nfn md_prefix(indent_count: usize) -> String {\n    if indent_count > 0 {\n        format!(\"{}*\", \"  \".repeat(indent_count))\n    } else {\n        \"\\n##\".to_string()\n    }\n}\n\nfn print_path(old_path: String, new_path: String) -> (String, String) {\n    let old_parts = old_path\n        .split(std::path::MAIN_SEPARATOR)\n        .collect::<Vec<&str>>();\n    let mut result = String::new();\n    for (count, new_part) in new_path.split(std::path::MAIN_SEPARATOR).enumerate() {\n        if count + 1 > old_parts.len() || old_parts[count] != new_part {\n            println!(\"{} {}\", md_prefix(count), to_title(new_part));\n            result.push_str(format!(\"{} {}\\n\", md_prefix(count), to_title(new_part)).as_str());\n        }\n    }\n    (new_path, result)\n}\n\npub fn build_directory_md(top_dir: &Path) -> Result<String, Box<dyn Error>> {\n    let mut old_path = String::from(\"\");\n    let mut result = String::new();\n    for filepath in good_filepaths(top_dir)? {\n        let mut filepath = PathBuf::from(filepath);\n        let filename = filepath.file_name().unwrap().to_owned();\n        filepath.pop();\n        let filepath = filepath.into_os_string().into_string().unwrap();\n        if filepath != old_path {\n            let path_res = print_path(old_path, filepath);\n            old_path = path_res.0;\n            result.push_str(path_res.1.as_str());\n        }\n        let url = format!(\"{}/{}\", old_path, filename.to_string_lossy());\n        let url = get_addr(&url);\n        let indent = old_path.matches(std::path::MAIN_SEPARATOR).count() + 1;\n        let filename = to_title(filename.to_str().unwrap().split('.').collect::<Vec<&str>>()[0]);\n        println!(\"{} [{}]({})\", md_prefix(indent), filename, url);\n        result.push_str(format!(\"{} [{}]({})\\n\", md_prefix(indent), filename, url).as_str());\n    }\n    Ok(result)\n}\n\nfn to_title(name: &str) -> String {\n    let mut change = true;\n    name.chars()\n        .map(move |letter| {\n            if change && !letter.is_numeric() {\n                change = false;\n                letter.to_uppercase().next().unwrap()\n            } else if letter == '_' {\n                change = true;\n                ' '\n            } else {\n                if letter.is_numeric() || !letter.is_alphanumeric() {\n                    change = true;\n                }\n                letter\n            }\n        })\n        .collect::<String>()\n}\n\nfn get_addr(addr: &str) -> String {\n    if cfg!(windows) {\n        format!(\"{}/{}\", URL_BASE, switch_backslash(addr))\n    } else {\n        format!(\"{}/{}\", URL_BASE, addr)\n    }\n}\n\n// Function that changes '\\' to '/' (for Windows builds only)\nfn switch_backslash(addr: &str) -> String {\n    addr.chars()\n        .map(|mut symbol| {\n            if symbol == '\\\\' {\n                symbol = '/';\n            }\n            symbol\n        })\n        .collect::<String>()\n}\n"
  },
  {
    "path": ".github/workflows/scripts/build_directory/src/main.rs",
    "content": "use std::{fs::File, io::Write, path::Path};\n\nuse build_directory::build_directory_md;\nfn main() -> Result<(), std::io::Error> {\n    let mut file = File::create(\"DIRECTORY.md\").unwrap(); // unwrap for panic\n\n    match build_directory_md(Path::new(\".\")) {\n        Ok(buf) => {\n            file.write_all(\"# List of all files\\n\".as_bytes())?;\n            file.write_all(buf.as_bytes())?;\n        }\n        Err(err) => {\n            panic!(\"Error while creating string: {err}\");\n        }\n    }\n    Ok(())\n}\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: 'Close stale issues and PRs'\non:\n  schedule:\n    - cron: '0 0 * * *'\npermissions:\n  contents: read\n\njobs:\n  stale:\n    permissions:\n      issues: write\n      pull-requests: write\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/stale@v10\n        with:\n          stale-issue-message: 'This issue has been automatically marked as abandoned because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'\n          close-issue-message: 'Please ping one of the maintainers once you add more information and updates here. If this is not the case and you need some help, feel free to ask for help in our [Gitter](https://gitter.im/TheAlgorithms) channel. Thank you for your contributions!'\n          stale-pr-message: 'This pull request has been automatically marked as abandoned because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'\n          close-pr-message: 'Please ping one of the maintainers once you commit the changes requested or make improvements on the code. If this is not the case and you need some help, feel free to ask for help in our [Gitter](https://gitter.im/TheAlgorithms) channel. Thank you for your contributions!'\n          exempt-issue-labels: 'dont-close'\n          exempt-pr-labels: 'dont-close'\n          days-before-stale: 30\n          days-before-close: 7\n"
  },
  {
    "path": ".github/workflows/upload_coverage_report.yml",
    "content": "---\nname: upload_coverage_report\n\n# yamllint disable-line rule:truthy\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - master\n  pull_request:\n\npermissions:\n  contents: read\n\nenv:\n  REPORT_NAME: \"lcov.info\"\n\njobs:\n  upload_coverage_report:\n    runs-on: ubuntu-latest\n    env:\n      CARGO_TERM_COLOR: always\n    steps:\n      - uses: actions/checkout@v6\n      - uses: taiki-e/install-action@cargo-llvm-cov\n      - name: Generate code coverage\n        run: >\n          cargo llvm-cov\n          --all-features\n          --workspace\n          --lcov\n          --output-path \"${{ env.REPORT_NAME }}\"\n      - name: Upload coverage to codecov (tokenless)\n        if: >-\n          github.event_name == 'pull_request' &&\n          github.event.pull_request.head.repo.full_name != github.repository\n        uses: codecov/codecov-action@v5\n        with:\n          files: \"${{ env.REPORT_NAME }}\"\n          fail_ci_if_error: true\n      - name: Upload coverage to codecov (with token)\n        if: \"! github.event.pull_request.head.repo.fork \"\n        uses: codecov/codecov-action@v5\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          files: \"${{ env.REPORT_NAME }}\"\n          fail_ci_if_error: true\n...\n"
  },
  {
    "path": ".gitignore",
    "content": "\n/target\n**/*.rs.bk\n\n/target\n**/*.rs.bk\nCargo.lock\n/.idea/\n.vscode\n"
  },
  {
    "path": ".gitpod.Dockerfile",
    "content": "FROM gitpod/workspace-rust:2024-06-05-14-45-28\n\nUSER gitpod\n"
  },
  {
    "path": ".gitpod.yml",
    "content": "---\nimage:\n  file: .gitpod.Dockerfile\n\ntasks:\n  - init: cargo build\n\nvscode:\n  extensions:\n    - rust-lang.rust-analyzer\n...\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# The Algorithms: Rust\n\nThis project aims at showcasing common algorithms implemented in `Rust`, with an accent on idiomatic code and genericity. \n\n## Project structure\n\nThe project is organized as follows:\n\n`src/`\n  - `my_algo_category/`\n    - `mod.rs`\n    - `my_algorithm.rs`\n    - `some_other_algorithm.rs`\n  - `some_other_algo_category/`\n    - ...\n\n\n`mod.rs` contains the export:\n\n```rust\nmod my_algorithm;\n\npub use self::my_algorithm::my_algorithm;\n```\n\n`my_algorithm.rs` contains your algorithm and the related tests:\n\n```rust\npub fn my_algorithm() {\n    // ...\n}\n\n#[cfg(test)]\nmod tests {\n    #[test]\n    fn my_test() {\n        // ...\n    }\n}\n```\n\n## Before submitting your PR\n\nDo **not** use acronyms: `DFS` should be `depth_first_search`.\n\nMake sure you run\n  * `cargo test` \n  * `cargo fmt`\n  * `cargo clippy --all -- -D warnings`\n\n  And that's about it !\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"the_algorithms_rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Anshul Malik <malikanshul29@gmail.com>\"]\n\n[dependencies]\nnalgebra = \"0.34.0\"\nndarray = \"0.17.2\"\nnum-bigint = { version = \"0.4\", optional = true }\nnum-traits = { version = \"0.2\", optional = true }\nrand = \"0.10\"\n\n[dev-dependencies]\nquickcheck = \"1.0\"\nquickcheck_macros = \"1.0\"\n\n[features]\ndefault = [\"big-math\"]\nbig-math = [\"dep:num-bigint\", \"dep:num-traits\"]\n\n[lints.clippy]\ncargo = \"warn\"\nnursery = \"warn\"\npedantic = \"warn\"\nrestriction = \"warn\"\n# cargo-lints:\ncargo_common_metadata = { level = \"allow\", priority = 1 }\nmultiple_crate_versions = { level = \"allow\", priority = 1 }\n# complexity-lints:\nmanual_div_ceil = { level = \"allow\", priority = 1 }\nprecedence = { level = \"allow\", priority = 1 }\n# nursery-lints:\nbranches_sharing_code = { level = \"allow\", priority = 1 }\ncognitive_complexity = { level = \"allow\", priority = 1 }\nderive_partial_eq_without_eq = { level = \"allow\", priority = 1 }\nempty_line_after_doc_comments = { level = \"allow\", priority = 1 }\nfallible_impl_from = { level = \"allow\", priority = 1 }\nimprecise_flops = { level = \"allow\", priority = 1 }\nmissing_const_for_fn = { level = \"allow\", priority = 1 }\nnonstandard_macro_braces = { level = \"allow\", priority = 1 }\noption_if_let_else = { level = \"allow\", priority = 1 }\nsuboptimal_flops = { level = \"allow\", priority = 1 }\nsuspicious_operation_groupings = { level = \"allow\", priority = 1 }\ntoo_long_first_doc_paragraph = { level = \"allow\", priority = 1 }\nuse_self = { level = \"allow\", priority = 1 }\nwhile_float = { level = \"allow\", priority = 1 }\n# pedantic-lints:\ncast_lossless = { level = \"allow\", priority = 1 }\ncast_possible_truncation = { level = \"allow\", priority = 1 }\ncast_possible_wrap = { level = \"allow\", priority = 1 }\ncast_precision_loss = { level = \"allow\", priority = 1 }\ncast_sign_loss = { level = \"allow\", priority = 1 }\ncloned_instead_of_copied = { level = \"allow\", priority = 1 }\ndoc_markdown = { level = \"allow\", priority = 1 }\nexplicit_deref_methods = { level = \"allow\", priority = 1 }\nexplicit_iter_loop = { level = \"allow\", priority = 1 }\nfloat_cmp = { level = \"allow\", priority = 1 }\nignore_without_reason = { level = \"allow\", priority = 1 }\nimplicit_clone = { level = \"allow\", priority = 1 }\nimplicit_hasher = { level = \"allow\", priority = 1 }\nitems_after_statements = { level = \"allow\", priority = 1 }\niter_without_into_iter = { level = \"allow\", priority = 1 }\nlarge_stack_arrays = { level = \"allow\", priority = 1 }\nlinkedlist = { level = \"allow\", priority = 1 }\nmanual_assert = { level = \"allow\", priority = 1 }\nmanual_let_else = { level = \"allow\", priority = 1 }\nmanual_string_new = { level = \"allow\", priority = 1 }\nmany_single_char_names = { level = \"allow\", priority = 1 }\nmatch_wildcard_for_single_variants = { level = \"allow\", priority = 1 }\nmissing_errors_doc = { level = \"allow\", priority = 1 }\nmissing_fields_in_debug = { level = \"allow\", priority = 1 }\nmissing_panics_doc = { level = \"allow\", priority = 1 }\nmodule_name_repetitions = { level = \"allow\", priority = 1 }\nmust_use_candidate = { level = \"allow\", priority = 1 }\nneedless_pass_by_value = { level = \"allow\", priority = 1 }\nredundant_closure_for_method_calls = { level = \"allow\", priority = 1 }\nref_option = { level = \"allow\", priority = 1 }\nreturn_self_not_must_use = { level = \"allow\", priority = 1 }\nsemicolon_if_nothing_returned = { level = \"allow\", priority = 1 }\nshould_panic_without_expect = { level = \"allow\", priority = 1 }\nsimilar_names = { level = \"allow\", priority = 1 }\nsingle_match_else = { level = \"allow\", priority = 1 }\nstable_sort_primitive = { level = \"allow\", priority = 1 }\ntoo_many_lines = { level = \"allow\", priority = 1 }\ntrivially_copy_pass_by_ref = { level = \"allow\", priority = 1 }\nunnecessary_box_returns = { level = \"allow\", priority = 1 }\nunnecessary_semicolon = { level = \"allow\", priority = 1 }\nunnested_or_patterns = { level = \"allow\", priority = 1 }\nunreadable_literal = { level = \"allow\", priority = 1 }\nunused_self = { level = \"allow\", priority = 1 }\nused_underscore_binding = { level = \"allow\", priority = 1 }\n# restriction-lints:\nabsolute_paths = { level = \"allow\", priority = 1 }\nallow_attributes = { level = \"allow\", priority = 1 }\nallow_attributes_without_reason = { level = \"allow\", priority = 1 }\narbitrary_source_item_ordering = { level = \"allow\", priority = 1 }\narithmetic_side_effects = { level = \"allow\", priority = 1 }\nas_conversions = { level = \"allow\", priority = 1 }\nassertions_on_result_states = { level = \"allow\", priority = 1 }\nblanket_clippy_restriction_lints = { level = \"allow\", priority = 1 }\ncfg_not_test = { level = \"allow\", priority = 1 }\nclone_on_ref_ptr = { level = \"allow\", priority = 1 }\ndbg_macro = { level = \"allow\", priority = 1 }\ndecimal_literal_representation = { level = \"allow\", priority = 1 }\ndefault_numeric_fallback = { level = \"allow\", priority = 1 }\nderef_by_slicing = { level = \"allow\", priority = 1 }\nelse_if_without_else = { level = \"allow\", priority = 1 }\nexhaustive_enums = { level = \"allow\", priority = 1 }\nexhaustive_structs = { level = \"allow\", priority = 1 }\nexpect_used = { level = \"allow\", priority = 1 }\nfield_scoped_visibility_modifiers = { level = \"allow\", priority = 1 }\nfloat_arithmetic = { level = \"allow\", priority = 1 }\nfloat_cmp_const = { level = \"allow\", priority = 1 }\nif_then_some_else_none = { level = \"allow\", priority = 1 }\nimpl_trait_in_params = { level = \"allow\", priority = 1 }\nimplicit_return = { level = \"allow\", priority = 1 }\nindexing_slicing = { level = \"allow\", priority = 1 }\ninteger_division = { level = \"allow\", priority = 1 }\ninteger_division_remainder_used = { level = \"allow\", priority = 1 }\niter_over_hash_type = { level = \"allow\", priority = 1 }\nlittle_endian_bytes = { level = \"allow\", priority = 1 }\nmap_err_ignore = { level = \"allow\", priority = 1 }\nmap_with_unused_argument_over_ranges = { level = \"allow\", priority = 1 }\nmin_ident_chars = { level = \"allow\", priority = 1 }\nmissing_assert_message = { level = \"allow\", priority = 1 }\nmissing_asserts_for_indexing = { level = \"allow\", priority = 1 }\nmissing_docs_in_private_items = { level = \"allow\", priority = 1 }\nmissing_inline_in_public_items = { level = \"allow\", priority = 1 }\nmissing_trait_methods = { level = \"allow\", priority = 1 }\nmod_module_files = { level = \"allow\", priority = 1 }\nmodulo_arithmetic = { level = \"allow\", priority = 1 }\nmultiple_unsafe_ops_per_block = { level = \"allow\", priority = 1 }\nnon_ascii_literal = { level = \"allow\", priority = 1 }\npanic = { level = \"allow\", priority = 1 }\npartial_pub_fields = { level = \"allow\", priority = 1 }\npattern_type_mismatch = { level = \"allow\", priority = 1 }\nprecedence_bits = { level = \"allow\", priority = 1 }\nprint_stderr = { level = \"allow\", priority = 1 }\nprint_stdout = { level = \"allow\", priority = 1 }\npub_use = { level = \"allow\", priority = 1 }\npub_with_shorthand = { level = \"allow\", priority = 1 }\nquestion_mark_used = { level = \"allow\", priority = 1 }\nredundant_test_prefix = { level = \"allow\", priority = 1 }\nrenamed_function_params = { level = \"allow\", priority = 1 }\nsame_name_method = { level = \"allow\", priority = 1 }\nsemicolon_outside_block = { level = \"allow\", priority = 1 }\nseparated_literal_suffix = { level = \"allow\", priority = 1 }\nshadow_reuse = { level = \"allow\", priority = 1 }\nshadow_same = { level = \"allow\", priority = 1 }\nshadow_unrelated = { level = \"allow\", priority = 1 }\nsingle_call_fn = { level = \"allow\", priority = 1 }\nsingle_char_lifetime_names = { level = \"allow\", priority = 1 }\nstd_instead_of_alloc = { level = \"allow\", priority = 1 }\nstd_instead_of_core = { level = \"allow\", priority = 1 }\nstr_to_string = { level = \"allow\", priority = 1 }\nstring_add = { level = \"allow\", priority = 1 }\nstring_slice = { level = \"allow\", priority = 1 }\nundocumented_unsafe_blocks = { level = \"allow\", priority = 1 }\nunnecessary_safety_comment = { level = \"allow\", priority = 1 }\nunreachable = { level = \"allow\", priority = 1 }\nunseparated_literal_suffix = { level = \"allow\", priority = 1 }\nunused_trait_names = { level = \"allow\", priority = 1 }\nunwrap_in_result = { level = \"allow\", priority = 1 }\nunwrap_used = { level = \"allow\", priority = 1 }\nuse_debug = { level = \"allow\", priority = 1 }\nused_underscore_items = { level = \"allow\", priority = 1 }\nwildcard_enum_match_arm = { level = \"allow\", priority = 1 }\n# style-lints:\ndoc_lazy_continuation = { level = \"allow\", priority = 1 }\ndoc_overindented_list_items = { level = \"allow\", priority = 1 }\ndoc_paragraphs_missing_punctuation = { level = \"allow\", priority = 1 }\nneedless_range_loop = { level = \"allow\", priority = 1 }\nneedless_return = { level = \"allow\", priority = 1 }\n"
  },
  {
    "path": "DIRECTORY.md",
    "content": "# List of all files\n\n## src\n  * Backtracking\n    * [All Combinations of Size K](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/all_combination_of_size_k.rs)\n    * [Graph Coloring](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/graph_coloring.rs)\n    * [Hamiltonian Cycle](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/hamiltonian_cycle.rs)\n    * [Knight Tour](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/knight_tour.rs)\n    * [N-Queens](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/n_queens.rs)\n    * [Parentheses Generator](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/parentheses_generator.rs)\n    * [Permutations](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/permutations.rs)\n    * [Rat in Maze](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/rat_in_maze.rs)\n    * [Subset Sum](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/subset_sum.rs)\n    * [Sudoku](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/sudoku.rs)\n  * Big Integer\n    * [Fast Factorial](https://github.com/TheAlgorithms/Rust/blob/master/src/big_integer/fast_factorial.rs)\n    * [Multiply](https://github.com/TheAlgorithms/Rust/blob/master/src/big_integer/multiply.rs)\n    * [Poly1305](https://github.com/TheAlgorithms/Rust/blob/master/src/big_integer/poly1305.rs)\n  * Bit Manipulation\n    * [Binary Coded Decimal](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/binary_coded_decimal.rs)\n    * [Binary Shifts](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/binary_shifts.rs)\n    * [Counting Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/counting_bits.rs)\n    * [Hamming Distance](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/hamming_distance.rs)\n    * [Highest Set Bit](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/highest_set_bit.rs)\n    * [Is Power of Two](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/is_power_of_two.rs)\n    * [Missing Number](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/find_missing_number.rs)\n    * [N Bits Gray Code](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/n_bits_gray_code.rs)\n    * [Previous Power of Two](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/find_previous_power_of_two.rs)\n    * [Reverse Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/reverse_bits.rs)\n    * [Rightmost Set Bit](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/rightmost_set_bit.rs)\n    * [Sum of Two Integers](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/sum_of_two_integers.rs)\n    * [Swap Odd and Even Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/swap_odd_even_bits.rs)\n    * [Trailing Zeros](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/binary_count_trailing_zeros.rs)\n    * [Two's Complement](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/twos_complement.rs)\n    * [Unique Number](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/find_unique_number.rs)\n  * Ciphers\n    * [AES](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/aes.rs)\n    * [Affine Cipher](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/affine_cipher.rs)\n    * [Another ROT13](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/another_rot13.rs)\n    * [Baconian Cipher](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/baconian_cipher.rs)\n    * [Base16](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/base16.rs)\n    * [Base32](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/base32.rs)\n    * [Base64](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/base64.rs)\n    * [Base85](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/base85.rs)\n    * [Blake2B](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/blake2b.rs)\n    * [Caesar](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/caesar.rs)\n    * [Chacha](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/chacha.rs)\n    * [Diffie-Hellman](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/diffie_hellman.rs)\n    * [Hashing Traits](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/hashing_traits.rs)\n    * [Hill Cipher](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/hill_cipher.rs)\n    * [Kernighan](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/kernighan.rs)\n    * [Morse Code](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/morse_code.rs)\n    * [Polybius](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/polybius.rs)\n    * [Rail Fence](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/rail_fence.rs)\n    * [ROT13](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/rot13.rs)\n    * [RSA Cipher](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/rsa_cipher.rs)\n    * [Salsa](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/salsa.rs)\n    * [SHA-256](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/sha256.rs)\n    * [SHA-3](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/sha3.rs)\n    * [Tea](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/tea.rs)\n    * [Theoretical ROT13](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/theoretical_rot13.rs)\n    * [Transposition](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/transposition.rs)\n    * [Trifid](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/trifid.rs)\n    * [Vernam](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/vernam.rs)\n    * [Vigenere](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/vigenere.rs)\n    * [XOR](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/xor.rs)\n  * Compression\n    * [Burrows-Wheeler Transform](https://github.com/TheAlgorithms/Rust/blob/master/src/compression/burrows_wheeler_transform.rs)\n    * [Huffman Encoding](https://github.com/TheAlgorithms/Rust/blob/master/src/compression/huffman_encoding.rs)\n    * [LZ77](https://github.com/TheAlgorithms/Rust/blob/master/src/compression/lz77.rs)\n    * [Move to Front](https://github.com/TheAlgorithms/Rust/blob/master/src/compression/move_to_front.rs)\n    * [Run Length Encoding](https://github.com/TheAlgorithms/Rust/blob/master/src/compression/run_length_encoding.rs)\n  * Conversions\n    * [Binary to Decimal](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/binary_to_decimal.rs)\n    * [Binary to Hexadecimal](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/binary_to_hexadecimal.rs)\n    * [Binary to Octal](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/binary_to_octal.rs)\n    * [Decimal to Binary](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/decimal_to_binary.rs)\n    * [Decimal to Hexadecimal](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/decimal_to_hexadecimal.rs)\n    * [Decimal to Octal](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/decimal_to_octal.rs)\n    * [Energy](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/energy.rs)\n    * [Hexadecimal to Binary](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/hexadecimal_to_binary.rs)\n    * [Hexadecimal to Decimal](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/hexadecimal_to_decimal.rs)\n    * [Hexadecimal to Octal](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/hexadecimal_to_octal.rs)\n    * [IPv4 Conversion](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/ipv4_conversion.rs)\n    * [Length Conversion](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/length_conversion.rs)\n    * [Octal to Binary](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/octal_to_binary.rs)\n    * [Octal to Decimal](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/octal_to_decimal.rs)\n    * [Octal to Hexadecimal](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/octal_to_hexadecimal.rs)\n    * [Order of Magnitude Conversion](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/order_of_magnitude_conversion.rs)\n    * [Pressure](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/pressure.rs)\n    * [Rectangular to Polar](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/rectangular_to_polar.rs)\n    * [RGB-CMYK Conversion](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/rgb_cmyk_conversion.rs)\n    * [RGB-HSV Conversion](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/rgb_hsv_conversion.rs)\n    * [Roman Numerals](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/roman_numerals.rs)\n    * [Speed](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/speed.rs)\n    * [Time](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/time.rs)\n    * [Temperature](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/temperature.rs)\n    * [Volume](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/volume.rs)\n    * [Weight](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/weight.rs)\n  * Data Structures\n    * [AVL Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/avl_tree.rs)\n    * [B-Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/b_tree.rs)\n    * [Binary Search Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/binary_search_tree.rs)\n    * [Fenwick Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/fenwick_tree.rs)\n    * [Floyds Algorithm](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/floyds_algorithm.rs)\n    * [Graph](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/graph.rs)\n    * [Hash Table](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/hash_table.rs)\n    * [Heap](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/heap.rs)\n    * [Lazy Segment Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/lazy_segment_tree.rs)\n    * [Linked List](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/linked_list.rs)\n    * Probabilistic\n      * [Bloom Filter](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/probabilistic/bloom_filter.rs)\n      * [Count Min Sketch](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/probabilistic/count_min_sketch.rs)\n    * [Queue](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/queue.rs)\n    * [Range Minimum Query](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/range_minimum_query.rs)\n    * [RB Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/rb_tree.rs)\n    * [Segment Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/segment_tree.rs)\n    * [Segment Tree Recursive](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/segment_tree_recursive.rs)\n    * [Stack Using Singly Linked List](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/stack_using_singly_linked_list.rs)\n    * [Treap](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/treap.rs)\n    * [Trie](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/trie.rs)\n    * [Union Find](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/union_find.rs)\n    * [Veb Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/veb_tree.rs)\n  * Dynamic Programming\n    * [Catalan Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/catalan_numbers.rs)\n    * [Coin Change](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/coin_change.rs)\n    * [Egg Dropping](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/egg_dropping.rs)\n    * [Fibonacci](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/fibonacci.rs)\n    * [Fractional Knapsack](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/fractional_knapsack.rs)\n    * [Integer Partition](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/integer_partition.rs)\n    * [Is Subsequence](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/is_subsequence.rs)\n    * [Knapsack](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/knapsack.rs)\n    * [Longest Common Subsequence](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/longest_common_subsequence.rs)\n    * [Longest Common Substring](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/longest_common_substring.rs)\n    * [Longest Continuous Increasing Subsequence](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/longest_continuous_increasing_subsequence.rs)\n    * [Longest Increasing Subsequence](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/longest_increasing_subsequence.rs)\n    * [Matrix Chain Multiply](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/matrix_chain_multiply.rs)\n    * [Maximal Square](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/maximal_square.rs)\n    * [Maximum Subarray](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/maximum_subarray.rs)\n    * [Minimum Cost Path](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/minimum_cost_path.rs)\n    * [Optimal BST](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/optimal_bst.rs)\n    * [Palindrome Partitioning](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/palindrome_partitioning.rs)\n    * [Rod Cutting](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/rod_cutting.rs)\n    * [Smith-Waterman](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/smith_waterman.rs)\n    * [Snail](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/snail.rs)\n    * [Subset Generation](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/subset_generation.rs)\n    * [Subset Sum](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/subset_sum.rs)\n    * [Task Assignment](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/task_assignment.rs)\n    * [Trapped Rainwater](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/trapped_rainwater.rs)\n    * [Word Break](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/word_break.rs)\n  * Financial\n    * [Depreciation](https://github.com/TheAlgorithms/Rust/blob/master/src/financial/depreciation.rs)\n    * [Equated Monthly Installments](https://github.com/TheAlgorithms/Rust/blob/master/src/financial/equated_monthly_installments.rs)\n    * [Exponential Moving Average](https://github.com/TheAlgorithms/Rust/blob/master/src/financial/exponential_moving_average.rs)\n    * [Finance Ratios](https://github.com/TheAlgorithms/Rust/blob/master/src/financial/finance_ratios.rs)\n    * [Interest](https://github.com/TheAlgorithms/Rust/blob/master/src/financial/interest.rs)\n    * [Net Present Value](https://github.com/TheAlgorithms/Rust/blob/master/src/financial/npv.rs)\n    * [NPV Sensitivity](https://github.com/TheAlgorithms/Rust/blob/master/src/financial/npv_sensitivity.rs)\n    * [Payback Period](https://github.com/TheAlgorithms/Rust/blob/master/src/financial/payback.rs)\n    * [Present Value](https://github.com/TheAlgorithms/Rust/blob/master/src/financial/present_value.rs)\n    * [Treynor Ratio](https://github.com/TheAlgorithms/Rust/blob/master/src/financial/treynor_ratio.rs)\n  * General\n    * [Convex Hull](https://github.com/TheAlgorithms/Rust/blob/master/src/general/convex_hull.rs)\n    * [Fisher Yates Shuffle](https://github.com/TheAlgorithms/Rust/blob/master/src/general/fisher_yates_shuffle.rs)\n    * [Genetic](https://github.com/TheAlgorithms/Rust/blob/master/src/general/genetic.rs)\n    * [Hanoi](https://github.com/TheAlgorithms/Rust/blob/master/src/general/hanoi.rs)\n    * [Huffman Encoding](https://github.com/TheAlgorithms/Rust/blob/master/src/general/huffman_encoding.rs)\n    * [Kadane Algorithm](https://github.com/TheAlgorithms/Rust/blob/master/src/general/kadane_algorithm.rs)\n    * [K-Means](https://github.com/TheAlgorithms/Rust/blob/master/src/general/kmeans.rs)\n    * [Mex](https://github.com/TheAlgorithms/Rust/blob/master/src/general/mex.rs)\n    * Permutations\n      * [Heap](https://github.com/TheAlgorithms/Rust/blob/master/src/general/permutations/heap.rs)\n      * [Naive](https://github.com/TheAlgorithms/Rust/blob/master/src/general/permutations/naive.rs)\n      * [Steinhaus Johnson Trotter](https://github.com/TheAlgorithms/Rust/blob/master/src/general/permutations/steinhaus_johnson_trotter.rs)\n    * [Subarray Sum Equals K](https://github.com/TheAlgorithms/Rust/blob/master/src/general/subarray_sum_equals_k.rs)\n    * [Two Sum](https://github.com/TheAlgorithms/Rust/blob/master/src/general/two_sum.rs)\n  * Geometry\n    * [Closest Points](https://github.com/TheAlgorithms/Rust/blob/master/src/geometry/closest_points.rs)\n    * [Graham Scan](https://github.com/TheAlgorithms/Rust/blob/master/src/geometry/graham_scan.rs)\n    * [Jarvis Scan](https://github.com/TheAlgorithms/Rust/blob/master/src/geometry/jarvis_scan.rs)\n    * [Point](https://github.com/TheAlgorithms/Rust/blob/master/src/geometry/point.rs)\n    * [Polygon Points](https://github.com/TheAlgorithms/Rust/blob/master/src/geometry/polygon_points.rs)\n    * [Ramer Douglas Peucker](https://github.com/TheAlgorithms/Rust/blob/master/src/geometry/ramer_douglas_peucker.rs)\n    * [Segment](https://github.com/TheAlgorithms/Rust/blob/master/src/geometry/segment.rs)\n  * Graph\n    * [A*](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/astar.rs)\n    * [Ant Colony Optimization](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/ant_colony_optimization.rs)\n    * [Bellman-Ford](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/bellman_ford.rs)\n    * [Bipartite Matching](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/bipartite_matching.rs)\n    * [Breadth First Search](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/breadth_first_search.rs)\n    * [Centroid Decomposition](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/centroid_decomposition.rs)\n    * [Decremental Connectivity](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/decremental_connectivity.rs)\n    * [Depth First Search](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/depth_first_search.rs)\n    * [Depth First Search Tic-Tac-Toe](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/depth_first_search_tic_tac_toe.rs)\n    * [Detect Cycle](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/detect_cycle.rs)\n    * [Dijkstra](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/dijkstra.rs)\n    * [Dinic Maxflow](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/dinic_maxflow.rs)\n    * [Disjoint Set Union](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/disjoint_set_union.rs)\n    * [Eulerian Path](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/eulerian_path.rs)\n    * [Floyd Warshall](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/floyd_warshall.rs)\n    * [Ford Fulkerson](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/ford_fulkerson.rs)\n    * [Graph Enumeration](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/graph_enumeration.rs)\n    * [Heavy Light Decomposition](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/heavy_light_decomposition.rs)\n    * [Kosaraju](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/kosaraju.rs)\n    * [Lee Breadth First Search](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/lee_breadth_first_search.rs)\n    * [Lowest Common Ancestor](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/lowest_common_ancestor.rs)\n    * [Minimum Spanning Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/minimum_spanning_tree.rs)\n    * [Prim](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/prim.rs)\n    * [Prufer Code](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/prufer_code.rs)\n    * [Strongly Connected Components](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/strongly_connected_components.rs)\n    * [Tarjans Strongly Connected Components](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/tarjans_ssc.rs)\n    * [Topological Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/topological_sort.rs)\n    * [Two Satisfiability](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/two_satisfiability.rs)\n  * Greedy\n    * [Minimum Coin Change](https://github.com/TheAlgorithms/Rust/blob/master/src/greedy/minimum_coin_changes.rs)\n    * [Smallest Range](https://github.com/TheAlgorithms/Rust/blob/master/src/greedy/smallest_range.rs)\n    * [Stable Matching](https://github.com/TheAlgorithms/Rust/blob/master/src/greedy/stable_matching.rs)\n  * [Lib](https://github.com/TheAlgorithms/Rust/blob/master/src/lib.rs)\n  * Machine Learning\n    * [Cholesky](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/cholesky.rs)\n    * [Decision Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/decision_tree.rs)\n    * [K-Means](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/k_means.rs)\n    * [K-Nearest Neighbors](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/k_nearest_neighbors.rs)\n    * [Linear Regression](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/linear_regression.rs)\n    * [Logistic Regression](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/logistic_regression.rs)\n    * [Naive Bayes](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/naive_bayes.rs)\n    * [Perceptron](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/perceptron.rs)\n    * [Principal Component Analysis](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/principal_component_analysis.rs)\n    * [Random Forest](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/random_forest.rs)\n    * [Support Vector Classifier](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/support_vector_classifier.rs)\n    * Loss Function\n      * [Average Margin Ranking Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/loss_function/average_margin_ranking_loss.rs)\n      * [Hinge Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/loss_function/hinge_loss.rs)\n      * [Huber Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/loss_function/huber_loss.rs)\n      * [KL Divergence Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/loss_function/kl_divergence_loss.rs)\n      * [Mean Absolute Error Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/loss_function/mean_absolute_error_loss.rs)\n      * [Mean Squared Error Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/loss_function/mean_squared_error_loss.rs)\n      * [Negative Log Likelihood](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/loss_function/negative_log_likelihood.rs)\n    * Optimization\n      * [Adam](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/optimization/adam.rs)\n      * [Gradient Descent](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/optimization/gradient_descent.rs)\n      * [Momentum](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/optimization/momentum.rs)\n  * Math\n    * [Absolute](https://github.com/TheAlgorithms/Rust/blob/master/src/math/abs.rs)\n    * [Aliquot Sum](https://github.com/TheAlgorithms/Rust/blob/master/src/math/aliquot_sum.rs)\n    * [Amicable Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/amicable_numbers.rs)\n    * [Area of Polygon](https://github.com/TheAlgorithms/Rust/blob/master/src/math/area_of_polygon.rs)\n    * [Area Under Curve](https://github.com/TheAlgorithms/Rust/blob/master/src/math/area_under_curve.rs)\n    * [Armstrong Number](https://github.com/TheAlgorithms/Rust/blob/master/src/math/armstrong_number.rs)\n    * [Average](https://github.com/TheAlgorithms/Rust/blob/master/src/math/average.rs)\n    * [Baby Step Giant Step](https://github.com/TheAlgorithms/Rust/blob/master/src/math/baby_step_giant_step.rs)\n    * [Bell Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/bell_numbers.rs)\n    * [Binary Exponentiation](https://github.com/TheAlgorithms/Rust/blob/master/src/math/binary_exponentiation.rs)\n    * [Binomial Coefficient](https://github.com/TheAlgorithms/Rust/blob/master/src/math/binomial_coefficient.rs)\n    * [Catalan Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/catalan_numbers.rs)\n    * [Ceil](https://github.com/TheAlgorithms/Rust/blob/master/src/math/ceil.rs)\n    * [Chinese Remainder Theorem](https://github.com/TheAlgorithms/Rust/blob/master/src/math/chinese_remainder_theorem.rs)\n    * [Collatz Sequence](https://github.com/TheAlgorithms/Rust/blob/master/src/math/collatz_sequence.rs)\n    * [Combinations](https://github.com/TheAlgorithms/Rust/blob/master/src/math/combinations.rs)\n    * [Cross Entropy Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/math/cross_entropy_loss.rs)\n    * [Decimal to Fraction](https://github.com/TheAlgorithms/Rust/blob/master/src/math/decimal_to_fraction.rs)\n    * [Doomsday](https://github.com/TheAlgorithms/Rust/blob/master/src/math/doomsday.rs)\n    * [Elliptic Curve](https://github.com/TheAlgorithms/Rust/blob/master/src/math/elliptic_curve.rs)\n    * [Euclidean Distance](https://github.com/TheAlgorithms/Rust/blob/master/src/math/euclidean_distance.rs)\n    * [Exponential Linear Unit](https://github.com/TheAlgorithms/Rust/blob/master/src/math/exponential_linear_unit.rs)\n    * [Extended Euclidean Algorithm](https://github.com/TheAlgorithms/Rust/blob/master/src/math/extended_euclidean_algorithm.rs)\n    * [Factorial](https://github.com/TheAlgorithms/Rust/blob/master/src/math/factorial.rs)\n    * [Factors](https://github.com/TheAlgorithms/Rust/blob/master/src/math/factors.rs)\n    * [Fast Fourier Transform](https://github.com/TheAlgorithms/Rust/blob/master/src/math/fast_fourier_transform.rs)\n    * [Fast Power](https://github.com/TheAlgorithms/Rust/blob/master/src/math/fast_power.rs)\n    * [Faster Perfect Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/faster_perfect_numbers.rs)\n    * [Field](https://github.com/TheAlgorithms/Rust/blob/master/src/math/field.rs)\n    * [Frizzy Number](https://github.com/TheAlgorithms/Rust/blob/master/src/math/frizzy_number.rs)\n    * [Gaussian Elimination](https://github.com/TheAlgorithms/Rust/blob/master/src/math/gaussian_elimination.rs)\n    * [Gaussian Error Linear Unit](https://github.com/TheAlgorithms/Rust/blob/master/src/math/gaussian_error_linear_unit.rs)\n    * [GCD of N Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/gcd_of_n_numbers.rs)\n    * [Geometric Series](https://github.com/TheAlgorithms/Rust/blob/master/src/math/geometric_series.rs)\n    * [Greatest Common Divisor](https://github.com/TheAlgorithms/Rust/blob/master/src/math/greatest_common_divisor.rs)\n    * [Huber Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/math/huber_loss.rs)\n    * [Infix to Postfix](https://github.com/TheAlgorithms/Rust/blob/master/src/math/infix_to_postfix.rs)\n    * [Interest](https://github.com/TheAlgorithms/Rust/blob/master/src/math/interest.rs)\n    * [Interpolation](https://github.com/TheAlgorithms/Rust/blob/master/src/math/interpolation.rs)\n    * [Interquartile Range](https://github.com/TheAlgorithms/Rust/blob/master/src/math/interquartile_range.rs)\n    * [Karatsuba Multiplication](https://github.com/TheAlgorithms/Rust/blob/master/src/math/karatsuba_multiplication.rs)\n    * [LCM of N Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/lcm_of_n_numbers.rs)\n    * [Leaky Relu](https://github.com/TheAlgorithms/Rust/blob/master/src/math/leaky_relu.rs)\n    * [Least Square Approx](https://github.com/TheAlgorithms/Rust/blob/master/src/math/least_square_approx.rs)\n    * [Linear Sieve](https://github.com/TheAlgorithms/Rust/blob/master/src/math/linear_sieve.rs)\n    * [Logarithm](https://github.com/TheAlgorithms/Rust/blob/master/src/math/logarithm.rs)\n    * [Lucas Series](https://github.com/TheAlgorithms/Rust/blob/master/src/math/lucas_series.rs)\n    * [Matrix Ops](https://github.com/TheAlgorithms/Rust/blob/master/src/math/matrix_ops.rs)\n    * [Mersenne Primes](https://github.com/TheAlgorithms/Rust/blob/master/src/math/mersenne_primes.rs)\n    * [Miller Rabin](https://github.com/TheAlgorithms/Rust/blob/master/src/math/miller_rabin.rs)\n    * [Modular Exponential](https://github.com/TheAlgorithms/Rust/blob/master/src/math/modular_exponential.rs)\n    * [Newton Raphson](https://github.com/TheAlgorithms/Rust/blob/master/src/math/newton_raphson.rs)\n    * [N-th prime](https://github.com/TheAlgorithms/Rust/blob/master/src/math/nthprime.rs)\n    * [Pascal Triangle](https://github.com/TheAlgorithms/Rust/blob/master/src/math/pascal_triangle.rs)\n    * [Perfect Cube](https://github.com/TheAlgorithms/Rust/blob/master/src/math/perfect_cube.rs)\n    * [Perfect Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/perfect_numbers.rs)\n    * [Perfect Square](https://github.com/TheAlgorithms/Rust/blob/master/src/math/perfect_square.rs)\n    * [Pollard Rho](https://github.com/TheAlgorithms/Rust/blob/master/src/math/pollard_rho.rs)\n    * [Postfix Evaluation](https://github.com/TheAlgorithms/Rust/blob/master/src/math/postfix_evaluation.rs)\n    * [Prime Check](https://github.com/TheAlgorithms/Rust/blob/master/src/math/prime_check.rs)\n    * [Prime Factors](https://github.com/TheAlgorithms/Rust/blob/master/src/math/prime_factors.rs)\n    * [Prime Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/prime_numbers.rs)\n    * [Quadratic Residue](https://github.com/TheAlgorithms/Rust/blob/master/src/math/quadratic_residue.rs)\n    * [Random](https://github.com/TheAlgorithms/Rust/blob/master/src/math/random.rs)\n    * [ReLU](https://github.com/TheAlgorithms/Rust/blob/master/src/math/relu.rs)\n    * [Sieve of Eratosthenes](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sieve_of_eratosthenes.rs)\n    * [Sigmoid](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sigmoid.rs)\n    * [Signum](https://github.com/TheAlgorithms/Rust/blob/master/src/math/signum.rs)\n    * [Simpsons Integration](https://github.com/TheAlgorithms/Rust/blob/master/src/math/simpsons_integration.rs)\n    * [Softmax](https://github.com/TheAlgorithms/Rust/blob/master/src/math/softmax.rs)\n    * [Sprague Grundy Theorem](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sprague_grundy_theorem.rs)\n    * [Square Pyramidal Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/square_pyramidal_numbers.rs)\n    * [Square Root](https://github.com/TheAlgorithms/Rust/blob/master/src/math/square_root.rs)\n    * [Sum of Digits](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sum_of_digits.rs)\n    * [Sum of Geometric Progression](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sum_of_geometric_progression.rs)\n    * [Sum of Harmonic Series](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sum_of_harmonic_series.rs)\n    * [Sylvester Sequence](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sylvester_sequence.rs)\n    * [Tanh](https://github.com/TheAlgorithms/Rust/blob/master/src/math/tanh.rs)\n    * [Trapezoidal Integration](https://github.com/TheAlgorithms/Rust/blob/master/src/math/trapezoidal_integration.rs)\n    * [Trial Division](https://github.com/TheAlgorithms/Rust/blob/master/src/math/trial_division.rs)\n    * [Trig Functions](https://github.com/TheAlgorithms/Rust/blob/master/src/math/trig_functions.rs)\n    * [Vector Cross Product](https://github.com/TheAlgorithms/Rust/blob/master/src/math/vector_cross_product.rs)\n    * [Zellers Congruence Algorithm](https://github.com/TheAlgorithms/Rust/blob/master/src/math/zellers_congruence_algorithm.rs)\n  * Navigation\n    * [Bearing](https://github.com/TheAlgorithms/Rust/blob/master/src/navigation/bearing.rs)\n    * [Haversine](https://github.com/TheAlgorithms/Rust/blob/master/src/navigation/haversine.rs)\n    * [Rhumbline](https://github.com/TheAlgorithms/Rust/blob/master/src/navigation/rhumbline.rs)\n  * Number Theory\n    * [Compute Totient](https://github.com/TheAlgorithms/Rust/blob/master/src/number_theory/compute_totient.rs)\n    * [Euler Totient](https://github.com/TheAlgorithms/Rust/blob/master/src/number_theory/euler_totient.rs)\n    * [K-th Factor](https://github.com/TheAlgorithms/Rust/blob/master/src/number_theory/kth_factor.rs)\n  * Searching\n    * [Binary Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/binary_search.rs)\n    * [Binary Search Recursive](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/binary_search_recursive.rs)\n    * [Exponential Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/exponential_search.rs)\n    * [Fibonacci Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/fibonacci_search.rs)\n    * [Interpolation Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/interpolation_search.rs)\n    * [Jump Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/jump_search.rs)\n    * [K-th Smallest](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/kth_smallest.rs)\n    * [K-th Smallest Heap](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/kth_smallest_heap.rs)\n    * [Linear Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/linear_search.rs)\n    * [Moore Voting](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/moore_voting.rs)\n    * [Quick Select](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/quick_select.rs)\n    * [Saddleback Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/saddleback_search.rs)\n    * [Ternary Search](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/ternary_search.rs)\n    * [Ternary Search Min Max](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/ternary_search_min_max.rs)\n    * [Ternary Search Min Max Recursive](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/ternary_search_min_max_recursive.rs)\n    * [Ternary Search Recursive](https://github.com/TheAlgorithms/Rust/blob/master/src/searching/ternary_search_recursive.rs)\n  * Signal Analysis\n    * [YIN](https://github.com/TheAlgorithms/Rust/blob/master/src/signal_analysis/yin.rs)\n  * Sorting\n    * [Bead Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/bead_sort.rs)\n    * [Binary Insertion Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/binary_insertion_sort.rs)\n    * [Bingo Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/bingo_sort.rs)\n    * [Bitonic Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/bitonic_sort.rs)\n    * [Bogo Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/bogo_sort.rs)\n    * [Bubble Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/bubble_sort.rs)\n    * [Bucket Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/bucket_sort.rs)\n    * [Cocktail Shaker Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/cocktail_shaker_sort.rs)\n    * [Comb Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/comb_sort.rs)\n    * [Counting Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/counting_sort.rs)\n    * [Cycle Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/cycle_sort.rs)\n    * [Dutch National Flag Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/dutch_national_flag_sort.rs)\n    * [Exchange Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/exchange_sort.rs)\n    * [Gnome Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/gnome_sort.rs)\n    * [Heap Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/heap_sort.rs)\n    * [Insertion Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/insertion_sort.rs)\n    * [Intro Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/intro_sort.rs)\n    * [Merge Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/merge_sort.rs)\n    * [Odd Even Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/odd_even_sort.rs)\n    * [Pancake Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/pancake_sort.rs)\n    * [Patience Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/patience_sort.rs)\n    * [Pigeonhole Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/pigeonhole_sort.rs)\n    * [Quick Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/quick_sort.rs)\n    * [Quick Sort 3-ways](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/quick_sort_3_ways.rs)\n    * [Radix Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/radix_sort.rs)\n    * [Selection Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/selection_sort.rs)\n    * [Shell Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/shell_sort.rs)\n    * [Sleep Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/sleep_sort.rs)\n    * [Sort Utils](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/sort_utils.rs)\n    * [Stooge Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/stooge_sort.rs)\n    * [Tim Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/tim_sort.rs)\n    * [Tree Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/tree_sort.rs)\n    * [Wave Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/wave_sort.rs)\n    * [Wiggle Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/wiggle_sort.rs)\n  * String\n    * [Aho Corasick](https://github.com/TheAlgorithms/Rust/blob/master/src/string/aho_corasick.rs)\n    * [Anagram](https://github.com/TheAlgorithms/Rust/blob/master/src/string/anagram.rs)\n    * [Autocomplete Using Trie](https://github.com/TheAlgorithms/Rust/blob/master/src/string/autocomplete_using_trie.rs)\n    * [Boyer Moore Search](https://github.com/TheAlgorithms/Rust/blob/master/src/string/boyer_moore_search.rs)\n    * [Burrows Wheeler Transform](https://github.com/TheAlgorithms/Rust/blob/master/src/string/burrows_wheeler_transform.rs)\n    * [Duval Algorithm](https://github.com/TheAlgorithms/Rust/blob/master/src/string/duval_algorithm.rs)\n    * [Hamming Distance](https://github.com/TheAlgorithms/Rust/blob/master/src/string/hamming_distance.rs)\n    * [Isogram](https://github.com/TheAlgorithms/Rust/blob/master/src/string/isogram.rs)\n    * [Isomorphism](https://github.com/TheAlgorithms/Rust/blob/master/src/string/isomorphism.rs)\n    * [Jaro Winkler Distance](https://github.com/TheAlgorithms/Rust/blob/master/src/string/jaro_winkler_distance.rs)\n    * [Knuth Morris Pratt](https://github.com/TheAlgorithms/Rust/blob/master/src/string/knuth_morris_pratt.rs)\n    * [Levenshtein Distance](https://github.com/TheAlgorithms/Rust/blob/master/src/string/levenshtein_distance.rs)\n    * [Lipogram](https://github.com/TheAlgorithms/Rust/blob/master/src/string/lipogram.rs)\n    * [Manacher](https://github.com/TheAlgorithms/Rust/blob/master/src/string/manacher.rs)\n    * [Palindrome](https://github.com/TheAlgorithms/Rust/blob/master/src/string/palindrome.rs)\n    * [Pangram](https://github.com/TheAlgorithms/Rust/blob/master/src/string/pangram.rs)\n    * [Rabin Karp](https://github.com/TheAlgorithms/Rust/blob/master/src/string/rabin_karp.rs)\n    * [Reverse](https://github.com/TheAlgorithms/Rust/blob/master/src/string/reverse.rs)\n    * [Run Length Encoding](https://github.com/TheAlgorithms/Rust/blob/master/src/string/run_length_encoding.rs)\n    * [Shortest Palindrome](https://github.com/TheAlgorithms/Rust/blob/master/src/string/shortest_palindrome.rs)\n    * [Suffix Array](https://github.com/TheAlgorithms/Rust/blob/master/src/string/suffix_array.rs)\n    * [Suffix Array Manber Myers](https://github.com/TheAlgorithms/Rust/blob/master/src/string/suffix_array_manber_myers.rs)\n    * [Suffix Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/string/suffix_tree.rs)\n    * [Z Algorithm](https://github.com/TheAlgorithms/Rust/blob/master/src/string/z_algorithm.rs)\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 The Algorithms\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n<!-- Title: -->\n<img src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/Rust_programming_language_black_logo.svg/1024px-Rust_programming_language_black_logo.svg.png\" width=\"100\" height=\"100\">\n\n<h1><a href=\"https://github.com/TheAlgorithms/\">The Algorithms</a> - Rust</h1>\n\n<!-- Labels: -->\n<a href=\"https://gitpod.io/#https://github.com/TheAlgorithms/Rust\">\n    <img src=\"https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod&style=flat-square\" height=\"20\" alt=\"Gitpod Ready-to-Code\">\n</a>\n<a href=\"https://github.com/TheAlgorithms/Rust/actions/workflows/build.yml\">\n  <img src=\"https://github.com/TheAlgorithms/Rust/actions/workflows/build.yml/badge.svg\" height=\"20\" alt=\"Build workflow\">\n</a>\n<a href=\"https://codecov.io/gh/TheAlgorithms/Rust\" > \n  <img src=\"https://codecov.io/gh/TheAlgorithms/Rust/graph/badge.svg?token=nRkPKfbs42\"/> \n</a>\n<a href=\"https://the-algorithms.com/discord\">\n  <img src=\"https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=00d37d\" height=\"20\" alt=\"Discord community\">\n</a>\n<a href=\"https://matrix.to/#/#TheAlgorithms_community:gitter.im\">\n  <img src=\"https://img.shields.io/gitter/room/TheAlgorithms/community.svg?style=flat-square\" height=\"20\" alt=\"Gitter chat\">\n</a>\n\n<!-- Short description: -->\n  <h3>All algorithms implemented in Rust - for education</h3>\n</div>\n\n### List of Algorithms\nSee our [directory](DIRECTORY.md) for easier navigation and a better overview of the project.\n\n### Contributing\nRead through our [Contribution Guidelines](CONTRIBUTING.md) before you contribute.\n"
  },
  {
    "path": "clippy.toml",
    "content": "allowed-duplicate-crates = [\n    \"glam\",\n]\n"
  },
  {
    "path": "git_hooks/pre-commit",
    "content": "cargo fmt\ncargo test\n"
  },
  {
    "path": "src/backtracking/all_combination_of_size_k.rs",
    "content": "//! This module provides a function to generate all possible combinations\n//! of `k` numbers out of `0...n-1` using a backtracking algorithm.\n\n/// Custom error type for combination generation.\n#[derive(Debug, PartialEq)]\npub enum CombinationError {\n    KGreaterThanN,\n    InvalidZeroRange,\n}\n\n/// Generates all possible combinations of `k` numbers out of `0...n-1`.\n///\n/// # Arguments\n///\n/// * `n` - The upper limit of the range (`0` to `n-1`).\n/// * `k` - The number of elements in each combination.\n///\n/// # Returns\n///\n/// A `Result` containing a vector with all possible combinations of `k` numbers out of `0...n-1`,\n/// or a `CombinationError` if the input is invalid.\npub fn generate_all_combinations(n: usize, k: usize) -> Result<Vec<Vec<usize>>, CombinationError> {\n    if n == 0 && k > 0 {\n        return Err(CombinationError::InvalidZeroRange);\n    }\n\n    if k > n {\n        return Err(CombinationError::KGreaterThanN);\n    }\n\n    let mut combinations = vec![];\n    let mut current = vec![0; k];\n    backtrack(0, n, k, 0, &mut current, &mut combinations);\n    Ok(combinations)\n}\n\n/// Helper function to generate combinations recursively.\n///\n/// # Arguments\n///\n/// * `start` - The current number to start the combination with.\n/// * `n` - The upper limit of the range (`0` to `n-1`).\n/// * `k` - The number of elements left to complete the combination.\n/// * `index` - The current index being filled in the combination.\n/// * `current` - A mutable reference to the current combination being constructed.\n/// * `combinations` - A mutable reference to the vector holding all combinations.\nfn backtrack(\n    start: usize,\n    n: usize,\n    k: usize,\n    index: usize,\n    current: &mut Vec<usize>,\n    combinations: &mut Vec<Vec<usize>>,\n) {\n    if index == k {\n        combinations.push(current.clone());\n        return;\n    }\n\n    for num in start..=(n - k + index) {\n        current[index] = num;\n        backtrack(num + 1, n, k, index + 1, current, combinations);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! combination_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (n, k, expected) = $test_case;\n                    assert_eq!(generate_all_combinations(n, k), expected);\n                }\n            )*\n        }\n    }\n\n    combination_tests! {\n        test_generate_4_2: (4, 2, Ok(vec![\n            vec![0, 1],\n            vec![0, 2],\n            vec![0, 3],\n            vec![1, 2],\n            vec![1, 3],\n            vec![2, 3],\n        ])),\n        test_generate_4_3: (4, 3, Ok(vec![\n            vec![0, 1, 2],\n            vec![0, 1, 3],\n            vec![0, 2, 3],\n            vec![1, 2, 3],\n        ])),\n        test_generate_5_3: (5, 3, Ok(vec![\n            vec![0, 1, 2],\n            vec![0, 1, 3],\n            vec![0, 1, 4],\n            vec![0, 2, 3],\n            vec![0, 2, 4],\n            vec![0, 3, 4],\n            vec![1, 2, 3],\n            vec![1, 2, 4],\n            vec![1, 3, 4],\n            vec![2, 3, 4],\n        ])),\n        test_generate_5_1: (5, 1, Ok(vec![\n            vec![0],\n            vec![1],\n            vec![2],\n            vec![3],\n            vec![4],\n        ])),\n        test_empty: (0, 0, Ok(vec![vec![]])),\n        test_generate_n_eq_k: (3, 3, Ok(vec![\n            vec![0, 1, 2],\n        ])),\n        test_generate_k_greater_than_n: (3, 4, Err(CombinationError::KGreaterThanN)),\n        test_zero_range_with_nonzero_k: (0, 1, Err(CombinationError::InvalidZeroRange)),\n    }\n}\n"
  },
  {
    "path": "src/backtracking/graph_coloring.rs",
    "content": "//! This module provides functionality for generating all possible colorings of a undirected (or directed) graph\n//! given a certain number of colors. It includes the GraphColoring struct and methods\n//! for validating color assignments and finding all valid colorings.\n\n/// Represents potential errors when coloring on an adjacency matrix.\n#[derive(Debug, PartialEq, Eq)]\npub enum GraphColoringError {\n    // Indicates that the adjacency matrix is empty\n    EmptyAdjacencyMatrix,\n    // Indicates that the adjacency matrix is not squared\n    ImproperAdjacencyMatrix,\n}\n\n/// Generates all possible valid colorings of a graph.\n///\n/// # Arguments\n///\n/// * `adjacency_matrix` - A 2D vector representing the adjacency matrix of the graph.\n/// * `num_colors` - The number of colors available for coloring the graph.\n///\n/// # Returns\n///\n/// * A `Result` containing an `Option` with a vector of solutions or a `GraphColoringError` if\n/// there is an issue with the matrix.\npub fn generate_colorings(\n    adjacency_matrix: Vec<Vec<bool>>,\n    num_colors: usize,\n) -> Result<Option<Vec<Vec<usize>>>, GraphColoringError> {\n    Ok(GraphColoring::new(adjacency_matrix)?.find_solutions(num_colors))\n}\n\n/// A struct representing a graph coloring problem.\nstruct GraphColoring {\n    // The adjacency matrix of the graph\n    adjacency_matrix: Vec<Vec<bool>>,\n    // The current colors assigned to each vertex\n    vertex_colors: Vec<usize>,\n    // Vector of all valid color assignments for the vertices found during the search\n    solutions: Vec<Vec<usize>>,\n}\n\nimpl GraphColoring {\n    /// Creates a new GraphColoring instance.\n    ///\n    /// # Arguments\n    ///\n    /// * `adjacency_matrix` - A 2D vector representing the adjacency matrix of the graph.\n    ///\n    /// # Returns\n    ///\n    /// * A new instance of GraphColoring or a `GraphColoringError` if the matrix is empty or non-square.\n    fn new(adjacency_matrix: Vec<Vec<bool>>) -> Result<Self, GraphColoringError> {\n        let num_vertices = adjacency_matrix.len();\n\n        // Check if the adjacency matrix is empty\n        if num_vertices == 0 {\n            return Err(GraphColoringError::EmptyAdjacencyMatrix);\n        }\n\n        // Check if the adjacency matrix is square\n        if adjacency_matrix.iter().any(|row| row.len() != num_vertices) {\n            return Err(GraphColoringError::ImproperAdjacencyMatrix);\n        }\n\n        Ok(GraphColoring {\n            adjacency_matrix,\n            vertex_colors: vec![usize::MAX; num_vertices],\n            solutions: Vec::new(),\n        })\n    }\n\n    /// Returns the number of vertices in the graph.\n    fn num_vertices(&self) -> usize {\n        self.adjacency_matrix.len()\n    }\n\n    /// Checks if a given color can be assigned to a vertex without causing a conflict.\n    ///\n    /// # Arguments\n    ///\n    /// * `vertex` - The index of the vertex to be colored.\n    /// * `color` - The color to be assigned to the vertex.\n    ///\n    /// # Returns\n    ///\n    /// * `true` if the color can be assigned to the vertex, `false` otherwise.\n    fn is_color_valid(&self, vertex: usize, color: usize) -> bool {\n        for neighbor in 0..self.num_vertices() {\n            // Check outgoing edges from vertex and incoming edges to vertex\n            if (self.adjacency_matrix[vertex][neighbor] || self.adjacency_matrix[neighbor][vertex])\n                && self.vertex_colors[neighbor] == color\n            {\n                return false;\n            }\n        }\n        true\n    }\n\n    /// Recursively finds all valid colorings for the graph.\n    ///\n    /// # Arguments\n    ///\n    /// * `vertex` - The current vertex to be colored.\n    /// * `num_colors` - The number of colors available for coloring the graph.\n    fn find_colorings(&mut self, vertex: usize, num_colors: usize) {\n        if vertex == self.num_vertices() {\n            self.solutions.push(self.vertex_colors.clone());\n            return;\n        }\n\n        for color in 0..num_colors {\n            if self.is_color_valid(vertex, color) {\n                self.vertex_colors[vertex] = color;\n                self.find_colorings(vertex + 1, num_colors);\n                self.vertex_colors[vertex] = usize::MAX;\n            }\n        }\n    }\n\n    /// Finds all solutions for the graph coloring problem.\n    ///\n    /// # Arguments\n    ///\n    /// * `num_colors` - The number of colors available for coloring the graph.\n    ///\n    /// # Returns\n    ///\n    /// * A `Result` containing an `Option` with a vector of solutions or a `GraphColoringError`.\n    fn find_solutions(&mut self, num_colors: usize) -> Option<Vec<Vec<usize>>> {\n        self.find_colorings(0, num_colors);\n        if self.solutions.is_empty() {\n            None\n        } else {\n            Some(std::mem::take(&mut self.solutions))\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_graph_coloring {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (adjacency_matrix, num_colors, expected) = $test_case;\n                    let actual = generate_colorings(adjacency_matrix, num_colors);\n                    assert_eq!(actual, expected);\n                }\n            )*\n        };\n    }\n\n    test_graph_coloring! {\n        test_complete_graph_with_3_colors: (\n            vec![\n                vec![false, true, true, true],\n                vec![true, false, true, false],\n                vec![true, true, false, true],\n                vec![true, false, true, false],\n            ],\n            3,\n            Ok(Some(vec![\n                vec![0, 1, 2, 1],\n                vec![0, 2, 1, 2],\n                vec![1, 0, 2, 0],\n                vec![1, 2, 0, 2],\n                vec![2, 0, 1, 0],\n                vec![2, 1, 0, 1],\n            ]))\n        ),\n        test_linear_graph_with_2_colors: (\n            vec![\n                vec![false, true, false, false],\n                vec![true, false, true, false],\n                vec![false, true, false, true],\n                vec![false, false, true, false],\n            ],\n            2,\n            Ok(Some(vec![\n                vec![0, 1, 0, 1],\n                vec![1, 0, 1, 0],\n            ]))\n        ),\n        test_incomplete_graph_with_insufficient_colors: (\n            vec![\n                vec![false, true, true],\n                vec![true, false, true],\n                vec![true, true, false],\n            ],\n            1,\n            Ok(None::<Vec<Vec<usize>>>)\n        ),\n        test_empty_graph: (\n            vec![],\n            1,\n            Err(GraphColoringError::EmptyAdjacencyMatrix)\n        ),\n        test_non_square_matrix: (\n            vec![\n                vec![false, true, true],\n                vec![true, false, true],\n            ],\n            3,\n            Err(GraphColoringError::ImproperAdjacencyMatrix)\n        ),\n        test_single_vertex_graph: (\n            vec![\n                vec![false],\n            ],\n            1,\n            Ok(Some(vec![\n                vec![0],\n            ]))\n        ),\n        test_bipartite_graph_with_2_colors: (\n            vec![\n                vec![false, true, false, true],\n                vec![true, false, true, false],\n                vec![false, true, false, true],\n                vec![true, false, true, false],\n            ],\n            2,\n            Ok(Some(vec![\n                vec![0, 1, 0, 1],\n                vec![1, 0, 1, 0],\n            ]))\n        ),\n        test_large_graph_with_3_colors: (\n            vec![\n                vec![false, true, true, false, true, true, false, true, true, false],\n                vec![true, false, true, true, false, true, true, false, true, true],\n                vec![true, true, false, true, true, false, true, true, false, true],\n                vec![false, true, true, false, true, true, false, true, true, false],\n                vec![true, false, true, true, false, true, true, false, true, true],\n                vec![true, true, false, true, true, false, true, true, false, true],\n                vec![false, true, true, false, true, true, false, true, true, false],\n                vec![true, false, true, true, false, true, true, false, true, true],\n                vec![true, true, false, true, true, false, true, true, false, true],\n                vec![false, true, true, false, true, true, false, true, true, false],\n            ],\n            3,\n            Ok(Some(vec![\n                vec![0, 1, 2, 0, 1, 2, 0, 1, 2, 0],\n                vec![0, 2, 1, 0, 2, 1, 0, 2, 1, 0],\n                vec![1, 0, 2, 1, 0, 2, 1, 0, 2, 1],\n                vec![1, 2, 0, 1, 2, 0, 1, 2, 0, 1],\n                vec![2, 0, 1, 2, 0, 1, 2, 0, 1, 2],\n                vec![2, 1, 0, 2, 1, 0, 2, 1, 0, 2],\n            ]))\n        ),\n        test_disconnected_graph: (\n            vec![\n                vec![false, false, false],\n                vec![false, false, false],\n                vec![false, false, false],\n            ],\n            2,\n            Ok(Some(vec![\n                vec![0, 0, 0],\n                vec![0, 0, 1],\n                vec![0, 1, 0],\n                vec![0, 1, 1],\n                vec![1, 0, 0],\n                vec![1, 0, 1],\n                vec![1, 1, 0],\n                vec![1, 1, 1],\n            ]))\n        ),\n        test_no_valid_coloring: (\n            vec![\n                vec![false, true, true],\n                vec![true, false, true],\n                vec![true, true, false],\n            ],\n            2,\n            Ok(None::<Vec<Vec<usize>>>)\n        ),\n        test_more_colors_than_nodes: (\n            vec![\n                vec![true, true],\n                vec![true, true],\n            ],\n            3,\n            Ok(Some(vec![\n                vec![0, 1],\n                vec![0, 2],\n                vec![1, 0],\n                vec![1, 2],\n                vec![2, 0],\n                vec![2, 1],\n            ]))\n        ),\n        test_no_coloring_with_zero_colors: (\n            vec![\n                vec![true],\n            ],\n            0,\n            Ok(None::<Vec<Vec<usize>>>)\n        ),\n        test_complete_graph_with_3_vertices_and_3_colors: (\n            vec![\n                vec![false, true, true],\n                vec![true, false, true],\n                vec![true, true, false],\n            ],\n            3,\n            Ok(Some(vec![\n                vec![0, 1, 2],\n                vec![0, 2, 1],\n                vec![1, 0, 2],\n                vec![1, 2, 0],\n                vec![2, 0, 1],\n                vec![2, 1, 0],\n            ]))\n        ),\n        test_directed_graph_with_3_colors: (\n            vec![\n                vec![false, true, false, true],\n                vec![false, false, true, false],\n                vec![true, false, false, true],\n                vec![true, false, false, false],\n            ],\n            3,\n            Ok(Some(vec![\n                vec![0, 1, 2, 1],\n                vec![0, 2, 1, 2],\n                vec![1, 0, 2, 0],\n                vec![1, 2, 0, 2],\n                vec![2, 0, 1, 0],\n                vec![2, 1, 0, 1],\n            ]))\n        ),\n        test_directed_graph_no_valid_coloring: (\n            vec![\n                vec![false, true, false, true],\n                vec![false, false, true, true],\n                vec![true, false, false, true],\n                vec![true, false, false, false],\n            ],\n            3,\n            Ok(None::<Vec<Vec<usize>>>)\n        ),\n        test_large_directed_graph_with_3_colors: (\n            vec![\n                vec![false, true, false, false, true, false, false, true, false, false],\n                vec![false, false, true, false, false, true, false, false, true, false],\n                vec![false, false, false, true, false, false, true, false, false, true],\n                vec![true, false, false, false, true, false, false, true, false, false],\n                vec![false, true, false, false, false, true, false, false, true, false],\n                vec![false, false, true, false, false, false, true, false, false, true],\n                vec![true, false, false, false, true, false, false, true, false, false],\n                vec![false, true, false, false, false, true, false, false, true, false],\n                vec![false, false, true, false, false, false, true, false, false, true],\n                vec![true, false, false, false, true, false, false, true, false, false],\n            ],\n            3,\n            Ok(Some(vec![\n                vec![0, 1, 2, 1, 2, 0, 1, 2, 0, 1],\n                vec![0, 2, 1, 2, 1, 0, 2, 1, 0, 2],\n                vec![1, 0, 2, 0, 2, 1, 0, 2, 1, 0],\n                vec![1, 2, 0, 2, 0, 1, 2, 0, 1, 2],\n                vec![2, 0, 1, 0, 1, 2, 0, 1, 2, 0],\n                vec![2, 1, 0, 1, 0, 2, 1, 0, 2, 1]\n            ]))\n        ),\n    }\n}\n"
  },
  {
    "path": "src/backtracking/hamiltonian_cycle.rs",
    "content": "//! This module provides functionality to find a Hamiltonian cycle in a directed or undirected graph.\n//! Source: [Wikipedia](https://en.wikipedia.org/wiki/Hamiltonian_path_problem)\n\n/// Represents potential errors when finding hamiltonian cycle on an adjacency matrix.\n#[derive(Debug, PartialEq, Eq)]\npub enum FindHamiltonianCycleError {\n    /// Indicates that the adjacency matrix is empty.\n    EmptyAdjacencyMatrix,\n    /// Indicates that the adjacency matrix is not square.\n    ImproperAdjacencyMatrix,\n    /// Indicates that the starting vertex is out of bounds.\n    StartOutOfBound,\n}\n\n/// Represents a graph using an adjacency matrix.\nstruct Graph {\n    /// The adjacency matrix representing the graph.\n    adjacency_matrix: Vec<Vec<bool>>,\n}\n\nimpl Graph {\n    /// Creates a new graph with the provided adjacency matrix.\n    ///\n    /// # Arguments\n    ///\n    /// * `adjacency_matrix` - A square matrix where each element indicates\n    ///                        the presence (`true`) or absence (`false`) of an edge\n    ///                        between two vertices.\n    ///\n    /// # Returns\n    ///\n    /// A `Result` containing the graph if successful, or an `FindHamiltonianCycleError` if there is an issue with the matrix.\n    fn new(adjacency_matrix: Vec<Vec<bool>>) -> Result<Self, FindHamiltonianCycleError> {\n        // Check if the adjacency matrix is empty.\n        if adjacency_matrix.is_empty() {\n            return Err(FindHamiltonianCycleError::EmptyAdjacencyMatrix);\n        }\n\n        // Validate that the adjacency matrix is square.\n        if adjacency_matrix\n            .iter()\n            .any(|row| row.len() != adjacency_matrix.len())\n        {\n            return Err(FindHamiltonianCycleError::ImproperAdjacencyMatrix);\n        }\n\n        Ok(Self { adjacency_matrix })\n    }\n\n    /// Returns the number of vertices in the graph.\n    fn num_vertices(&self) -> usize {\n        self.adjacency_matrix.len()\n    }\n\n    /// Determines if it is safe to include vertex `v` in the Hamiltonian cycle path.\n    ///\n    /// # Arguments\n    ///\n    /// * `v` - The index of the vertex being considered.\n    /// * `visited` - A reference to the vector representing the visited vertices.\n    /// * `path` - A reference to the current path being explored.\n    /// * `pos` - The position of the current vertex being considered.\n    ///\n    /// # Returns\n    ///\n    /// `true` if it is safe to include `v` in the path, `false` otherwise.\n    fn is_safe(&self, v: usize, visited: &[bool], path: &[Option<usize>], pos: usize) -> bool {\n        // Check if the current vertex and the last vertex in the path are adjacent.\n        if !self.adjacency_matrix[path[pos - 1].unwrap()][v] {\n            return false;\n        }\n\n        // Check if the vertex has already been included in the path.\n        !visited[v]\n    }\n\n    /// Recursively searches for a Hamiltonian cycle.\n    ///\n    /// This function is called by `find_hamiltonian_cycle`.\n    ///\n    /// # Arguments\n    ///\n    /// * `path` - A mutable vector representing the current path being explored.\n    /// * `visited` - A mutable vector representing the visited vertices.\n    /// * `pos` - The position of the current vertex being considered.\n    ///\n    /// # Returns\n    ///\n    /// `true` if a Hamiltonian cycle is found, `false` otherwise.\n    fn hamiltonian_cycle_util(\n        &self,\n        path: &mut [Option<usize>],\n        visited: &mut [bool],\n        pos: usize,\n    ) -> bool {\n        if pos == self.num_vertices() {\n            // Check if there is an edge from the last included vertex to the first vertex.\n            return self.adjacency_matrix[path[pos - 1].unwrap()][path[0].unwrap()];\n        }\n\n        for v in 0..self.num_vertices() {\n            if self.is_safe(v, visited, path, pos) {\n                path[pos] = Some(v);\n                visited[v] = true;\n                if self.hamiltonian_cycle_util(path, visited, pos + 1) {\n                    return true;\n                }\n                path[pos] = None;\n                visited[v] = false;\n            }\n        }\n\n        false\n    }\n\n    /// Attempts to find a Hamiltonian cycle in the graph, starting from the specified vertex.\n    ///\n    /// A Hamiltonian cycle visits every vertex exactly once and returns to the starting vertex.\n    ///\n    /// # Note\n    /// This implementation may not find all possible Hamiltonian cycles.\n    /// It stops as soon as it finds one valid cycle. If multiple Hamiltonian cycles exist,\n    /// only one will be returned.\n    ///\n    /// # Returns\n    ///\n    /// `Ok(Some(path))` if a Hamiltonian cycle is found, where `path` is a vector\n    /// containing the indices of vertices in the cycle, starting and ending with the same vertex.\n    ///\n    /// `Ok(None)` if no Hamiltonian cycle exists.\n    fn find_hamiltonian_cycle(\n        &self,\n        start_vertex: usize,\n    ) -> Result<Option<Vec<usize>>, FindHamiltonianCycleError> {\n        // Validate the start vertex.\n        if start_vertex >= self.num_vertices() {\n            return Err(FindHamiltonianCycleError::StartOutOfBound);\n        }\n\n        // Initialize the path.\n        let mut path = vec![None; self.num_vertices()];\n        // Start at the specified vertex.\n        path[0] = Some(start_vertex);\n\n        // Initialize the visited vector.\n        let mut visited = vec![false; self.num_vertices()];\n        visited[start_vertex] = true;\n\n        if self.hamiltonian_cycle_util(&mut path, &mut visited, 1) {\n            // Complete the cycle by returning to the starting vertex.\n            path.push(Some(start_vertex));\n            Ok(Some(path.into_iter().map(Option::unwrap).collect()))\n        } else {\n            Ok(None)\n        }\n    }\n}\n\n/// Attempts to find a Hamiltonian cycle in a graph represented by an adjacency matrix, starting from a specified vertex.\npub fn find_hamiltonian_cycle(\n    adjacency_matrix: Vec<Vec<bool>>,\n    start_vertex: usize,\n) -> Result<Option<Vec<usize>>, FindHamiltonianCycleError> {\n    Graph::new(adjacency_matrix)?.find_hamiltonian_cycle(start_vertex)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! hamiltonian_cycle_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (adjacency_matrix, start_vertex, expected) = $test_case;\n                    let result = find_hamiltonian_cycle(adjacency_matrix, start_vertex);\n                    assert_eq!(result, expected);\n                }\n            )*\n        };\n    }\n\n    hamiltonian_cycle_tests! {\n        test_complete_graph: (\n            vec![\n                vec![false, true, true, true],\n                vec![true, false, true, true],\n                vec![true, true, false, true],\n                vec![true, true, true, false],\n            ],\n            0,\n            Ok(Some(vec![0, 1, 2, 3, 0]))\n        ),\n        test_directed_graph_with_cycle: (\n            vec![\n                vec![false, true, false, false, false],\n                vec![false, false, true, true, false],\n                vec![true, false, false, true, true],\n                vec![false, false, true, false, true],\n                vec![true, true, false, false, false],\n            ],\n            2,\n            Ok(Some(vec![2, 3, 4, 0, 1, 2]))\n        ),\n        test_undirected_graph_with_cycle: (\n            vec![\n                vec![false, true, false, false, true],\n                vec![true, false, true, false, false],\n                vec![false, true, false, true, false],\n                vec![false, false, true, false, true],\n                vec![true, false, false, true, false],\n            ],\n            2,\n            Ok(Some(vec![2, 1, 0, 4, 3, 2]))\n        ),\n        test_directed_graph_no_cycle: (\n            vec![\n                vec![false, true, false, true, false],\n                vec![false, false, true, true, false],\n                vec![false, false, false, true, false],\n                vec![false, false, false, false, true],\n                vec![false, false, true, false, false],\n            ],\n            0,\n            Ok(None::<Vec<usize>>)\n        ),\n        test_undirected_graph_no_cycle: (\n            vec![\n                vec![false, true, false, false, false],\n                vec![true, false, true, true, false],\n                vec![false, true, false, true, true],\n                vec![false, true, true, false, true],\n                vec![false, false, true, true, false],\n            ],\n            0,\n            Ok(None::<Vec<usize>>)\n        ),\n        test_triangle_graph: (\n            vec![\n                vec![false, true, false],\n                vec![false, false, true],\n                vec![true, false, false],\n            ],\n            1,\n            Ok(Some(vec![1, 2, 0, 1]))\n        ),\n        test_tree_graph: (\n            vec![\n                vec![false, true, false, true, false],\n                vec![true, false, true, true, false],\n                vec![false, true, false, false, false],\n                vec![true, true, false, false, true],\n                vec![false, false, false, true, false],\n            ],\n            0,\n            Ok(None::<Vec<usize>>)\n        ),\n        test_empty_graph: (\n            vec![],\n            0,\n            Err(FindHamiltonianCycleError::EmptyAdjacencyMatrix)\n        ),\n        test_improper_graph: (\n            vec![\n                vec![false, true],\n                vec![true],\n                vec![false, true, true],\n                vec![true, true, true, false]\n            ],\n            0,\n            Err(FindHamiltonianCycleError::ImproperAdjacencyMatrix)\n        ),\n        test_start_out_of_bound: (\n            vec![\n                vec![false, true, true],\n                vec![true, false, true],\n                vec![true, true, false],\n            ],\n            3,\n            Err(FindHamiltonianCycleError::StartOutOfBound)\n        ),\n        test_complex_directed_graph: (\n            vec![\n                vec![false, true, false, true, false, false],\n                vec![false, false, true, false, true, false],\n                vec![false, false, false, true, false, false],\n                vec![false, true, false, false, true, false],\n                vec![false, false, true, false, false, true],\n                vec![true, false, false, false, false, false],\n            ],\n            0,\n            Ok(Some(vec![0, 1, 2, 3, 4, 5, 0]))\n        ),\n        single_node_self_loop: (\n            vec![\n                vec![true],\n            ],\n            0,\n            Ok(Some(vec![0, 0]))\n        ),\n        single_node: (\n            vec![\n                vec![false],\n            ],\n            0,\n            Ok(None)\n        ),\n    }\n}\n"
  },
  {
    "path": "src/backtracking/knight_tour.rs",
    "content": "//! This module contains the implementation of the Knight's Tour problem.\n//!\n//! The Knight's Tour is a classic chess problem where the objective is to move a knight to every square on a chessboard exactly once.\n\n/// Finds the Knight's Tour starting from the specified position.\n///\n/// # Arguments\n///\n/// * `size_x` - The width of the chessboard.\n/// * `size_y` - The height of the chessboard.\n/// * `start_x` - The x-coordinate of the starting position.\n/// * `start_y` - The y-coordinate of the starting position.\n///\n/// # Returns\n///\n/// A tour matrix if the tour was found or None if not found.\n/// The tour matrix returned is essentially the board field of the `KnightTour`\n/// struct `Vec<Vec<usize>>`. It represents the sequence of moves made by the\n/// knight on the chessboard, with each cell containing the order in which the knight visited that square.\npub fn find_knight_tour(\n    size_x: usize,\n    size_y: usize,\n    start_x: usize,\n    start_y: usize,\n) -> Option<Vec<Vec<usize>>> {\n    let mut tour = KnightTour::new(size_x, size_y);\n    tour.find_tour(start_x, start_y)\n}\n\n/// Represents the KnightTour struct which implements the Knight's Tour problem.\nstruct KnightTour {\n    board: Vec<Vec<usize>>,\n}\n\nimpl KnightTour {\n    /// Possible moves of the knight on the board\n    const MOVES: [(isize, isize); 8] = [\n        (2, 1),\n        (1, 2),\n        (-1, 2),\n        (-2, 1),\n        (-2, -1),\n        (-1, -2),\n        (1, -2),\n        (2, -1),\n    ];\n\n    /// Constructs a new KnightTour instance with the given board size.\n    /// # Arguments\n    ///\n    /// * `size_x` - The width of the chessboard.\n    /// * `size_y` - The height of the chessboard.\n    ///\n    /// # Returns\n    ///\n    /// A new KnightTour instance.\n    fn new(size_x: usize, size_y: usize) -> Self {\n        let board = vec![vec![0; size_x]; size_y];\n        KnightTour { board }\n    }\n\n    /// Returns the width of the chessboard.\n    fn size_x(&self) -> usize {\n        self.board.len()\n    }\n\n    /// Returns the height of the chessboard.\n    fn size_y(&self) -> usize {\n        self.board[0].len()\n    }\n\n    /// Checks if the given position is safe to move to.\n    ///\n    /// # Arguments\n    ///\n    /// * `x` - The x-coordinate of the position.\n    /// * `y` - The y-coordinate of the position.\n    ///\n    /// # Returns\n    ///\n    /// A boolean indicating whether the position is safe to move to.\n    fn is_safe(&self, x: isize, y: isize) -> bool {\n        x >= 0\n            && y >= 0\n            && x < self.size_x() as isize\n            && y < self.size_y() as isize\n            && self.board[x as usize][y as usize] == 0\n    }\n\n    /// Recursively solves the Knight's Tour problem.\n    ///\n    /// # Arguments\n    ///\n    /// * `x` - The current x-coordinate of the knight.\n    /// * `y` - The current y-coordinate of the knight.\n    /// * `move_count` - The current move count.\n    ///\n    /// # Returns\n    ///\n    /// A boolean indicating whether a solution was found.\n    fn solve_tour(&mut self, x: isize, y: isize, move_count: usize) -> bool {\n        if move_count == self.size_x() * self.size_y() {\n            return true;\n        }\n        for &(dx, dy) in &Self::MOVES {\n            let next_x = x + dx;\n            let next_y = y + dy;\n\n            if self.is_safe(next_x, next_y) {\n                self.board[next_x as usize][next_y as usize] = move_count + 1;\n\n                if self.solve_tour(next_x, next_y, move_count + 1) {\n                    return true;\n                }\n                // Backtrack\n                self.board[next_x as usize][next_y as usize] = 0;\n            }\n        }\n\n        false\n    }\n\n    /// Finds the Knight's Tour starting from the specified position.\n    ///\n    /// # Arguments\n    ///\n    /// * `start_x` - The x-coordinate of the starting position.\n    /// * `start_y` - The y-coordinate of the starting position.\n    ///\n    /// # Returns\n    ///\n    /// A tour matrix if the tour was found or None if not found.\n    fn find_tour(&mut self, start_x: usize, start_y: usize) -> Option<Vec<Vec<usize>>> {\n        if !self.is_safe(start_x as isize, start_y as isize) {\n            return None;\n        }\n\n        self.board[start_x][start_y] = 1;\n\n        if !self.solve_tour(start_x as isize, start_y as isize, 1) {\n            return None;\n        }\n\n        Some(self.board.clone())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_find_knight_tour {\n        ($($name:ident: $tc:expr,)*) => {\n        $(\n            #[test]\n            fn $name() {\n                let (size_x, size_y, start_x, start_y, expected) = $tc;\n                if expected.is_some() {\n                    assert_eq!(expected.clone().unwrap()[start_x][start_y], 1)\n                }\n                assert_eq!(find_knight_tour(size_x, size_y, start_x, start_y), expected);\n            }\n        )*\n        }\n    }\n    test_find_knight_tour! {\n        test_knight_tour_5x5: (5, 5, 0, 0, Some(vec![\n            vec![1, 6, 15, 10, 21],\n            vec![14, 9, 20, 5, 16],\n            vec![19, 2, 7, 22, 11],\n            vec![8, 13, 24, 17, 4],\n            vec![25, 18, 3, 12, 23],\n        ])),\n        test_knight_tour_6x6: (6, 6, 0, 0, Some(vec![\n            vec![1, 16, 7, 26, 11, 14],\n            vec![34, 25, 12, 15, 6, 27],\n            vec![17, 2, 33, 8, 13, 10],\n            vec![32, 35, 24, 21, 28, 5],\n            vec![23, 18, 3, 30, 9, 20],\n            vec![36, 31, 22, 19, 4, 29],\n        ])),\n        test_knight_tour_8x8: (8, 8, 0, 0, Some(vec![\n            vec![1, 60, 39, 34, 31, 18, 9, 64],\n            vec![38, 35, 32, 61, 10, 63, 30, 17],\n            vec![59, 2, 37, 40, 33, 28, 19, 8],\n            vec![36, 49, 42, 27, 62, 11, 16, 29],\n            vec![43, 58, 3, 50, 41, 24, 7, 20],\n            vec![48, 51, 46, 55, 26, 21, 12, 15],\n            vec![57, 44, 53, 4, 23, 14, 25, 6],\n            vec![52, 47, 56, 45, 54, 5, 22, 13],\n        ])),\n        test_no_solution: (5, 5, 2, 1, None::<Vec<Vec<usize>>>),\n        test_invalid_start_position: (8, 8, 10, 10, None::<Vec<Vec<usize>>>),\n    }\n}\n"
  },
  {
    "path": "src/backtracking/mod.rs",
    "content": "mod all_combination_of_size_k;\nmod graph_coloring;\nmod hamiltonian_cycle;\nmod knight_tour;\nmod n_queens;\nmod parentheses_generator;\nmod permutations;\nmod rat_in_maze;\nmod subset_sum;\nmod sudoku;\n\npub use all_combination_of_size_k::generate_all_combinations;\npub use graph_coloring::generate_colorings;\npub use hamiltonian_cycle::find_hamiltonian_cycle;\npub use knight_tour::find_knight_tour;\npub use n_queens::n_queens_solver;\npub use parentheses_generator::generate_parentheses;\npub use permutations::permute;\npub use rat_in_maze::find_path_in_maze;\npub use subset_sum::has_subset_with_sum;\npub use sudoku::sudoku_solver;\n"
  },
  {
    "path": "src/backtracking/n_queens.rs",
    "content": "//! This module provides functionality to solve the N-Queens problem.\n//!\n//! The N-Queens problem is a classic chessboard puzzle where the goal is to\n//! place N queens on an NxN chessboard so that no two queens threaten each\n//! other. Queens can attack each other if they share the same row, column, or\n//! diagonal.\n//!\n//! This implementation solves the N-Queens problem using a backtracking algorithm.\n//! It starts with an empty chessboard and iteratively tries to place queens in\n//! different rows, ensuring they do not conflict with each other. If a valid\n//! solution is found, it's added to the list of solutions.\n\n/// Solves the N-Queens problem for a given size and returns a vector of solutions.\n///\n/// # Arguments\n///\n/// * `n` - The size of the chessboard (NxN).\n///\n/// # Returns\n///\n/// A vector containing all solutions to the N-Queens problem.\npub fn n_queens_solver(n: usize) -> Vec<Vec<String>> {\n    let mut solver = NQueensSolver::new(n);\n    solver.solve()\n}\n\n/// Represents a solver for the N-Queens problem.\nstruct NQueensSolver {\n    // The size of the chessboard\n    size: usize,\n    // A 2D vector representing the chessboard where '.' denotes an empty space and 'Q' denotes a queen\n    board: Vec<Vec<char>>,\n    // A vector to store all valid solutions\n    solutions: Vec<Vec<String>>,\n}\n\nimpl NQueensSolver {\n    /// Creates a new `NQueensSolver` instance with the given size.\n    ///\n    /// # Arguments\n    ///\n    /// * `size` - The size of the chessboard (N×N).\n    ///\n    /// # Returns\n    ///\n    /// A new `NQueensSolver` instance.\n    fn new(size: usize) -> Self {\n        NQueensSolver {\n            size,\n            board: vec![vec!['.'; size]; size],\n            solutions: Vec::new(),\n        }\n    }\n\n    /// Solves the N-Queens problem and returns a vector of solutions.\n    ///\n    /// # Returns\n    ///\n    /// A vector containing all solutions to the N-Queens problem.\n    fn solve(&mut self) -> Vec<Vec<String>> {\n        self.solve_helper(0);\n        std::mem::take(&mut self.solutions)\n    }\n\n    /// Checks if it's safe to place a queen at the specified position (row, col).\n    ///\n    /// # Arguments\n    ///\n    /// * `row` - The row index of the position to check.\n    /// * `col` - The column index of the position to check.\n    ///\n    /// # Returns\n    ///\n    /// `true` if it's safe to place a queen at the specified position, `false` otherwise.\n    fn is_safe(&self, row: usize, col: usize) -> bool {\n        // Check column and diagonals\n        for i in 0..row {\n            if self.board[i][col] == 'Q'\n                || (col >= row - i && self.board[i][col - (row - i)] == 'Q')\n                || (col + row - i < self.size && self.board[i][col + (row - i)] == 'Q')\n            {\n                return false;\n            }\n        }\n        true\n    }\n\n    /// Recursive helper function to solve the N-Queens problem.\n    ///\n    /// # Arguments\n    ///\n    /// * `row` - The current row being processed.\n    fn solve_helper(&mut self, row: usize) {\n        if row == self.size {\n            self.solutions\n                .push(self.board.iter().map(|row| row.iter().collect()).collect());\n            return;\n        }\n\n        for col in 0..self.size {\n            if self.is_safe(row, col) {\n                self.board[row][col] = 'Q';\n                self.solve_helper(row + 1);\n                self.board[row][col] = '.';\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_n_queens_solver {\n        ($($name:ident: $tc:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (n, expected_solutions) = $tc;\n                    let solutions = n_queens_solver(n);\n                    assert_eq!(solutions, expected_solutions);\n                }\n            )*\n        };\n    }\n\n    test_n_queens_solver! {\n        test_0_queens: (0, vec![Vec::<String>::new()]),\n        test_1_queen: (1, vec![vec![\"Q\"]]),\n        test_2_queens:(2, Vec::<Vec<String>>::new()),\n        test_3_queens:(3, Vec::<Vec<String>>::new()),\n        test_4_queens: (4, vec![\n            vec![\".Q..\",\n                 \"...Q\",\n                 \"Q...\",\n                 \"..Q.\"],\n            vec![\"..Q.\",\n                 \"Q...\",\n                 \"...Q\",\n                 \".Q..\"],\n        ]),\n        test_5_queens:(5, vec![\n            vec![\"Q....\",\n                 \"..Q..\",\n                 \"....Q\",\n                 \".Q...\",\n                 \"...Q.\"],\n            vec![\"Q....\",\n                 \"...Q.\",\n                 \".Q...\",\n                 \"....Q\",\n                 \"..Q..\"],\n            vec![\".Q...\",\n                 \"...Q.\",\n                 \"Q....\",\n                 \"..Q..\",\n                 \"....Q\"],\n            vec![\".Q...\",\n                 \"....Q\",\n                 \"..Q..\",\n                 \"Q....\",\n                 \"...Q.\"],\n            vec![\"..Q..\",\n                 \"Q....\",\n                 \"...Q.\",\n                 \".Q...\",\n                 \"....Q\"],\n            vec![\"..Q..\",\n                 \"....Q\",\n                 \".Q...\",\n                 \"...Q.\",\n                 \"Q....\"],\n            vec![\"...Q.\",\n                 \"Q....\",\n                 \"..Q..\",\n                 \"....Q\",\n                 \".Q...\"],\n            vec![\"...Q.\",\n                 \".Q...\",\n                 \"....Q\",\n                 \"..Q..\",\n                 \"Q....\"],\n            vec![\"....Q\",\n                 \".Q...\",\n                 \"...Q.\",\n                 \"Q....\",\n                 \"..Q..\"],\n            vec![\"....Q\",\n                 \"..Q..\",\n                 \"Q....\",\n                 \"...Q.\",\n                 \".Q...\"],\n        ]),\n        test_6_queens: (6, vec![\n            vec![\".Q....\",\n                 \"...Q..\",\n                 \".....Q\",\n                 \"Q.....\",\n                 \"..Q...\",\n                 \"....Q.\"],\n            vec![\"..Q...\",\n                 \".....Q\",\n                 \".Q....\",\n                 \"....Q.\",\n                 \"Q.....\",\n                 \"...Q..\"],\n            vec![\"...Q..\",\n                 \"Q.....\",\n                 \"....Q.\",\n                 \".Q....\",\n                 \".....Q\",\n                 \"..Q...\"],\n            vec![\"....Q.\",\n                 \"..Q...\",\n                 \"Q.....\",\n                 \".....Q\",\n                 \"...Q..\",\n                 \".Q....\"],\n        ]),\n    }\n}\n"
  },
  {
    "path": "src/backtracking/parentheses_generator.rs",
    "content": "/// Generates all combinations of well-formed parentheses given a non-negative integer `n`.\n///\n/// This function uses backtracking to generate all possible combinations of well-formed\n/// parentheses. The resulting combinations are returned as a vector of strings.\n///\n/// # Arguments\n///\n/// * `n` - A non-negative integer representing the number of pairs of parentheses.\npub fn generate_parentheses(n: usize) -> Vec<String> {\n    let mut result = Vec::new();\n    if n > 0 {\n        generate(\"\", 0, 0, n, &mut result);\n    }\n    result\n}\n\n/// Helper function for generating parentheses recursively.\n///\n/// This function is called recursively to build combinations of well-formed parentheses.\n/// It tracks the number of open and close parentheses added so far and adds a new parenthesis\n/// if it's valid to do so.\n///\n/// # Arguments\n///\n/// * `current` - The current string of parentheses being built.\n/// * `open_count` - The count of open parentheses in the current string.\n/// * `close_count` - The count of close parentheses in the current string.\n/// * `n` - The total number of pairs of parentheses to be generated.\n/// * `result` - A mutable reference to the vector storing the generated combinations.\nfn generate(\n    current: &str,\n    open_count: usize,\n    close_count: usize,\n    n: usize,\n    result: &mut Vec<String>,\n) {\n    if current.len() == (n * 2) {\n        result.push(current.to_string());\n        return;\n    }\n\n    if open_count < n {\n        let new_str = current.to_string() + \"(\";\n        generate(&new_str, open_count + 1, close_count, n, result);\n    }\n\n    if close_count < open_count {\n        let new_str = current.to_string() + \")\";\n        generate(&new_str, open_count, close_count + 1, n, result);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! generate_parentheses_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (n, expected_result) = $test_case;\n                    assert_eq!(generate_parentheses(n), expected_result);\n                }\n            )*\n        };\n    }\n\n    generate_parentheses_tests! {\n        test_generate_parentheses_0: (0, Vec::<String>::new()),\n        test_generate_parentheses_1: (1, vec![\"()\"]),\n        test_generate_parentheses_2: (2, vec![\"(())\", \"()()\"]),\n        test_generate_parentheses_3: (3, vec![\"((()))\", \"(()())\", \"(())()\", \"()(())\", \"()()()\"]),\n        test_generate_parentheses_4: (4, vec![\"(((())))\", \"((()()))\", \"((())())\", \"((()))()\", \"(()(()))\", \"(()()())\", \"(()())()\", \"(())(())\", \"(())()()\", \"()((()))\", \"()(()())\", \"()(())()\", \"()()(())\", \"()()()()\"]),\n    }\n}\n"
  },
  {
    "path": "src/backtracking/permutations.rs",
    "content": "//! This module provides a function to generate all possible distinct permutations\n//! of a given collection of integers using a backtracking algorithm.\n\n/// Generates all possible distinct permutations of a given vector of integers.\n///\n/// # Arguments\n///\n/// * `nums` - A vector of integers. The input vector is sorted before generating\n/// permutations to handle duplicates effectively.\n///\n/// # Returns\n///\n/// A vector containing all possible distinct permutations of the input vector.\npub fn permute(mut nums: Vec<isize>) -> Vec<Vec<isize>> {\n    let mut permutations = Vec::new();\n    let mut current = Vec::new();\n    let mut used = vec![false; nums.len()];\n\n    nums.sort();\n    generate(&nums, &mut current, &mut used, &mut permutations);\n\n    permutations\n}\n\n/// Helper function for the `permute` function to generate distinct permutations recursively.\n///\n/// # Arguments\n///\n/// * `nums` - A reference to the sorted slice of integers.\n/// * `current` - A mutable reference to the vector holding the current permutation.\n/// * `used` - A mutable reference to a vector tracking which elements are used.\n/// * `permutations` - A mutable reference to the vector holding all generated distinct permutations.\nfn generate(\n    nums: &[isize],\n    current: &mut Vec<isize>,\n    used: &mut Vec<bool>,\n    permutations: &mut Vec<Vec<isize>>,\n) {\n    if current.len() == nums.len() {\n        permutations.push(current.clone());\n        return;\n    }\n\n    for idx in 0..nums.len() {\n        if used[idx] {\n            continue;\n        }\n\n        if idx > 0 && nums[idx] == nums[idx - 1] && !used[idx - 1] {\n            continue;\n        }\n\n        current.push(nums[idx]);\n        used[idx] = true;\n\n        generate(nums, current, used, permutations);\n\n        current.pop();\n        used[idx] = false;\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! permute_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $test_case;\n                    assert_eq!(permute(input), expected);\n                }\n            )*\n        }\n    }\n\n    permute_tests! {\n        test_permute_basic: (vec![1, 2, 3], vec![\n            vec![1, 2, 3],\n            vec![1, 3, 2],\n            vec![2, 1, 3],\n            vec![2, 3, 1],\n            vec![3, 1, 2],\n            vec![3, 2, 1],\n        ]),\n        test_permute_empty: (Vec::<isize>::new(), vec![vec![]]),\n        test_permute_single: (vec![1], vec![vec![1]]),\n        test_permute_duplicates: (vec![1, 1, 2], vec![\n            vec![1, 1, 2],\n            vec![1, 2, 1],\n            vec![2, 1, 1],\n        ]),\n        test_permute_all_duplicates: (vec![1, 1, 1, 1], vec![\n            vec![1, 1, 1, 1],\n        ]),\n        test_permute_negative: (vec![-1, -2, -3], vec![\n            vec![-3, -2, -1],\n            vec![-3, -1, -2],\n            vec![-2, -3, -1],\n            vec![-2, -1, -3],\n            vec![-1, -3, -2],\n            vec![-1, -2, -3],\n        ]),\n        test_permute_mixed: (vec![-1, 0, 1], vec![\n            vec![-1, 0, 1],\n            vec![-1, 1, 0],\n            vec![0, -1, 1],\n            vec![0, 1, -1],\n            vec![1, -1, 0],\n            vec![1, 0, -1],\n        ]),\n        test_permute_larger: (vec![1, 2, 3, 4], vec![\n            vec![1, 2, 3, 4],\n            vec![1, 2, 4, 3],\n            vec![1, 3, 2, 4],\n            vec![1, 3, 4, 2],\n            vec![1, 4, 2, 3],\n            vec![1, 4, 3, 2],\n            vec![2, 1, 3, 4],\n            vec![2, 1, 4, 3],\n            vec![2, 3, 1, 4],\n            vec![2, 3, 4, 1],\n            vec![2, 4, 1, 3],\n            vec![2, 4, 3, 1],\n            vec![3, 1, 2, 4],\n            vec![3, 1, 4, 2],\n            vec![3, 2, 1, 4],\n            vec![3, 2, 4, 1],\n            vec![3, 4, 1, 2],\n            vec![3, 4, 2, 1],\n            vec![4, 1, 2, 3],\n            vec![4, 1, 3, 2],\n            vec![4, 2, 1, 3],\n            vec![4, 2, 3, 1],\n            vec![4, 3, 1, 2],\n            vec![4, 3, 2, 1],\n        ]),\n    }\n}\n"
  },
  {
    "path": "src/backtracking/rat_in_maze.rs",
    "content": "//! This module contains the implementation of the Rat in Maze problem.\n//!\n//! The Rat in Maze problem is a classic algorithmic problem where the\n//! objective is to find a path from the starting position to the exit\n//! position in a maze.\n\n/// Enum representing various errors that can occur while working with mazes.\n#[derive(Debug, PartialEq, Eq)]\npub enum MazeError {\n    /// Indicates that the maze is empty (zero rows).\n    EmptyMaze,\n    /// Indicates that the starting position is out of bounds.\n    OutOfBoundPos,\n    /// Indicates an improper representation of the maze (e.g., non-rectangular maze).\n    ImproperMazeRepr,\n}\n\n/// Finds a path through the maze starting from the specified position.\n///\n/// # Arguments\n///\n/// * `maze` - The maze represented as a vector of vectors where each\n/// inner vector represents a row in the maze grid.\n/// * `start_x` - The x-coordinate of the starting position.\n/// * `start_y` - The y-coordinate of the starting position.\n///\n/// # Returns\n///\n/// A `Result` where:\n/// - `Ok(Some(solution))` if a path is found and contains the solution matrix.\n/// - `Ok(None)` if no path is found.\n/// - `Err(MazeError)` for various error conditions such as out-of-bound start position or improper maze representation.\n///\n/// # Solution Selection\n///\n/// The function returns the first successful path it discovers based on the predefined order of moves.\n/// The order of moves is defined in the `MOVES` constant of the `Maze` struct.\n///\n/// The backtracking algorithm explores each direction in this order. If multiple solutions exist,\n/// the algorithm returns the first path it finds according to this sequence. It recursively explores\n/// each direction, marks valid moves, and backtracks if necessary, ensuring that the solution is found\n/// efficiently and consistently.\npub fn find_path_in_maze(\n    maze: &[Vec<bool>],\n    start_x: usize,\n    start_y: usize,\n) -> Result<Option<Vec<Vec<bool>>>, MazeError> {\n    if maze.is_empty() {\n        return Err(MazeError::EmptyMaze);\n    }\n\n    // Validate start position\n    if start_x >= maze.len() || start_y >= maze[0].len() {\n        return Err(MazeError::OutOfBoundPos);\n    }\n\n    // Validate maze representation (if necessary)\n    if maze.iter().any(|row| row.len() != maze[0].len()) {\n        return Err(MazeError::ImproperMazeRepr);\n    }\n\n    // If validations pass, proceed with finding the path\n    let maze_instance = Maze::new(maze.to_owned());\n    Ok(maze_instance.find_path(start_x, start_y))\n}\n\n/// Represents a maze.\nstruct Maze {\n    maze: Vec<Vec<bool>>,\n}\n\nimpl Maze {\n    /// Represents possible moves in the maze.\n    const MOVES: [(isize, isize); 4] = [(0, 1), (1, 0), (0, -1), (-1, 0)];\n\n    /// Constructs a new Maze instance.\n    /// # Arguments\n    ///\n    /// * `maze` - The maze represented as a vector of vectors where each\n    /// inner vector represents a row in the maze grid.\n    ///\n    /// # Returns\n    ///\n    /// A new Maze instance.\n    fn new(maze: Vec<Vec<bool>>) -> Self {\n        Maze { maze }\n    }\n\n    /// Returns the width of the maze.\n    ///\n    /// # Returns\n    ///\n    /// The width of the maze.\n    fn width(&self) -> usize {\n        self.maze[0].len()\n    }\n\n    /// Returns the height of the maze.\n    ///\n    /// # Returns\n    ///\n    /// The height of the maze.\n    fn height(&self) -> usize {\n        self.maze.len()\n    }\n\n    /// Finds a path through the maze starting from the specified position.\n    ///\n    /// # Arguments\n    ///\n    /// * `start_x` - The x-coordinate of the starting position.\n    /// * `start_y` - The y-coordinate of the starting position.\n    ///\n    /// # Returns\n    ///\n    /// A solution matrix if a path is found or None if not found.\n    fn find_path(&self, start_x: usize, start_y: usize) -> Option<Vec<Vec<bool>>> {\n        let mut solution = vec![vec![false; self.width()]; self.height()];\n        if self.solve(start_x as isize, start_y as isize, &mut solution) {\n            Some(solution)\n        } else {\n            None\n        }\n    }\n\n    /// Recursively solves the Rat in Maze problem using backtracking.\n    ///\n    /// # Arguments\n    ///\n    /// * `x` - The current x-coordinate.\n    /// * `y` - The current y-coordinate.\n    /// * `solution` - The current solution matrix.\n    ///\n    /// # Returns\n    ///\n    /// A boolean indicating whether a solution was found.\n    fn solve(&self, x: isize, y: isize, solution: &mut [Vec<bool>]) -> bool {\n        if x == (self.height() as isize - 1) && y == (self.width() as isize - 1) {\n            solution[x as usize][y as usize] = true;\n            return true;\n        }\n\n        if self.is_valid(x, y, solution) {\n            solution[x as usize][y as usize] = true;\n\n            for &(dx, dy) in &Self::MOVES {\n                if self.solve(x + dx, y + dy, solution) {\n                    return true;\n                }\n            }\n\n            // If none of the directions lead to the solution, backtrack\n            solution[x as usize][y as usize] = false;\n            return false;\n        }\n        false\n    }\n\n    /// Checks if a given position is valid in the maze.\n    ///\n    /// # Arguments\n    ///\n    /// * `x` - The x-coordinate of the position.\n    /// * `y` - The y-coordinate of the position.\n    /// * `solution` - The current solution matrix.\n    ///\n    /// # Returns\n    ///\n    /// A boolean indicating whether the position is valid.\n    fn is_valid(&self, x: isize, y: isize, solution: &[Vec<bool>]) -> bool {\n        x >= 0\n            && y >= 0\n            && x < self.height() as isize\n            && y < self.width() as isize\n            && self.maze[x as usize][y as usize]\n            && !solution[x as usize][y as usize]\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_find_path_in_maze {\n        ($($name:ident: $start_x:expr, $start_y:expr, $maze:expr, $expected:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let solution = find_path_in_maze($maze, $start_x, $start_y);\n                    assert_eq!(solution, $expected);\n                    if let Ok(Some(expected_solution)) = &solution {\n                        assert_eq!(expected_solution[$start_x][$start_y], true);\n                    }\n                }\n            )*\n        }\n    }\n\n    test_find_path_in_maze! {\n        maze_with_solution_5x5: 0, 0, &[\n            vec![true, false, true, false, false],\n            vec![true, true, false, true, false],\n            vec![false, true, true, true, false],\n            vec![false, false, false, true, true],\n            vec![false, true, false, false, true],\n        ], Ok(Some(vec![\n            vec![true, false, false, false, false],\n            vec![true, true, false, false, false],\n            vec![false, true, true, true, false],\n            vec![false, false, false, true, true],\n            vec![false, false, false, false, true],\n        ])),\n        maze_with_solution_6x6: 0, 0, &[\n            vec![true, false, true, false, true, false],\n            vec![true, true, false, true, false, true],\n            vec![false, true, true, true, true, false],\n            vec![false, false, false, true, true, true],\n            vec![false, true, false, false, true, false],\n            vec![true, true, true, true, true, true],\n        ], Ok(Some(vec![\n            vec![true, false, false, false, false, false],\n            vec![true, true, false, false, false, false],\n            vec![false, true, true, true, true, false],\n            vec![false, false, false, false, true, false],\n            vec![false, false, false, false, true, false],\n            vec![false, false, false, false, true, true],\n        ])),\n        maze_with_solution_8x8: 0, 0, &[\n            vec![true, false, false, false, false, false, false, true],\n            vec![true, true, false, true, true, true, false, false],\n            vec![false, true, true, true, false, false, false, false],\n            vec![false, false, false, true, false, true, true, false],\n            vec![false, true, false, true, true, true, false, true],\n            vec![true, false, true, false, false, true, true, true],\n            vec![false, false, true, true, true, false, true, true],\n            vec![true, true, true, false, true, true, true, true],\n        ], Ok(Some(vec![\n            vec![true, false, false, false, false, false, false, false],\n            vec![true, true, false, false, false, false, false, false],\n            vec![false, true, true, true, false, false, false, false],\n            vec![false, false, false, true, false, false, false, false],\n            vec![false, false, false, true, true, true, false, false],\n            vec![false, false, false, false, false, true, true, true],\n            vec![false, false, false, false, false, false, false, true],\n            vec![false, false, false, false, false, false, false, true],\n        ])),\n        maze_without_solution_4x4: 0, 0, &[\n            vec![true, false, false, false],\n            vec![true, true, false, false],\n            vec![false, false, true, false],\n            vec![false, false, false, true],\n        ], Ok(None::<Vec<Vec<bool>>>),\n        maze_with_solution_3x4: 0, 0, &[\n            vec![true, false, true, true],\n            vec![true, true, true, false],\n            vec![false, true, true, true],\n        ], Ok(Some(vec![\n            vec![true, false, false, false],\n            vec![true, true, true, false],\n            vec![false, false, true, true],\n        ])),\n        maze_without_solution_3x4: 0, 0, &[\n            vec![true, false, true, true],\n            vec![true, false, true, false],\n            vec![false, true, false, true],\n        ], Ok(None::<Vec<Vec<bool>>>),\n        improper_maze_representation: 0, 0, &[\n            vec![true],\n            vec![true, true],\n            vec![true, true, true],\n            vec![true, true, true, true]\n        ], Err(MazeError::ImproperMazeRepr),\n        out_of_bound_start: 0, 3, &[\n            vec![true, false, true],\n            vec![true, true],\n            vec![false, true, true],\n        ], Err(MazeError::OutOfBoundPos),\n        empty_maze: 0, 0, &[], Err(MazeError::EmptyMaze),\n        maze_with_single_cell: 0, 0, &[\n            vec![true],\n        ], Ok(Some(vec![\n                vec![true]\n        ])),\n        maze_with_one_row_and_multiple_columns: 0, 0, &[\n            vec![true, false, true, true, false]\n        ], Ok(None::<Vec<Vec<bool>>>),\n        maze_with_multiple_rows_and_one_column: 0, 0, &[\n            vec![true],\n            vec![true],\n            vec![false],\n            vec![true],\n        ], Ok(None::<Vec<Vec<bool>>>),\n        maze_with_walls_surrounding_border: 0, 0, &[\n            vec![false, false, false],\n            vec![false, true, false],\n            vec![false, false, false],\n        ], Ok(None::<Vec<Vec<bool>>>),\n        maze_with_no_walls: 0, 0, &[\n            vec![true, true, true],\n            vec![true, true, true],\n            vec![true, true, true],\n        ], Ok(Some(vec![\n            vec![true, true, true],\n            vec![false, false, true],\n            vec![false, false, true],\n        ])),\n        maze_with_going_back: 0, 0, &[\n            vec![true,  true,  true,  true, true,   true],\n            vec![false, false, false, true, false,  true],\n            vec![true,  true,  true,  true,  false, false],\n            vec![true,  false, false, false, false, false],\n            vec![true,  false, false, false, true, true],\n            vec![true,  false, true,  true,  true,  false],\n            vec![true,  false, true , false, true,  false],\n            vec![true,  true,  true,  false, true,  true],\n        ], Ok(Some(vec![\n            vec![true,  true,  true,  true, false,  false],\n            vec![false, false, false, true, false,  false],\n            vec![true,  true,  true,  true,  false, false],\n            vec![true,  false, false, false, false, false],\n            vec![true,  false, false, false, false, false],\n            vec![true,  false, true,  true,  true,  false],\n            vec![true,  false, true , false, true,  false],\n            vec![true,  true,  true,  false, true,  true],\n        ])),\n    }\n}\n"
  },
  {
    "path": "src/backtracking/subset_sum.rs",
    "content": "//! This module provides functionality to check if there exists a subset of a given set of integers\n//! that sums to a target value. The implementation uses a recursive backtracking approach.\n\n/// Checks if there exists a subset of the given set that sums to the target value.\npub fn has_subset_with_sum(set: &[isize], target: isize) -> bool {\n    backtrack(set, set.len(), target)\n}\n\nfn backtrack(set: &[isize], remaining_items: usize, target: isize) -> bool {\n    // Found a subset with the required sum\n    if target == 0 {\n        return true;\n    }\n    // No more elements to process\n    if remaining_items == 0 {\n        return false;\n    }\n    // Check if we can find a subset including or excluding the last element\n    backtrack(set, remaining_items - 1, target)\n        || backtrack(set, remaining_items - 1, target - set[remaining_items - 1])\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! has_subset_with_sum_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (set, target, expected) = $test_case;\n                    assert_eq!(has_subset_with_sum(set, target), expected);\n                }\n            )*\n        }\n    }\n\n    has_subset_with_sum_tests! {\n        test_small_set_with_sum: (&[3, 34, 4, 12, 5, 2], 9, true),\n        test_small_set_without_sum: (&[3, 34, 4, 12, 5, 2], 30, false),\n        test_consecutive_set_with_sum: (&[1, 2, 3, 4, 5, 6], 10, true),\n        test_consecutive_set_without_sum: (&[1, 2, 3, 4, 5, 6], 22, false),\n        test_large_set_with_sum: (&[5, 10, 12, 13, 15, 18, -1, 10, 50, -2, 3, 4], 30, true),\n        test_empty_set: (&[], 0, true),\n        test_empty_set_with_nonzero_sum: (&[], 10, false),\n        test_single_element_equal_to_sum: (&[10], 10, true),\n        test_single_element_not_equal_to_sum: (&[5], 10, false),\n        test_negative_set_with_sum: (&[-7, -3, -2, 5, 8], 0, true),\n        test_negative_sum: (&[1, 2, 3, 4, 5], -1, false),\n        test_negative_sum_with_negatives: (&[-7, -3, -2, 5, 8], -4, true),\n        test_negative_sum_with_negatives_no_solution: (&[-7, -3, -2, 5, 8], -14, false),\n        test_even_inputs_odd_target: (&[2, 4, 6, 2, 8, -2, 10, 12, -24, 8, 12, 18], 3, false),\n    }\n}\n"
  },
  {
    "path": "src/backtracking/sudoku.rs",
    "content": "//! A Rust implementation of Sudoku solver using Backtracking.\n//!\n//! This module provides functionality to solve Sudoku puzzles using the backtracking algorithm.\n//!\n//! GeeksForGeeks: [Sudoku Backtracking](https://www.geeksforgeeks.org/sudoku-backtracking-7/)\n\n/// Solves a Sudoku puzzle.\n///\n/// Given a partially filled Sudoku puzzle represented by a 9x9 grid, this function attempts to\n/// solve the puzzle using the backtracking algorithm.\n///\n/// Returns the solved Sudoku board if a solution exists, or `None` if no solution is found.\npub fn sudoku_solver(board: &[[u8; 9]; 9]) -> Option<[[u8; 9]; 9]> {\n    let mut solver = SudokuSolver::new(*board);\n    if solver.solve() {\n        Some(solver.board)\n    } else {\n        None\n    }\n}\n\n/// Represents a Sudoku puzzle solver.\nstruct SudokuSolver {\n    /// The Sudoku board represented by a 9x9 grid.\n    board: [[u8; 9]; 9],\n}\n\nimpl SudokuSolver {\n    /// Creates a new Sudoku puzzle solver with the given board.\n    fn new(board: [[u8; 9]; 9]) -> SudokuSolver {\n        SudokuSolver { board }\n    }\n\n    /// Finds an empty cell in the Sudoku board.\n    ///\n    /// Returns the coordinates of an empty cell `(row, column)` if found, or `None` if all cells are filled.\n    fn find_empty_cell(&self) -> Option<(usize, usize)> {\n        // Find an empty cell in the board (returns None if all cells are filled)\n        for row in 0..9 {\n            for column in 0..9 {\n                if self.board[row][column] == 0 {\n                    return Some((row, column));\n                }\n            }\n        }\n\n        None\n    }\n\n    /// Checks whether a given value can be placed in a specific cell according to Sudoku rules.\n    ///\n    /// Returns `true` if the value can be placed in the cell, otherwise `false`.\n    fn is_value_valid(&self, coordinates: (usize, usize), value: u8) -> bool {\n        let (row, column) = coordinates;\n\n        // Checks if the value to be added in the board is an acceptable value for the cell\n        // Checking through the row\n        for current_column in 0..9 {\n            if self.board[row][current_column] == value {\n                return false;\n            }\n        }\n\n        // Checking through the column\n        for current_row in 0..9 {\n            if self.board[current_row][column] == value {\n                return false;\n            }\n        }\n\n        // Checking through the 3x3 block of the cell\n        let start_row = row / 3 * 3;\n        let start_column = column / 3 * 3;\n\n        for current_row in start_row..start_row + 3 {\n            for current_column in start_column..start_column + 3 {\n                if self.board[current_row][current_column] == value {\n                    return false;\n                }\n            }\n        }\n\n        true\n    }\n\n    /// Solves the Sudoku puzzle recursively using backtracking.\n    ///\n    /// Returns `true` if a solution is found, otherwise `false`.\n    fn solve(&mut self) -> bool {\n        let empty_cell = self.find_empty_cell();\n\n        if let Some((row, column)) = empty_cell {\n            for value in 1..=9 {\n                if self.is_value_valid((row, column), value) {\n                    self.board[row][column] = value;\n                    if self.solve() {\n                        return true;\n                    }\n                    // Backtracking if the board cannot be solved using the current configuration\n                    self.board[row][column] = 0;\n                }\n            }\n        } else {\n            // If the board is complete\n            return true;\n        }\n\n        // Returning false if the board cannot be solved using the current configuration\n        false\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_sudoku_solver {\n        ($($name:ident: $board:expr, $expected:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let result = sudoku_solver(&$board);\n                    assert_eq!(result, $expected);\n                }\n            )*\n        };\n    }\n\n    test_sudoku_solver! {\n        test_sudoku_correct: [\n            [3, 0, 6, 5, 0, 8, 4, 0, 0],\n            [5, 2, 0, 0, 0, 0, 0, 0, 0],\n            [0, 8, 7, 0, 0, 0, 0, 3, 1],\n            [0, 0, 3, 0, 1, 0, 0, 8, 0],\n            [9, 0, 0, 8, 6, 3, 0, 0, 5],\n            [0, 5, 0, 0, 9, 0, 6, 0, 0],\n            [1, 3, 0, 0, 0, 0, 2, 5, 0],\n            [0, 0, 0, 0, 0, 0, 0, 7, 4],\n            [0, 0, 5, 2, 0, 6, 3, 0, 0],\n        ], Some([\n            [3, 1, 6, 5, 7, 8, 4, 9, 2],\n            [5, 2, 9, 1, 3, 4, 7, 6, 8],\n            [4, 8, 7, 6, 2, 9, 5, 3, 1],\n            [2, 6, 3, 4, 1, 5, 9, 8, 7],\n            [9, 7, 4, 8, 6, 3, 1, 2, 5],\n            [8, 5, 1, 7, 9, 2, 6, 4, 3],\n            [1, 3, 8, 9, 4, 7, 2, 5, 6],\n            [6, 9, 2, 3, 5, 1, 8, 7, 4],\n            [7, 4, 5, 2, 8, 6, 3, 1, 9],\n        ]),\n\n        test_sudoku_incorrect: [\n            [6, 0, 3, 5, 0, 8, 4, 0, 0],\n            [5, 2, 0, 0, 0, 0, 0, 0, 0],\n            [0, 8, 7, 0, 0, 0, 0, 3, 1],\n            [0, 0, 3, 0, 1, 0, 0, 8, 0],\n            [9, 0, 0, 8, 6, 3, 0, 0, 5],\n            [0, 5, 0, 0, 9, 0, 6, 0, 0],\n            [1, 3, 0, 0, 0, 0, 2, 5, 0],\n            [0, 0, 0, 0, 0, 0, 0, 7, 4],\n            [0, 0, 5, 2, 0, 6, 3, 0, 0],\n        ], None::<[[u8; 9]; 9]>,\n    }\n}\n"
  },
  {
    "path": "src/big_integer/fast_factorial.rs",
    "content": "// Algorithm created by Peter Borwein in 1985\n// https://doi.org/10.1016/0196-6774(85)90006-9\n\nuse crate::math::sieve_of_eratosthenes;\nuse num_bigint::BigUint;\nuse num_traits::One;\nuse std::collections::BTreeMap;\n\n/// Calculate the sum of n / p^i with integer division for all values of i\nfn index(p: usize, n: usize) -> usize {\n    let mut index = 0;\n    let mut i = 1;\n    let mut quot = n / p;\n\n    while quot > 0 {\n        index += quot;\n        i += 1;\n        quot = n / p.pow(i);\n    }\n\n    index\n}\n\n/// Calculate the factorial with time complexity O(log(log(n)) * M(n * log(n))) where M(n) is the time complexity of multiplying two n-digit numbers together.\npub fn fast_factorial(n: usize) -> BigUint {\n    if n < 2 {\n        return BigUint::one();\n    }\n\n    // get list of primes that will be factors of n!\n    let primes = sieve_of_eratosthenes(n);\n\n    // Map the primes with their index\n    let p_indices = primes\n        .into_iter()\n        .map(|p| (p, index(p, n)))\n        .collect::<BTreeMap<_, _>>();\n\n    let max_bits = p_indices[&2].next_power_of_two().ilog2() + 1;\n\n    // Create a Vec of 1's\n    let mut a = vec![BigUint::one(); max_bits as usize];\n\n    // For every prime p, multiply a[i] by p if the ith bit of p's index is 1\n    for (p, i) in p_indices {\n        let mut bit = 1usize;\n        while bit.ilog2() < max_bits {\n            if (bit & i) > 0 {\n                a[bit.ilog2() as usize] *= p;\n            }\n\n            bit <<= 1;\n        }\n    }\n\n    a.into_iter()\n        .enumerate()\n        .map(|(i, a_i)| a_i.pow(2u32.pow(i as u32))) // raise every a[i] to the 2^ith power\n        .product() // we get our answer by multiplying the result\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::math::factorial::factorial_bigmath;\n\n    #[test]\n    fn fact() {\n        assert_eq!(fast_factorial(0), BigUint::one());\n        assert_eq!(fast_factorial(1), BigUint::one());\n        assert_eq!(fast_factorial(2), factorial_bigmath(2));\n        assert_eq!(fast_factorial(3), factorial_bigmath(3));\n        assert_eq!(fast_factorial(6), factorial_bigmath(6));\n        assert_eq!(fast_factorial(7), factorial_bigmath(7));\n        assert_eq!(fast_factorial(10), factorial_bigmath(10));\n        assert_eq!(fast_factorial(11), factorial_bigmath(11));\n        assert_eq!(fast_factorial(18), factorial_bigmath(18));\n        assert_eq!(fast_factorial(19), factorial_bigmath(19));\n        assert_eq!(fast_factorial(30), factorial_bigmath(30));\n        assert_eq!(fast_factorial(34), factorial_bigmath(34));\n        assert_eq!(fast_factorial(35), factorial_bigmath(35));\n        assert_eq!(fast_factorial(52), factorial_bigmath(52));\n        assert_eq!(fast_factorial(100), factorial_bigmath(100));\n        assert_eq!(fast_factorial(1000), factorial_bigmath(1000));\n        assert_eq!(fast_factorial(5000), factorial_bigmath(5000));\n    }\n}\n"
  },
  {
    "path": "src/big_integer/mod.rs",
    "content": "#![cfg(feature = \"big-math\")]\n\nmod fast_factorial;\nmod multiply;\nmod poly1305;\n\npub use self::fast_factorial::fast_factorial;\npub use self::multiply::multiply;\npub use self::poly1305::Poly1305;\n"
  },
  {
    "path": "src/big_integer/multiply.rs",
    "content": "/// Performs long multiplication on string representations of non-negative numbers.\npub fn multiply(num1: &str, num2: &str) -> String {\n    if !is_valid_nonnegative(num1) || !is_valid_nonnegative(num2) {\n        panic!(\"String does not conform to specification\")\n    }\n\n    if num1 == \"0\" || num2 == \"0\" {\n        return \"0\".to_string();\n    }\n    let output_size = num1.len() + num2.len();\n\n    let mut mult = vec![0; output_size];\n    for (i, c1) in num1.chars().rev().enumerate() {\n        for (j, c2) in num2.chars().rev().enumerate() {\n            let mul = c1.to_digit(10).unwrap() * c2.to_digit(10).unwrap();\n            // It could be a two-digit number here.\n            mult[i + j + 1] += (mult[i + j] + mul) / 10;\n            // Handling rounding. Here's a single digit.\n            mult[i + j] = (mult[i + j] + mul) % 10;\n        }\n    }\n    if mult[output_size - 1] == 0 {\n        mult.pop();\n    }\n    mult.iter().rev().map(|&n| n.to_string()).collect()\n}\n\npub fn is_valid_nonnegative(num: &str) -> bool {\n    num.chars().all(char::is_numeric) && !num.is_empty() && (!num.starts_with('0') || num == \"0\")\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    macro_rules! test_multiply {\n        ($($name:ident: $inputs:expr,)*) => {\n        $(\n            #[test]\n            fn $name() {\n                let (s, t, expected) = $inputs;\n                assert_eq!(multiply(s, t), expected);\n                assert_eq!(multiply(t, s), expected);\n            }\n        )*\n        }\n    }\n\n    test_multiply! {\n        multiply0: (\"2\", \"3\", \"6\"),\n        multiply1: (\"123\", \"456\", \"56088\"),\n        multiply_zero: (\"0\", \"222\", \"0\"),\n        other_1: (\"99\", \"99\", \"9801\"),\n        other_2: (\"999\", \"99\", \"98901\"),\n        other_3: (\"9999\", \"99\", \"989901\"),\n        other_4: (\"192939\", \"9499596\", \"1832842552644\"),\n    }\n\n    macro_rules! test_multiply_with_wrong_input {\n        ($($name:ident: $inputs:expr,)*) => {\n        $(\n            #[test]\n            #[should_panic]\n            fn $name() {\n                let (s, t) = $inputs;\n                multiply(s, t);\n            }\n        )*\n        }\n    }\n    test_multiply_with_wrong_input! {\n        empty_input: (\"\", \"121\"),\n        leading_zero: (\"01\", \"3\"),\n        wrong_characters: (\"2\", \"12d4\"),\n        wrong_input_and_zero_1: (\"0\", \"x\"),\n        wrong_input_and_zero_2: (\"y\", \"0\"),\n    }\n}\n"
  },
  {
    "path": "src/big_integer/poly1305.rs",
    "content": "use num_bigint::BigUint;\nuse num_traits::Num;\nuse num_traits::Zero;\n\nmacro_rules! hex_uint {\n    ($a:literal) => {\n        BigUint::from_str_radix($a, 16).unwrap()\n    };\n}\n\n/**\n * Poly1305 Message Authentication Code:\n * This implementation is based on RFC8439.\n * Note that the Big Integer library we are using may not be suitable for\n * cryptographic applications due to non constant time operations.\n*/\npub struct Poly1305 {\n    p: BigUint,\n    r: BigUint,\n    s: BigUint,\n    /// The accumulator\n    pub acc: BigUint,\n}\n\nimpl Default for Poly1305 {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl Poly1305 {\n    pub fn new() -> Self {\n        Poly1305 {\n            p: hex_uint!(\"3fffffffffffffffffffffffffffffffb\"), // 2^130 - 5\n            r: Zero::zero(),\n            s: Zero::zero(),\n            acc: Zero::zero(),\n        }\n    }\n    pub fn clamp_r(&mut self) {\n        self.r &= hex_uint!(\"0ffffffc0ffffffc0ffffffc0fffffff\");\n    }\n    pub fn set_key(&mut self, key: &[u8; 32]) {\n        self.r = BigUint::from_bytes_le(&key[..16]);\n        self.s = BigUint::from_bytes_le(&key[16..]);\n        self.clamp_r();\n    }\n    /// process a 16-byte-long message block. If message is not long enough,\n    /// fill the `msg` array with zeros, but set `msg_bytes` to the original\n    /// chunk length in bytes. See `basic_tv1` for example usage.\n    pub fn add_msg(&mut self, msg: &[u8; 16], msg_bytes: u64) {\n        let mut n = BigUint::from_bytes_le(msg);\n        n.set_bit(msg_bytes * 8, true);\n        self.acc += n;\n        self.acc *= &self.r;\n        self.acc %= &self.p;\n    }\n    /// The result is guaranteed to be 16 bytes long\n    pub fn get_tag(&self) -> Vec<u8> {\n        let result = &self.acc + &self.s;\n        let mut bytes = result.to_bytes_le();\n        bytes.resize(16, 0);\n        bytes\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::fmt::Write;\n    fn get_tag_hex(tag: &[u8]) -> String {\n        let mut result = String::new();\n        for &x in tag {\n            write!(result, \"{x:02x}\").unwrap();\n        }\n        result\n    }\n    #[test]\n    fn basic_tv1() {\n        let mut mac = Poly1305::default();\n        let key: [u8; 32] = [\n            0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33, 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5,\n            0x06, 0xa8, 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd, 0x4a, 0xbf, 0xf6, 0xaf,\n            0x41, 0x49, 0xf5, 0x1b,\n        ];\n        let mut tmp_buffer = [0_u8; 16];\n        mac.set_key(&key);\n        mac.add_msg(b\"Cryptographic Fo\", 16);\n        mac.add_msg(b\"rum Research Gro\", 16);\n        tmp_buffer[..2].copy_from_slice(b\"up\");\n        mac.add_msg(&tmp_buffer, 2);\n        let result = mac.get_tag();\n        assert_eq!(\n            get_tag_hex(result.as_slice()),\n            \"a8061dc1305136c6c22b8baf0c0127a9\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/binary_coded_decimal.rs",
    "content": "//! Binary Coded Decimal (BCD) conversion\n//!\n//! This module provides a function to convert decimal integers to Binary Coded Decimal (BCD) format.\n//! In BCD, each decimal digit is represented by its 4-bit binary equivalent.\n//!\n//! # Examples\n//!\n//! ```\n//! use the_algorithms_rust::bit_manipulation::binary_coded_decimal;\n//!\n//! assert_eq!(binary_coded_decimal(12), \"0b00010010\");\n//! assert_eq!(binary_coded_decimal(987), \"0b100110000111\");\n//! ```\n\nuse std::fmt::Write;\n\n/// Converts a decimal integer to Binary Coded Decimal (BCD) format.\n///\n/// Each digit of the input number is represented by a 4-bit binary value.\n/// Negative numbers are treated as 0.\n///\n/// # Arguments\n///\n/// * `number` - An integer to be converted to BCD format\n///\n/// # Returns\n///\n/// A `String` representing the BCD encoding with \"0b\" prefix\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::binary_coded_decimal;\n///\n/// assert_eq!(binary_coded_decimal(0), \"0b0000\");\n/// assert_eq!(binary_coded_decimal(3), \"0b0011\");\n/// assert_eq!(binary_coded_decimal(12), \"0b00010010\");\n/// assert_eq!(binary_coded_decimal(987), \"0b100110000111\");\n/// assert_eq!(binary_coded_decimal(-5), \"0b0000\");\n/// ```\n///\n/// # Algorithm\n///\n/// 1. Convert the number to its absolute value (negative numbers become 0)\n/// 2. For each decimal digit:\n///    - Convert the digit to binary\n///    - Pad to 4 bits with leading zeros\n///    - Concatenate to the result\n/// 3. Prepend \"0b\" to the final binary string\npub fn binary_coded_decimal(number: i32) -> String {\n    // Handle negative numbers by converting to 0\n    let num = if number < 0 { 0 } else { number };\n\n    // Convert to string to process each digit\n    let digits = num.to_string();\n\n    // Build the BCD string using fold for efficiency\n    let bcd = digits.chars().fold(String::new(), |mut acc, digit| {\n        // Convert char to digit value and format as 4-bit binary\n        let digit_value = digit.to_digit(10).unwrap();\n        write!(acc, \"{digit_value:04b}\").unwrap();\n        acc\n    });\n\n    format!(\"0b{bcd}\")\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_zero() {\n        assert_eq!(binary_coded_decimal(0), \"0b0000\");\n    }\n\n    #[test]\n    fn test_single_digit() {\n        assert_eq!(binary_coded_decimal(1), \"0b0001\");\n        assert_eq!(binary_coded_decimal(2), \"0b0010\");\n        assert_eq!(binary_coded_decimal(3), \"0b0011\");\n        assert_eq!(binary_coded_decimal(4), \"0b0100\");\n        assert_eq!(binary_coded_decimal(5), \"0b0101\");\n        assert_eq!(binary_coded_decimal(6), \"0b0110\");\n        assert_eq!(binary_coded_decimal(7), \"0b0111\");\n        assert_eq!(binary_coded_decimal(8), \"0b1000\");\n        assert_eq!(binary_coded_decimal(9), \"0b1001\");\n    }\n\n    #[test]\n    fn test_two_digits() {\n        assert_eq!(binary_coded_decimal(10), \"0b00010000\");\n        assert_eq!(binary_coded_decimal(12), \"0b00010010\");\n        assert_eq!(binary_coded_decimal(25), \"0b00100101\");\n        assert_eq!(binary_coded_decimal(99), \"0b10011001\");\n    }\n\n    #[test]\n    fn test_three_digits() {\n        assert_eq!(binary_coded_decimal(100), \"0b000100000000\");\n        assert_eq!(binary_coded_decimal(123), \"0b000100100011\");\n        assert_eq!(binary_coded_decimal(456), \"0b010001010110\");\n        assert_eq!(binary_coded_decimal(987), \"0b100110000111\");\n    }\n\n    #[test]\n    fn test_large_numbers() {\n        assert_eq!(binary_coded_decimal(1234), \"0b0001001000110100\");\n        assert_eq!(binary_coded_decimal(9999), \"0b1001100110011001\");\n    }\n\n    #[test]\n    fn test_negative_numbers() {\n        // Negative numbers should be treated as 0\n        assert_eq!(binary_coded_decimal(-1), \"0b0000\");\n        assert_eq!(binary_coded_decimal(-2), \"0b0000\");\n        assert_eq!(binary_coded_decimal(-100), \"0b0000\");\n    }\n\n    #[test]\n    fn test_each_digit_encoding() {\n        // Verify that each digit is encoded correctly in a multi-digit number\n        // 67 should be: 6 (0110) and 7 (0111)\n        assert_eq!(binary_coded_decimal(67), \"0b01100111\");\n\n        // 305 should be: 3 (0011), 0 (0000), 5 (0101)\n        assert_eq!(binary_coded_decimal(305), \"0b001100000101\");\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/binary_count_trailing_zeros.rs",
    "content": "/// Counts the number of trailing zeros in the binary representation of a number\n///\n/// # Arguments\n///\n/// * `num` - The input number\n///\n/// # Returns\n///\n/// The number of trailing zeros in the binary representation\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::binary_count_trailing_zeros;\n///\n/// assert_eq!(binary_count_trailing_zeros(25), 0);\n/// assert_eq!(binary_count_trailing_zeros(36), 2);\n/// assert_eq!(binary_count_trailing_zeros(16), 4);\n/// assert_eq!(binary_count_trailing_zeros(58), 1);\n/// ```\npub fn binary_count_trailing_zeros(num: u64) -> u32 {\n    if num == 0 {\n        return 0;\n    }\n    num.trailing_zeros()\n}\n\n/// Alternative implementation using bit manipulation\n///\n/// Uses the bit manipulation trick: log2(num & -num)\n///\n/// # Examples\n///\n/// ```\n/// // This function uses bit manipulation: log2(num & -num)\n/// // where num & -num isolates the rightmost set bit\n/// # fn binary_count_trailing_zeros_bitwise(num: u64) -> u32 {\n/// #     if num == 0 { return 0; }\n/// #     let rightmost_set_bit = num & (num.wrapping_neg());\n/// #     63 - rightmost_set_bit.leading_zeros()\n/// # }\n/// assert_eq!(binary_count_trailing_zeros_bitwise(25), 0);\n/// assert_eq!(binary_count_trailing_zeros_bitwise(36), 2);\n/// assert_eq!(binary_count_trailing_zeros_bitwise(16), 4);\n/// ```\n#[allow(dead_code)]\npub fn binary_count_trailing_zeros_bitwise(num: u64) -> u32 {\n    if num == 0 {\n        return 0;\n    }\n\n    let rightmost_set_bit = num & (num.wrapping_neg());\n    63 - rightmost_set_bit.leading_zeros()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_basic_cases() {\n        assert_eq!(binary_count_trailing_zeros(25), 0);\n        assert_eq!(binary_count_trailing_zeros(36), 2);\n        assert_eq!(binary_count_trailing_zeros(16), 4);\n        assert_eq!(binary_count_trailing_zeros(58), 1);\n        assert_eq!(binary_count_trailing_zeros(4294967296), 32);\n    }\n\n    #[test]\n    fn test_zero() {\n        assert_eq!(binary_count_trailing_zeros(0), 0);\n    }\n\n    #[test]\n    fn test_powers_of_two() {\n        assert_eq!(binary_count_trailing_zeros(1), 0);\n        assert_eq!(binary_count_trailing_zeros(2), 1);\n        assert_eq!(binary_count_trailing_zeros(4), 2);\n        assert_eq!(binary_count_trailing_zeros(8), 3);\n        assert_eq!(binary_count_trailing_zeros(1024), 10);\n    }\n\n    #[test]\n    fn test_bitwise_vs_builtin() {\n        // Test that bitwise implementation matches built-in trailing_zeros()\n        let test_cases = vec![\n            0,\n            1,\n            2,\n            3,\n            4,\n            5,\n            6,\n            7,\n            8,\n            16,\n            25,\n            36,\n            58,\n            64,\n            100,\n            128,\n            256,\n            512,\n            1024,\n            4294967296,\n            u64::MAX - 1,\n            u64::MAX,\n        ];\n\n        for num in test_cases {\n            assert_eq!(\n                binary_count_trailing_zeros(num),\n                binary_count_trailing_zeros_bitwise(num),\n                \"Mismatch for input: {num}\"\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/binary_shifts.rs",
    "content": "//! Binary Shift Operations\n//!\n//! This module provides implementations of various binary shift operations with\n//! binary string output for visualization.\n//!\n//! # Shift Types\n//!\n//! - **Logical Left Shift**: Shifts bits left, filling with zeros on the right\n//! - **Logical Right Shift**: Shifts bits right, filling with zeros on the left\n//! - **Arithmetic Left Shift**: Same as logical left shift (included for completeness)\n//! - **Arithmetic Right Shift**: Shifts bits right, preserving the sign bit\n//!\n//! # Note on Arithmetic vs Logical Left Shifts\n//!\n//! In most systems, arithmetic left shift and logical left shift are identical operations.\n//! Both shift bits to the left and fill with zeros on the right. The distinction between\n//! arithmetic and logical shifts only matters for right shifts, where arithmetic shifts\n//! preserve the sign bit.\n//!\n//! # References\n//!\n//! - [Bitwise Operations - Python Docs](https://docs.python.org/3/library/stdtypes.html#bitwise-operations-on-integer-types)\n//! - [Bit Shift - Interview Cake](https://www.interviewcake.com/concept/java/bit-shift)\n\n/// Performs a logical left shift on a number and returns the binary representation.\n///\n/// Shifts the bits of `number` to the left by `shift_amount` positions,\n/// filling the rightmost bits with zeros.\n///\n/// # Arguments\n///\n/// * `number` - The non-negative integer to be shifted\n/// * `shift_amount` - The number of positions to shift (must be non-negative)\n///\n/// # Returns\n///\n/// `Ok(String)` with the binary representation (including \"0b\" prefix),\n/// or `Err(String)` if either input is negative\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::logical_left_shift;\n///\n/// assert_eq!(logical_left_shift(0, 1).unwrap(), \"0b00\");\n/// assert_eq!(logical_left_shift(1, 1).unwrap(), \"0b10\");\n/// assert_eq!(logical_left_shift(1, 5).unwrap(), \"0b100000\");\n/// assert_eq!(logical_left_shift(17, 2).unwrap(), \"0b1000100\");\n/// assert_eq!(logical_left_shift(1983, 4).unwrap(), \"0b111101111110000\");\n///\n/// // Negative inputs return error\n/// assert!(logical_left_shift(1, -1).is_err());\n/// ```\npub fn logical_left_shift(number: i32, shift_amount: i32) -> Result<String, String> {\n    if number < 0 || shift_amount < 0 {\n        return Err(\"both inputs must be positive integers\".to_string());\n    }\n\n    // Get binary representation and append zeros\n    let binary = format!(\"{number:b}\");\n    let zeros = \"0\".repeat(shift_amount as usize);\n    Ok(format!(\"0b{binary}{zeros}\"))\n}\n\n/// Performs a logical right shift on a number and returns the binary representation.\n///\n/// Shifts the bits of `number` to the right by `shift_amount` positions,\n/// filling the leftmost bits with zeros. This is an unsigned shift operation.\n///\n/// # Arguments\n///\n/// * `number` - The non-negative integer to be shifted\n/// * `shift_amount` - The number of positions to shift (must be non-negative)\n///\n/// # Returns\n///\n/// `Ok(String)` with the binary representation (including \"0b\" prefix),\n/// or `Err(String)` if either input is negative\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::logical_right_shift;\n///\n/// assert_eq!(logical_right_shift(0, 1).unwrap(), \"0b0\");\n/// assert_eq!(logical_right_shift(1, 1).unwrap(), \"0b0\");\n/// assert_eq!(logical_right_shift(1, 5).unwrap(), \"0b0\");\n/// assert_eq!(logical_right_shift(17, 2).unwrap(), \"0b100\");\n/// assert_eq!(logical_right_shift(1983, 4).unwrap(), \"0b1111011\");\n///\n/// // Negative inputs return error\n/// assert!(logical_right_shift(1, -1).is_err());\n/// ```\npub fn logical_right_shift(number: i32, shift_amount: i32) -> Result<String, String> {\n    if number < 0 || shift_amount < 0 {\n        return Err(\"both inputs must be positive integers\".to_string());\n    }\n\n    let shifted = (number as u32) >> shift_amount;\n    Ok(format!(\"0b{shifted:b}\"))\n}\n\n/// Performs an arithmetic right shift on a number and returns the binary representation.\n///\n/// Shifts the bits of `number` to the right by `shift_amount` positions,\n/// preserving the sign bit. For positive numbers, fills with 0s; for negative\n/// numbers, fills with 1s (sign extension).\n///\n/// # Arguments\n///\n/// * `number` - The integer to be shifted (can be negative)\n/// * `shift_amount` - The number of positions to shift (must be non-negative)\n///\n/// # Returns\n///\n/// `Ok(String)` with the binary representation including sign bit (with \"0b\" prefix),\n/// or `Err(String)` if shift_amount is negative\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::arithmetic_right_shift;\n///\n/// assert_eq!(arithmetic_right_shift(0, 1).unwrap(), \"0b00\");\n/// assert_eq!(arithmetic_right_shift(1, 1).unwrap(), \"0b00\");\n/// assert_eq!(arithmetic_right_shift(-1, 1).unwrap(), \"0b11\");\n/// assert_eq!(arithmetic_right_shift(17, 2).unwrap(), \"0b000100\");\n/// assert_eq!(arithmetic_right_shift(-17, 2).unwrap(), \"0b111011\");\n/// assert_eq!(arithmetic_right_shift(-1983, 4).unwrap(), \"0b111110000100\");\n/// ```\npub fn arithmetic_right_shift(number: i32, shift_amount: i32) -> Result<String, String> {\n    if shift_amount < 0 {\n        return Err(\"shift amount must be a positive integer\".to_string());\n    }\n\n    let shift_amount_usize = shift_amount as usize;\n\n    let binary_number = if number >= 0 {\n        // Python: binary_number = \"0\" + str(bin(number)).strip(\"-\")[2:]\n        let bin_str = format!(\"{number:b}\");\n        format!(\"0{bin_str}\")\n    } else {\n        // Python: binary_number_length = len(bin(number)[3:])\n        // bin(-17) = \"-0b10001\", [3:] = \"10001\", length = 5\n        let abs_bin = format!(\"{:b}\", number.abs());\n        let binary_number_length = abs_bin.len();\n\n        // Python: binary_number = bin(abs(number) - (1 << binary_number_length))[3:]\n        let abs_num = number.abs();\n        let subtracted = abs_num - (1 << binary_number_length);\n\n        // bin() of negative number is \"-0b...\" so [3:] skips \"-0b\"\n        let bin_result = if subtracted < 0 {\n            // For negative result, we need its absolute value binary representation\n            // In Python, bin(-15) = \"-0b1111\", and [3:] = \"1111\"\n            format!(\"{:b}\", subtracted.abs())\n        } else {\n            format!(\"{subtracted:b}\")\n        };\n\n        // Python: binary_number = \"1\" + \"0\" * (binary_number_length - len(binary_number)) + binary_number\n        let padding = if binary_number_length > bin_result.len() {\n            \"0\".repeat(binary_number_length - bin_result.len())\n        } else {\n            String::new()\n        };\n\n        format!(\"1{padding}{bin_result}\")\n    };\n\n    // Python: if shift_amount >= len(binary_number):\n    //             return \"0b\" + binary_number[0] * len(binary_number)\n    if shift_amount_usize >= binary_number.len() {\n        let sign_char = binary_number.chars().next().unwrap();\n        return Ok(format!(\n            \"0b{}\",\n            sign_char.to_string().repeat(binary_number.len())\n        ));\n    }\n\n    // Python: return (\"0b\" + binary_number[0] * shift_amount +\n    //                 binary_number[: len(binary_number) - shift_amount])\n    let sign_char = binary_number.chars().next().unwrap();\n    let end_idx = binary_number.len() - shift_amount_usize;\n    let slice = &binary_number[..end_idx];\n\n    Ok(format!(\n        \"0b{}{}\",\n        sign_char.to_string().repeat(shift_amount_usize),\n        slice\n    ))\n}\n\n/// Performs an arithmetic left shift on a number and returns the binary representation.\n///\n/// **Note**: Arithmetic left shift is identical to logical left shift - both shift bits\n/// to the left and fill with zeros on the right. This function is provided for\n/// completeness and educational purposes. The distinction between arithmetic and logical\n/// shifts only matters for right shifts (sign preservation).\n///\n/// # Arguments\n///\n/// * `number` - The integer to be shifted (can be negative)\n/// * `shift_amount` - The number of positions to shift (must be non-negative)\n///\n/// # Returns\n///\n/// `Ok(String)` with the binary representation (with \"0b\" prefix),\n/// or `Err(String)` if shift_amount is negative\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::arithmetic_left_shift;\n///\n/// assert_eq!(arithmetic_left_shift(1, 5).unwrap(), \"0b100000\");\n/// assert_eq!(arithmetic_left_shift(17, 2).unwrap(), \"0b1000100\");\n/// assert_eq!(arithmetic_left_shift(-1, 2).unwrap(), \"0b11111111111111111111111111111100\");\n/// ```\npub fn arithmetic_left_shift(number: i32, shift_amount: i32) -> Result<String, String> {\n    if shift_amount < 0 {\n        return Err(\"shift amount must be a positive integer\".to_string());\n    }\n\n    // Arithmetic left shift is the same as logical left shift\n    // Both shift left and fill with zeros\n    let shifted = (number << shift_amount) as u32;\n    let binary = format!(\"{shifted:b}\");\n    Ok(format!(\"0b{binary}\"))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    // Logical Left Shift Tests\n    #[test]\n    fn test_logical_left_shift_zero() {\n        assert_eq!(logical_left_shift(0, 1).unwrap(), \"0b00\");\n    }\n\n    #[test]\n    fn test_logical_left_shift_one() {\n        assert_eq!(logical_left_shift(1, 1).unwrap(), \"0b10\");\n    }\n\n    #[test]\n    fn test_logical_left_shift_large_shift() {\n        assert_eq!(logical_left_shift(1, 5).unwrap(), \"0b100000\");\n    }\n\n    #[test]\n    fn test_logical_left_shift_seventeen() {\n        assert_eq!(logical_left_shift(17, 2).unwrap(), \"0b1000100\");\n    }\n\n    #[test]\n    fn test_logical_left_shift_large_number() {\n        assert_eq!(logical_left_shift(1983, 4).unwrap(), \"0b111101111110000\");\n    }\n\n    #[test]\n    fn test_logical_left_shift_negative_number() {\n        assert!(logical_left_shift(-1, 1).is_err());\n    }\n\n    #[test]\n    fn test_logical_left_shift_negative_shift() {\n        assert!(logical_left_shift(1, -1).is_err());\n    }\n\n    #[test]\n    fn test_logical_left_shift_both_negative() {\n        assert!(logical_left_shift(-1, -1).is_err());\n    }\n\n    // Logical Right Shift Tests\n    #[test]\n    fn test_logical_right_shift_zero() {\n        assert_eq!(logical_right_shift(0, 1).unwrap(), \"0b0\");\n    }\n\n    #[test]\n    fn test_logical_right_shift_one() {\n        assert_eq!(logical_right_shift(1, 1).unwrap(), \"0b0\");\n    }\n\n    #[test]\n    fn test_logical_right_shift_shift_all_bits() {\n        assert_eq!(logical_right_shift(1, 5).unwrap(), \"0b0\");\n    }\n\n    #[test]\n    fn test_logical_right_shift_seventeen() {\n        assert_eq!(logical_right_shift(17, 2).unwrap(), \"0b100\");\n    }\n\n    #[test]\n    fn test_logical_right_shift_large_number() {\n        assert_eq!(logical_right_shift(1983, 4).unwrap(), \"0b1111011\");\n    }\n\n    #[test]\n    fn test_logical_right_shift_negative_number() {\n        assert!(logical_right_shift(-1, 1).is_err());\n    }\n\n    #[test]\n    fn test_logical_right_shift_negative_shift() {\n        assert!(logical_right_shift(1, -1).is_err());\n    }\n\n    #[test]\n    fn test_logical_right_shift_both_negative() {\n        assert!(logical_right_shift(-1, -1).is_err());\n    }\n\n    // Arithmetic Right Shift Tests\n    #[test]\n    fn test_arithmetic_right_shift_zero() {\n        assert_eq!(arithmetic_right_shift(0, 1).unwrap(), \"0b00\");\n    }\n\n    #[test]\n    fn test_arithmetic_right_shift_one() {\n        assert_eq!(arithmetic_right_shift(1, 1).unwrap(), \"0b00\");\n    }\n\n    #[test]\n    fn test_arithmetic_right_shift_negative_one() {\n        assert_eq!(arithmetic_right_shift(-1, 1).unwrap(), \"0b11\");\n    }\n\n    #[test]\n    fn test_arithmetic_right_shift_seventeen_positive() {\n        assert_eq!(arithmetic_right_shift(17, 2).unwrap(), \"0b000100\");\n    }\n\n    #[test]\n    fn test_arithmetic_right_shift_seventeen_negative() {\n        assert_eq!(arithmetic_right_shift(-17, 2).unwrap(), \"0b111011\");\n    }\n\n    #[test]\n    fn test_arithmetic_right_shift_large_negative() {\n        assert_eq!(arithmetic_right_shift(-1983, 4).unwrap(), \"0b111110000100\");\n    }\n\n    #[test]\n    fn test_arithmetic_right_shift_negative_shift() {\n        assert!(arithmetic_right_shift(1, -1).is_err());\n    }\n\n    #[test]\n    fn test_arithmetic_right_shift_preserves_sign_positive() {\n        // Positive number should have leading 0\n        // 16 = 0b10000, with sign bit = 0b010000, shift right by 2 = 0b000100\n        let result = arithmetic_right_shift(16, 2).unwrap();\n        assert!(result.starts_with(\"0b0\"));\n        assert_eq!(result, \"0b000100\");\n    }\n\n    #[test]\n    fn test_arithmetic_right_shift_preserves_sign_negative() {\n        // Negative number should have leading 1\n        let result = arithmetic_right_shift(-16, 2).unwrap();\n        assert!(result.starts_with(\"0b1\"));\n    }\n\n    #[test]\n    fn test_arithmetic_right_shift_large_shift_positive() {\n        // Shifting positive number by large amount\n        // 1 = 0b1, with sign bit = 0b01 (2 bits)\n        // Shift by 10 (>= 2), so return sign bit repeated 2 times = 0b00\n        assert_eq!(arithmetic_right_shift(1, 10).unwrap(), \"0b00\");\n    }\n\n    #[test]\n    fn test_arithmetic_right_shift_large_shift_negative() {\n        // Shifting negative number by large amount should preserve sign\n        // -1 has all 1s, minimal representation with sign bit\n        let result = arithmetic_right_shift(-1, 10).unwrap();\n        assert!(result.starts_with(\"0b1\"));\n        // All bits should be 1s (sign extended)\n        assert!(result.chars().skip(2).all(|c| c == '1'));\n    }\n\n    // Arithmetic Left Shift Tests\n    #[test]\n    fn test_arithmetic_left_shift_basic() {\n        assert_eq!(arithmetic_left_shift(1, 5).unwrap(), \"0b100000\");\n        assert_eq!(arithmetic_left_shift(17, 2).unwrap(), \"0b1000100\");\n    }\n\n    #[test]\n    fn test_arithmetic_left_shift_negative() {\n        // Negative numbers in arithmetic left shift\n        // -1 << 2 in two's complement\n        let result = arithmetic_left_shift(-1, 2).unwrap();\n        assert!(result.starts_with(\"0b\"));\n        // Should contain all 1s followed by 00\n        assert!(result.ends_with(\"00\"));\n    }\n\n    #[test]\n    fn test_arithmetic_left_shift_zero() {\n        assert_eq!(arithmetic_left_shift(0, 3).unwrap(), \"0b0\");\n    }\n\n    #[test]\n    fn test_arithmetic_left_shift_negative_shift() {\n        assert!(arithmetic_left_shift(1, -1).is_err());\n    }\n\n    #[test]\n    fn test_arithmetic_left_shift_same_as_logical() {\n        // For positive numbers, arithmetic and logical left shifts are identical\n        let num = 17;\n        let shift = 3;\n        let arithmetic = arithmetic_left_shift(num, shift).unwrap();\n        let logical = logical_left_shift(num, shift).unwrap();\n\n        // Parse the binary strings and compare the values\n        let arith_val = u32::from_str_radix(&arithmetic[2..], 2).unwrap();\n        let logic_val = u32::from_str_radix(&logical[2..], 2).unwrap();\n        assert_eq!(arith_val, logic_val);\n    }\n\n    #[test]\n    fn test_all_shifts_on_same_value() {\n        let number = 8;\n        let shift = 2;\n\n        // 8 (0b1000) << 2 = 32 (0b100000)\n        assert_eq!(logical_left_shift(number, shift).unwrap(), \"0b100000\");\n        assert_eq!(arithmetic_left_shift(number, shift).unwrap(), \"0b100000\");\n\n        // 8 (0b1000) >> 2 = 2 (0b10)\n        assert_eq!(logical_right_shift(number, shift).unwrap(), \"0b10\");\n\n        // 8 (0b1000) >> 2 = 2 (0b010)\n        assert_eq!(arithmetic_right_shift(number, shift).unwrap(), \"0b00010\");\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/counting_bits.rs",
    "content": "//! This module implements a function to count the number of set bits (1s)\n//! in the binary representation of an unsigned integer.\n//! It uses Brian Kernighan's algorithm, which efficiently clears the least significant\n//! set bit in each iteration until all bits are cleared.\n//! The algorithm runs in O(k), where k is the number of set bits.\n\n/// Counts the number of set bits in an unsigned integer.\n///\n/// # Arguments\n///\n/// * `n` - An unsigned 32-bit integer whose set bits will be counted.\n///\n/// # Returns\n///\n/// * `usize` - The number of set bits (1s) in the binary representation of the input number.\npub fn count_set_bits(mut n: usize) -> usize {\n    // Initialize a variable to keep track of the count of set bits\n    let mut count = 0;\n    while n > 0 {\n        // Clear the least significant set bit by\n        // performing a bitwise AND operation with (n - 1)\n        n &= n - 1;\n\n        // Increment the count for each set bit found\n        count += 1;\n    }\n\n    count\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_count_set_bits {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $test_case;\n                    assert_eq!(count_set_bits(input), expected);\n                }\n            )*\n        };\n    }\n    test_count_set_bits! {\n        test_count_set_bits_zero: (0, 0),\n        test_count_set_bits_one: (1, 1),\n        test_count_set_bits_power_of_two: (16, 1),\n        test_count_set_bits_all_set_bits: (usize::MAX, std::mem::size_of::<usize>() * 8),\n        test_count_set_bits_alternating_bits: (0b10101010, 4),\n        test_count_set_bits_mixed_bits: (0b11011011, 6),\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/find_missing_number.rs",
    "content": "/// Finds the missing number in a slice of consecutive integers.\n///\n/// This function uses XOR bitwise operation to find the missing number.\n/// It XORs all expected numbers in the range [min, max] with the actual\n/// numbers present in the array. Since XOR has the property that `a ^ a = 0`,\n/// all present numbers cancel out, leaving only the missing number.\n///\n/// # Arguments\n///\n/// * `nums` - A slice of integers forming a sequence with one missing number\n///\n/// # Returns\n///\n/// * `Ok(i32)` - The missing number in the sequence\n/// * `Err(String)` - An error message if the input is invalid\n///\n/// # Examples\n///\n/// ```\n/// # use the_algorithms_rust::bit_manipulation::find_missing_number;\n/// assert_eq!(find_missing_number(&[0, 1, 3, 4]).unwrap(), 2);\n/// assert_eq!(find_missing_number(&[4, 3, 1, 0]).unwrap(), 2);\n/// assert_eq!(find_missing_number(&[-4, -3, -1, 0]).unwrap(), -2);\n/// assert_eq!(find_missing_number(&[-2, 2, 1, 3, 0]).unwrap(), -1);\n/// assert_eq!(find_missing_number(&[1, 3, 4, 5, 6]).unwrap(), 2);\n/// ```\npub fn find_missing_number(nums: &[i32]) -> Result<i32, String> {\n    if nums.is_empty() {\n        return Err(\"input array must not be empty\".to_string());\n    }\n\n    if nums.len() == 1 {\n        return Err(\"array must have at least 2 elements to find a missing number\".to_string());\n    }\n\n    let low = *nums.iter().min().unwrap();\n    let high = *nums.iter().max().unwrap();\n\n    let mut missing_number = high;\n\n    for i in low..high {\n        let index = (i - low) as usize;\n        missing_number ^= i ^ nums[index];\n    }\n\n    Ok(missing_number)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_missing_in_middle() {\n        assert_eq!(find_missing_number(&[0, 1, 3, 4]).unwrap(), 2);\n    }\n\n    #[test]\n    fn test_unordered_array() {\n        assert_eq!(find_missing_number(&[4, 3, 1, 0]).unwrap(), 2);\n    }\n\n    #[test]\n    fn test_negative_numbers() {\n        assert_eq!(find_missing_number(&[-4, -3, -1, 0]).unwrap(), -2);\n    }\n\n    #[test]\n    fn test_negative_and_positive() {\n        assert_eq!(find_missing_number(&[-2, 2, 1, 3, 0]).unwrap(), -1);\n    }\n\n    #[test]\n    fn test_missing_at_start() {\n        assert_eq!(find_missing_number(&[1, 3, 4, 5, 6]).unwrap(), 2);\n    }\n\n    #[test]\n    fn test_unordered_missing_middle() {\n        assert_eq!(find_missing_number(&[6, 5, 4, 2, 1]).unwrap(), 3);\n    }\n\n    #[test]\n    fn test_another_unordered() {\n        assert_eq!(find_missing_number(&[6, 1, 5, 3, 4]).unwrap(), 2);\n    }\n\n    #[test]\n    fn test_empty_array() {\n        assert!(find_missing_number(&[]).is_err());\n        assert_eq!(\n            find_missing_number(&[]).unwrap_err(),\n            \"input array must not be empty\"\n        );\n    }\n\n    #[test]\n    fn test_single_element() {\n        assert!(find_missing_number(&[5]).is_err());\n        assert_eq!(\n            find_missing_number(&[5]).unwrap_err(),\n            \"array must have at least 2 elements to find a missing number\"\n        );\n    }\n\n    #[test]\n    fn test_two_elements() {\n        assert_eq!(find_missing_number(&[0, 2]).unwrap(), 1);\n        assert_eq!(find_missing_number(&[2, 0]).unwrap(), 1);\n    }\n\n    #[test]\n    fn test_large_range() {\n        assert_eq!(find_missing_number(&[100, 101, 103, 104]).unwrap(), 102);\n    }\n\n    #[test]\n    fn test_missing_at_boundaries() {\n        // Missing is the second to last element\n        assert_eq!(find_missing_number(&[1, 2, 3, 5]).unwrap(), 4);\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/find_previous_power_of_two.rs",
    "content": "//! Previous Power of Two\n//!\n//! This module provides a function to find the largest power of two that is less than\n//! or equal to a given non-negative integer.\n//!\n//! # Algorithm\n//!\n//! The algorithm works by repeatedly left-shifting (doubling) a power value starting\n//! from 1 until it exceeds the input number, then returning the previous power (by\n//! right-shifting once).\n//!\n//! For more information: <https://stackoverflow.com/questions/1322510>\n\n/// Finds the largest power of two that is less than or equal to a given integer.\n///\n/// The function uses bit shifting to efficiently find the power of two. It starts\n/// with 1 and keeps doubling (left shift) until it exceeds the input, then returns\n/// the previous value (right shift).\n///\n/// # Arguments\n///\n/// * `number` - A non-negative integer\n///\n/// # Returns\n///\n/// A `Result` containing:\n/// - `Ok(u32)` - The largest power of two ≤ the input number\n/// - `Err(String)` - An error message if the input is negative\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::find_previous_power_of_two;\n///\n/// assert_eq!(find_previous_power_of_two(0).unwrap(), 0);\n/// assert_eq!(find_previous_power_of_two(1).unwrap(), 1);\n/// assert_eq!(find_previous_power_of_two(2).unwrap(), 2);\n/// assert_eq!(find_previous_power_of_two(3).unwrap(), 2);\n/// assert_eq!(find_previous_power_of_two(4).unwrap(), 4);\n/// assert_eq!(find_previous_power_of_two(5).unwrap(), 4);\n/// assert_eq!(find_previous_power_of_two(8).unwrap(), 8);\n/// assert_eq!(find_previous_power_of_two(15).unwrap(), 8);\n/// assert_eq!(find_previous_power_of_two(16).unwrap(), 16);\n/// assert_eq!(find_previous_power_of_two(17).unwrap(), 16);\n///\n/// // Negative numbers return an error\n/// assert!(find_previous_power_of_two(-5).is_err());\n/// ```\n///\n/// # Errors\n///\n/// Returns an error if the input number is negative.\npub fn find_previous_power_of_two(number: i32) -> Result<u32, String> {\n    if number < 0 {\n        return Err(\"Input must be a non-negative integer\".to_string());\n    }\n\n    let number = number as u32;\n\n    if number == 0 {\n        return Ok(0);\n    }\n\n    let mut power = 1u32;\n    while power <= number {\n        power <<= 1; // Equivalent to multiplying by 2\n    }\n\n    Ok(if number > 1 { power >> 1 } else { 1 })\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_zero() {\n        assert_eq!(find_previous_power_of_two(0).unwrap(), 0);\n    }\n\n    #[test]\n    fn test_one() {\n        assert_eq!(find_previous_power_of_two(1).unwrap(), 1);\n    }\n\n    #[test]\n    fn test_powers_of_two() {\n        assert_eq!(find_previous_power_of_two(2).unwrap(), 2);\n        assert_eq!(find_previous_power_of_two(4).unwrap(), 4);\n        assert_eq!(find_previous_power_of_two(8).unwrap(), 8);\n        assert_eq!(find_previous_power_of_two(16).unwrap(), 16);\n        assert_eq!(find_previous_power_of_two(32).unwrap(), 32);\n        assert_eq!(find_previous_power_of_two(64).unwrap(), 64);\n        assert_eq!(find_previous_power_of_two(128).unwrap(), 128);\n        assert_eq!(find_previous_power_of_two(256).unwrap(), 256);\n        assert_eq!(find_previous_power_of_two(512).unwrap(), 512);\n        assert_eq!(find_previous_power_of_two(1024).unwrap(), 1024);\n    }\n\n    #[test]\n    fn test_numbers_between_powers() {\n        // Between 2 and 4\n        assert_eq!(find_previous_power_of_two(3).unwrap(), 2);\n\n        // Between 4 and 8\n        assert_eq!(find_previous_power_of_two(5).unwrap(), 4);\n        assert_eq!(find_previous_power_of_two(6).unwrap(), 4);\n        assert_eq!(find_previous_power_of_two(7).unwrap(), 4);\n\n        // Between 8 and 16\n        assert_eq!(find_previous_power_of_two(9).unwrap(), 8);\n        assert_eq!(find_previous_power_of_two(10).unwrap(), 8);\n        assert_eq!(find_previous_power_of_two(11).unwrap(), 8);\n        assert_eq!(find_previous_power_of_two(12).unwrap(), 8);\n        assert_eq!(find_previous_power_of_two(13).unwrap(), 8);\n        assert_eq!(find_previous_power_of_two(14).unwrap(), 8);\n        assert_eq!(find_previous_power_of_two(15).unwrap(), 8);\n\n        // Between 16 and 32\n        assert_eq!(find_previous_power_of_two(17).unwrap(), 16);\n        assert_eq!(find_previous_power_of_two(20).unwrap(), 16);\n        assert_eq!(find_previous_power_of_two(31).unwrap(), 16);\n    }\n\n    #[test]\n    fn test_range_0_to_17() {\n        // Test the exact output from the Python docstring\n        let expected = vec![0, 1, 2, 2, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16];\n        let results: Vec<u32> = (0..18)\n            .map(|i| find_previous_power_of_two(i).unwrap())\n            .collect();\n        assert_eq!(results, expected);\n    }\n\n    #[test]\n    fn test_large_numbers() {\n        assert_eq!(find_previous_power_of_two(100).unwrap(), 64);\n        assert_eq!(find_previous_power_of_two(500).unwrap(), 256);\n        assert_eq!(find_previous_power_of_two(1000).unwrap(), 512);\n        assert_eq!(find_previous_power_of_two(2000).unwrap(), 1024);\n        assert_eq!(find_previous_power_of_two(10000).unwrap(), 8192);\n    }\n\n    #[test]\n    fn test_max_safe_values() {\n        assert_eq!(find_previous_power_of_two(1023).unwrap(), 512);\n        assert_eq!(find_previous_power_of_two(2047).unwrap(), 1024);\n        assert_eq!(find_previous_power_of_two(4095).unwrap(), 2048);\n    }\n\n    #[test]\n    fn test_negative_number_returns_error() {\n        let result = find_previous_power_of_two(-1);\n        assert!(result.is_err());\n        assert_eq!(result.unwrap_err(), \"Input must be a non-negative integer\");\n    }\n\n    #[test]\n    fn test_negative_numbers_return_errors() {\n        assert!(find_previous_power_of_two(-5).is_err());\n        assert!(find_previous_power_of_two(-10).is_err());\n        assert!(find_previous_power_of_two(-100).is_err());\n    }\n\n    #[test]\n    fn test_edge_cases() {\n        // One less than powers of two\n        assert_eq!(find_previous_power_of_two(127).unwrap(), 64);\n        assert_eq!(find_previous_power_of_two(255).unwrap(), 128);\n        assert_eq!(find_previous_power_of_two(511).unwrap(), 256);\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/find_unique_number.rs",
    "content": "/// Finds the unique number in a slice where every other element appears twice.\n///\n/// This function uses the XOR bitwise operation. Since XOR has the property that\n/// `a ^ a = 0` and `a ^ 0 = a`, all paired numbers cancel out, leaving only the\n/// unique number.\n///\n/// # Arguments\n///\n/// * `arr` - A slice of integers where all elements except one appear exactly twice\n///\n/// # Returns\n///\n/// * `Ok(i32)` - The unique number that appears only once\n/// * `Err(String)` - An error message if the input is empty\n///\n/// # Examples\n///\n/// ```\n/// # use the_algorithms_rust::bit_manipulation::find_unique_number;\n/// assert_eq!(find_unique_number(&[1, 1, 2, 2, 3]).unwrap(), 3);\n/// assert_eq!(find_unique_number(&[4, 5, 4, 6, 6]).unwrap(), 5);\n/// assert_eq!(find_unique_number(&[7]).unwrap(), 7);\n/// assert_eq!(find_unique_number(&[10, 20, 10]).unwrap(), 20);\n/// assert!(find_unique_number(&[]).is_err());\n/// ```\npub fn find_unique_number(arr: &[i32]) -> Result<i32, String> {\n    if arr.is_empty() {\n        return Err(\"input list must not be empty\".to_string());\n    }\n\n    let result = arr.iter().fold(0, |acc, &num| acc ^ num);\n    Ok(result)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_basic_case() {\n        assert_eq!(find_unique_number(&[1, 1, 2, 2, 3]).unwrap(), 3);\n    }\n\n    #[test]\n    fn test_different_order() {\n        assert_eq!(find_unique_number(&[4, 5, 4, 6, 6]).unwrap(), 5);\n    }\n\n    #[test]\n    fn test_single_element() {\n        assert_eq!(find_unique_number(&[7]).unwrap(), 7);\n    }\n\n    #[test]\n    fn test_three_elements() {\n        assert_eq!(find_unique_number(&[10, 20, 10]).unwrap(), 20);\n    }\n\n    #[test]\n    fn test_empty_array() {\n        assert!(find_unique_number(&[]).is_err());\n        assert_eq!(\n            find_unique_number(&[]).unwrap_err(),\n            \"input list must not be empty\"\n        );\n    }\n\n    #[test]\n    fn test_negative_numbers() {\n        assert_eq!(find_unique_number(&[-1, -1, -2, -2, -3]).unwrap(), -3);\n    }\n\n    #[test]\n    fn test_large_numbers() {\n        assert_eq!(\n            find_unique_number(&[1000, 2000, 1000, 3000, 3000]).unwrap(),\n            2000\n        );\n    }\n\n    #[test]\n    fn test_zero() {\n        assert_eq!(find_unique_number(&[0, 1, 1]).unwrap(), 0);\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/hamming_distance.rs",
    "content": "//! Hamming Distance\n//!\n//! This module implements the [Hamming distance](https://en.wikipedia.org/wiki/Hamming_distance)\n//! algorithm for both integers and strings.\n//!\n//! The Hamming distance between two values is the number of positions at which\n//! the corresponding symbols differ.\n\n/// Counts the number of set bits (1s) in a 64-bit unsigned integer.\n///\n/// # Arguments\n///\n/// * `value` - The number to count set bits in\n///\n/// # Returns\n///\n/// The number of set bits in the value\n///\n/// # Example\n///\n/// ```\n/// // This is a private helper function\n/// let value: u64 = 11; // 1011 in binary has 3 set bits\n/// ```\nfn bit_count(mut value: u64) -> u64 {\n    let mut count = 0;\n    while value != 0 {\n        if value & 1 == 1 {\n            count += 1;\n        }\n        value >>= 1;\n    }\n    count\n}\n\n/// Calculates the Hamming distance between two unsigned 64-bit integers.\n///\n/// The Hamming distance is the number of bit positions at which the\n/// corresponding bits differ. This is computed by taking the XOR of the\n/// two numbers and counting the set bits.\n///\n/// # Arguments\n///\n/// * `a` - The first integer\n/// * `b` - The second integer\n///\n/// # Returns\n///\n/// The number of differing bits between `a` and `b`\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::hamming_distance;\n///\n/// let distance = hamming_distance(11, 2);\n/// assert_eq!(distance, 2);\n/// ```\npub fn hamming_distance(a: u64, b: u64) -> u64 {\n    bit_count(a ^ b)\n}\n\n/// Calculates the Hamming distance between two strings of equal length.\n///\n/// The Hamming distance is the number of positions at which the\n/// corresponding characters differ.\n///\n/// # Arguments\n///\n/// * `a` - The first string\n/// * `b` - The second string\n///\n/// # Returns\n///\n/// The number of differing characters between `a` and `b`\n///\n/// # Panics\n///\n/// Panics if the strings have different lengths\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::hamming_distance_str;\n///\n/// let distance = hamming_distance_str(\"1101\", \"1111\");\n/// assert_eq!(distance, 1);\n/// ```\npub fn hamming_distance_str(a: &str, b: &str) -> u64 {\n    assert_eq!(\n        a.len(),\n        b.len(),\n        \"Strings must have the same length for Hamming distance calculation\"\n    );\n\n    a.chars()\n        .zip(b.chars())\n        .filter(|(ch_a, ch_b)| ch_a != ch_b)\n        .count() as u64\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_bit_count() {\n        assert_eq!(bit_count(0), 0);\n        assert_eq!(bit_count(11), 3); // 1011 in binary\n        assert_eq!(bit_count(15), 4); // 1111 in binary\n    }\n\n    #[test]\n    fn test_hamming_distance_integers() {\n        assert_eq!(hamming_distance(11, 2), 2);\n        assert_eq!(hamming_distance(2, 0), 1);\n        assert_eq!(hamming_distance(11, 0), 3);\n        assert_eq!(hamming_distance(0, 0), 0);\n    }\n\n    #[test]\n    fn test_hamming_distance_strings() {\n        assert_eq!(hamming_distance_str(\"1101\", \"1111\"), 1);\n        assert_eq!(hamming_distance_str(\"1111\", \"1111\"), 0);\n        assert_eq!(hamming_distance_str(\"0000\", \"1111\"), 4);\n        assert_eq!(hamming_distance_str(\"alpha\", \"alphb\"), 1);\n        assert_eq!(hamming_distance_str(\"abcd\", \"abcd\"), 0);\n        assert_eq!(hamming_distance_str(\"dcba\", \"abcd\"), 4);\n    }\n\n    #[test]\n    #[should_panic(expected = \"Strings must have the same length\")]\n    fn test_hamming_distance_strings_different_lengths() {\n        hamming_distance_str(\"abc\", \"abcd\");\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/highest_set_bit.rs",
    "content": "//! This module provides a function to find the position of the most significant bit (MSB)\n//! set to 1 in a given positive integer.\n\n/// Finds the position of the highest (most significant) set bit in a positive integer.\n///\n/// # Arguments\n///\n/// * `num` - An integer value for which the highest set bit will be determined.\n///\n/// # Returns\n///\n/// *  Returns `Some(position)` if a set bit exists or `None` if no bit is set.\npub fn find_highest_set_bit(num: usize) -> Option<usize> {\n    if num == 0 {\n        return None;\n    }\n\n    let mut position = 0;\n    let mut n = num;\n\n    while n > 0 {\n        n >>= 1;\n        position += 1;\n    }\n\n    Some(position - 1)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_find_highest_set_bit {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $test_case;\n                    assert_eq!(find_highest_set_bit(input), expected);\n                }\n            )*\n        };\n    }\n\n    test_find_highest_set_bit! {\n        test_positive_number: (18, Some(4)),\n        test_0: (0, None),\n        test_1: (1, Some(0)),\n        test_2: (2, Some(1)),\n        test_3: (3, Some(1)),\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/is_power_of_two.rs",
    "content": "//! Power of Two Check\n//!\n//! This module provides a function to determine if a given positive integer is a power of two\n//! using efficient bit manipulation.\n//!\n//! # Algorithm\n//!\n//! The algorithm uses the property that powers of two have exactly one bit set in their\n//! binary representation. When we subtract 1 from a power of two, all bits after the single\n//! set bit become 1, and the set bit becomes 0:\n//!\n//! ```text\n//! n     = 0..100..00  (power of 2)\n//! n - 1 = 0..011..11\n//! n & (n - 1) = 0     (no intersections)\n//! ```\n//!\n//! For example:\n//! - 8 in binary:  1000\n//! - 7 in binary:  0111\n//! - 8 & 7 = 0000 = 0 ✓\n//!\n//! Author: Alexander Pantyukhin\n//! Date: November 1, 2022\n\n/// Determines if a given number is a power of two.\n///\n/// This function uses bit manipulation to efficiently check if a number is a power of two.\n/// A number is a power of two if it has exactly one bit set in its binary representation.\n/// The check `number & (number - 1) == 0` leverages this property.\n///\n/// # Arguments\n///\n/// * `number` - An integer to check (must be non-negative)\n///\n/// # Returns\n///\n/// A `Result` containing:\n/// - `Ok(true)` - If the number is a power of two (including 0 and 1)\n/// - `Ok(false)` - If the number is not a power of two\n/// - `Err(String)` - If the number is negative\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::is_power_of_two;\n///\n/// assert_eq!(is_power_of_two(0).unwrap(), true);\n/// assert_eq!(is_power_of_two(1).unwrap(), true);\n/// assert_eq!(is_power_of_two(2).unwrap(), true);\n/// assert_eq!(is_power_of_two(4).unwrap(), true);\n/// assert_eq!(is_power_of_two(8).unwrap(), true);\n/// assert_eq!(is_power_of_two(16).unwrap(), true);\n///\n/// assert_eq!(is_power_of_two(3).unwrap(), false);\n/// assert_eq!(is_power_of_two(6).unwrap(), false);\n/// assert_eq!(is_power_of_two(17).unwrap(), false);\n///\n/// // Negative numbers return an error\n/// assert!(is_power_of_two(-1).is_err());\n/// ```\n///\n/// # Errors\n///\n/// Returns an error if the input number is negative.\n///\n/// # Time Complexity\n///\n/// O(1) - The function performs a constant number of operations regardless of input size.\npub fn is_power_of_two(number: i32) -> Result<bool, String> {\n    if number < 0 {\n        return Err(\"number must not be negative\".to_string());\n    }\n\n    // Convert to u32 for safe bit operations\n    let num = number as u32;\n\n    // Check if number & (number - 1) == 0\n    // For powers of 2, this will always be true\n    Ok(num & num.wrapping_sub(1) == 0)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_zero() {\n        // 0 is considered a power of 2 by the algorithm (2^(-∞) interpretation)\n        assert!(is_power_of_two(0).unwrap());\n    }\n\n    #[test]\n    fn test_one() {\n        // 1 = 2^0\n        assert!(is_power_of_two(1).unwrap());\n    }\n\n    #[test]\n    fn test_powers_of_two() {\n        assert!(is_power_of_two(2).unwrap()); // 2^1\n        assert!(is_power_of_two(4).unwrap()); // 2^2\n        assert!(is_power_of_two(8).unwrap()); // 2^3\n        assert!(is_power_of_two(16).unwrap()); // 2^4\n        assert!(is_power_of_two(32).unwrap()); // 2^5\n        assert!(is_power_of_two(64).unwrap()); // 2^6\n        assert!(is_power_of_two(128).unwrap()); // 2^7\n        assert!(is_power_of_two(256).unwrap()); // 2^8\n        assert!(is_power_of_two(512).unwrap()); // 2^9\n        assert!(is_power_of_two(1024).unwrap()); // 2^10\n        assert!(is_power_of_two(2048).unwrap()); // 2^11\n        assert!(is_power_of_two(4096).unwrap()); // 2^12\n        assert!(is_power_of_two(8192).unwrap()); // 2^13\n        assert!(is_power_of_two(16384).unwrap()); // 2^14\n        assert!(is_power_of_two(32768).unwrap()); // 2^15\n        assert!(is_power_of_two(65536).unwrap()); // 2^16\n    }\n\n    #[test]\n    fn test_non_powers_of_two() {\n        assert!(!is_power_of_two(3).unwrap());\n        assert!(!is_power_of_two(5).unwrap());\n        assert!(!is_power_of_two(6).unwrap());\n        assert!(!is_power_of_two(7).unwrap());\n        assert!(!is_power_of_two(9).unwrap());\n        assert!(!is_power_of_two(10).unwrap());\n        assert!(!is_power_of_two(11).unwrap());\n        assert!(!is_power_of_two(12).unwrap());\n        assert!(!is_power_of_two(13).unwrap());\n        assert!(!is_power_of_two(14).unwrap());\n        assert!(!is_power_of_two(15).unwrap());\n        assert!(!is_power_of_two(17).unwrap());\n        assert!(!is_power_of_two(18).unwrap());\n    }\n\n    #[test]\n    fn test_specific_non_powers() {\n        assert!(!is_power_of_two(6).unwrap());\n        assert!(!is_power_of_two(17).unwrap());\n        assert!(!is_power_of_two(100).unwrap());\n        assert!(!is_power_of_two(1000).unwrap());\n    }\n\n    #[test]\n    fn test_large_powers_of_two() {\n        assert!(is_power_of_two(131072).unwrap()); // 2^17\n        assert!(is_power_of_two(262144).unwrap()); // 2^18\n        assert!(is_power_of_two(524288).unwrap()); // 2^19\n        assert!(is_power_of_two(1048576).unwrap()); // 2^20\n    }\n\n    #[test]\n    fn test_numbers_near_powers_of_two() {\n        // One less than powers of 2\n        assert!(!is_power_of_two(3).unwrap()); // 2^2 - 1\n        assert!(!is_power_of_two(7).unwrap()); // 2^3 - 1\n        assert!(!is_power_of_two(15).unwrap()); // 2^4 - 1\n        assert!(!is_power_of_two(31).unwrap()); // 2^5 - 1\n        assert!(!is_power_of_two(63).unwrap()); // 2^6 - 1\n        assert!(!is_power_of_two(127).unwrap()); // 2^7 - 1\n        assert!(!is_power_of_two(255).unwrap()); // 2^8 - 1\n\n        // One more than powers of 2\n        assert!(!is_power_of_two(3).unwrap()); // 2^1 + 1\n        assert!(!is_power_of_two(5).unwrap()); // 2^2 + 1\n        assert!(!is_power_of_two(9).unwrap()); // 2^3 + 1\n        assert!(!is_power_of_two(17).unwrap()); // 2^4 + 1\n        assert!(!is_power_of_two(33).unwrap()); // 2^5 + 1\n        assert!(!is_power_of_two(65).unwrap()); // 2^6 + 1\n        assert!(!is_power_of_two(129).unwrap()); // 2^7 + 1\n    }\n\n    #[test]\n    fn test_negative_number_returns_error() {\n        let result = is_power_of_two(-1);\n        assert!(result.is_err());\n        assert_eq!(result.unwrap_err(), \"number must not be negative\");\n    }\n\n    #[test]\n    fn test_multiple_negative_numbers() {\n        assert!(is_power_of_two(-1).is_err());\n        assert!(is_power_of_two(-2).is_err());\n        assert!(is_power_of_two(-4).is_err());\n        assert!(is_power_of_two(-8).is_err());\n        assert!(is_power_of_two(-100).is_err());\n    }\n\n    #[test]\n    fn test_all_powers_of_two_up_to_30() {\n        // Test 2^0 through 2^30\n        for i in 0..=30 {\n            let power = 1u32 << i; // 2^i\n            assert!(\n                is_power_of_two(power as i32).unwrap(),\n                \"2^{i} = {power} should be a power of 2\"\n            );\n        }\n    }\n\n    #[test]\n    fn test_range_verification() {\n        // Test that between consecutive powers of 2, only the powers return true\n        for i in 1..10 {\n            let power = 1 << i; // 2^i\n            assert!(is_power_of_two(power).unwrap());\n\n            // Check numbers between this power and the next\n            let next_power = 1 << (i + 1);\n            for num in (power + 1)..next_power {\n                assert!(\n                    !is_power_of_two(num).unwrap(),\n                    \"{num} should not be a power of 2\"\n                );\n            }\n        }\n    }\n\n    #[test]\n    fn test_bit_manipulation_correctness() {\n        // Verify the bit manipulation logic for specific examples\n        // For 8: 1000 & 0111 = 0000 ✓\n        assert_eq!(8 & 7, 0);\n        assert!(is_power_of_two(8).unwrap());\n\n        // For 16: 10000 & 01111 = 00000 ✓\n        assert_eq!(16 & 15, 0);\n        assert!(is_power_of_two(16).unwrap());\n\n        // For 6: 110 & 101 = 100 ✗\n        assert_ne!(6 & 5, 0);\n        assert!(!is_power_of_two(6).unwrap());\n    }\n\n    #[test]\n    fn test_edge_case_max_i32_power_of_two() {\n        // Largest power of 2 that fits in i32: 2^30 = 1073741824\n        assert!(is_power_of_two(1073741824).unwrap());\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/mod.rs",
    "content": "mod binary_coded_decimal;\nmod binary_count_trailing_zeros;\nmod binary_shifts;\nmod counting_bits;\nmod find_missing_number;\nmod find_previous_power_of_two;\nmod find_unique_number;\nmod hamming_distance;\nmod highest_set_bit;\nmod is_power_of_two;\nmod n_bits_gray_code;\nmod reverse_bits;\nmod rightmost_set_bit;\nmod sum_of_two_integers;\nmod swap_odd_even_bits;\nmod twos_complement;\n\npub use self::binary_coded_decimal::binary_coded_decimal;\npub use self::binary_count_trailing_zeros::binary_count_trailing_zeros;\npub use self::binary_shifts::{\n    arithmetic_left_shift, arithmetic_right_shift, logical_left_shift, logical_right_shift,\n};\npub use self::counting_bits::count_set_bits;\npub use self::find_missing_number::find_missing_number;\npub use self::find_previous_power_of_two::find_previous_power_of_two;\npub use self::find_unique_number::find_unique_number;\npub use self::hamming_distance::{hamming_distance, hamming_distance_str};\npub use self::highest_set_bit::find_highest_set_bit;\npub use self::is_power_of_two::is_power_of_two;\npub use self::n_bits_gray_code::generate_gray_code;\npub use self::reverse_bits::reverse_bits;\npub use self::rightmost_set_bit::{index_of_rightmost_set_bit, index_of_rightmost_set_bit_log};\npub use self::sum_of_two_integers::add_two_integers;\npub use self::swap_odd_even_bits::swap_odd_even_bits;\npub use self::twos_complement::twos_complement;\n"
  },
  {
    "path": "src/bit_manipulation/n_bits_gray_code.rs",
    "content": "/// Custom error type for Gray code generation.\n#[derive(Debug, PartialEq)]\npub enum GrayCodeError {\n    ZeroBitCount,\n}\n\n/// Generates an n-bit Gray code sequence using the direct Gray code formula.\n///\n/// # Arguments\n///\n/// * `n` - The number of bits for the Gray code.\n///\n/// # Returns\n///\n/// A vector of Gray code sequences as strings.\npub fn generate_gray_code(n: usize) -> Result<Vec<String>, GrayCodeError> {\n    if n == 0 {\n        return Err(GrayCodeError::ZeroBitCount);\n    }\n\n    let num_codes = 1 << n;\n    let mut result = Vec::with_capacity(num_codes);\n\n    for i in 0..num_codes {\n        let gray = i ^ (i >> 1);\n        let gray_code = (0..n)\n            .rev()\n            .map(|bit| if gray & (1 << bit) != 0 { '1' } else { '0' })\n            .collect::<String>();\n        result.push(gray_code);\n    }\n\n    Ok(result)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! gray_code_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $test_case;\n                    assert_eq!(generate_gray_code(input), expected);\n                }\n            )*\n        };\n    }\n\n    gray_code_tests! {\n        zero_bit_count: (0, Err(GrayCodeError::ZeroBitCount)),\n        gray_code_1_bit: (1, Ok(vec![\n            \"0\".to_string(),\n            \"1\".to_string(),\n        ])),\n        gray_code_2_bit: (2, Ok(vec![\n            \"00\".to_string(),\n            \"01\".to_string(),\n            \"11\".to_string(),\n            \"10\".to_string(),\n        ])),\n        gray_code_3_bit: (3, Ok(vec![\n            \"000\".to_string(),\n            \"001\".to_string(),\n            \"011\".to_string(),\n            \"010\".to_string(),\n            \"110\".to_string(),\n            \"111\".to_string(),\n            \"101\".to_string(),\n            \"100\".to_string(),\n        ])),\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/reverse_bits.rs",
    "content": "//! This module provides a function to reverse the bits of a 32-bit unsigned integer.\n//!\n//! The algorithm works by iterating through each of the 32 bits from least\n//! significant to most significant, extracting each bit and placing it in the\n//! reverse position.\n//!\n//! # Algorithm\n//!\n//! For each of the 32 bits:\n//! 1. Shift the result left by 1 to make room for the next bit\n//! 2. Extract the least significant bit of the input using bitwise AND with 1\n//! 3. OR that bit into the result\n//! 4. Shift the input right by 1 to process the next bit\n//!\n//! # Time Complexity\n//!\n//! O(1) - Always processes exactly 32 bits\n//!\n//! # Space Complexity\n//!\n//! O(1) - Uses a constant amount of extra space\n//!\n//! # Example\n//!\n//! ```\n//! use the_algorithms_rust::bit_manipulation::reverse_bits;\n//!\n//! let n = 43261596;  // Binary: 00000010100101000001111010011100\n//! let reversed = reverse_bits(n);\n//! assert_eq!(reversed, 964176192);  // Binary: 00111001011110000010100101000000\n//! ```\n\n/// Reverses the bits of a 32-bit unsigned integer.\n///\n/// # Arguments\n///\n/// * `n` - A 32-bit unsigned integer whose bits are to be reversed\n///\n/// # Returns\n///\n/// A 32-bit unsigned integer with bits in reverse order\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::reverse_bits;\n///\n/// let n = 43261596;  // 00000010100101000001111010011100 in binary\n/// let result = reverse_bits(n);\n/// assert_eq!(result, 964176192);  // 00111001011110000010100101000000 in binary\n/// ```\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::reverse_bits;\n///\n/// let n = 1;  // 00000000000000000000000000000001 in binary\n/// let result = reverse_bits(n);\n/// assert_eq!(result, 2147483648);  // 10000000000000000000000000000000 in binary\n/// ```\npub fn reverse_bits(n: u32) -> u32 {\n    let mut result: u32 = 0;\n    let mut num = n;\n\n    // Process all 32 bits\n    for _ in 0..32 {\n        // Shift result left to make room for next bit\n        result <<= 1;\n\n        // Extract the least significant bit of num and add it to result\n        result |= num & 1;\n\n        // Shift num right to process the next bit\n        num >>= 1;\n    }\n\n    result\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_reverse_bits_basic() {\n        // Test case 1: 43261596 (00000010100101000001111010011100)\n        // Expected: 964176192 (00111001011110000010100101000000)\n        assert_eq!(reverse_bits(43261596), 964176192);\n    }\n\n    #[test]\n    fn test_reverse_bits_one() {\n        // Test case 2: 1 (00000000000000000000000000000001)\n        // Expected: 2147483648 (10000000000000000000000000000000)\n        assert_eq!(reverse_bits(1), 2147483648);\n    }\n\n    #[test]\n    fn test_reverse_bits_all_ones() {\n        // Test case 3: 4294967293 (11111111111111111111111111111101)\n        // Expected: 3221225471 (10111111111111111111111111111111)\n        assert_eq!(reverse_bits(4294967293), 3221225471);\n    }\n\n    #[test]\n    fn test_reverse_bits_zero() {\n        // Test case 4: 0 (00000000000000000000000000000000)\n        // Expected: 0 (00000000000000000000000000000000)\n        assert_eq!(reverse_bits(0), 0);\n    }\n\n    #[test]\n    fn test_reverse_bits_max() {\n        // Test case 5: u32::MAX (11111111111111111111111111111111)\n        // Expected: u32::MAX (11111111111111111111111111111111)\n        assert_eq!(reverse_bits(u32::MAX), u32::MAX);\n    }\n\n    #[test]\n    fn test_reverse_bits_alternating() {\n        // Test case 6: 2863311530 (10101010101010101010101010101010)\n        // Expected: 1431655765 (01010101010101010101010101010101)\n        assert_eq!(reverse_bits(2863311530), 1431655765);\n    }\n\n    #[test]\n    fn test_reverse_bits_symmetric() {\n        // Test case 7: reversing twice should give original number\n        let n = 12345678;\n        assert_eq!(reverse_bits(reverse_bits(n)), n);\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/rightmost_set_bit.rs",
    "content": "/// Finds the index (position) of the rightmost set bit in a number.\n///\n/// The index is 1-based, where position 1 is the least significant bit (rightmost).\n/// This function uses the bitwise trick `n & -n` to isolate the rightmost set bit,\n/// then calculates its position using logarithm base 2.\n///\n/// # Algorithm\n///\n/// 1. Use `n & -n` to isolate the rightmost set bit\n/// 2. Calculate log2 of the result to get the 0-based position\n/// 3. Add 1 to convert to 1-based indexing\n///\n/// # Arguments\n///\n/// * `num` - A positive integer\n///\n/// # Returns\n///\n/// * `Ok(u32)` - The 1-based position of the rightmost set bit\n/// * `Err(String)` - An error message if the input is invalid\n///\n/// # Examples\n///\n/// ```\n/// # use the_algorithms_rust::bit_manipulation::index_of_rightmost_set_bit;\n/// // 18 in binary: 10010, rightmost set bit is at position 2\n/// assert_eq!(index_of_rightmost_set_bit(18).unwrap(), 2);\n///\n/// // 12 in binary: 1100, rightmost set bit is at position 3\n/// assert_eq!(index_of_rightmost_set_bit(12).unwrap(), 3);\n///\n/// // 5 in binary: 101, rightmost set bit is at position 1\n/// assert_eq!(index_of_rightmost_set_bit(5).unwrap(), 1);\n///\n/// // 16 in binary: 10000, rightmost set bit is at position 5\n/// assert_eq!(index_of_rightmost_set_bit(16).unwrap(), 5);\n///\n/// // 0 has no set bits\n/// assert!(index_of_rightmost_set_bit(0).is_err());\n/// ```\npub fn index_of_rightmost_set_bit(num: i32) -> Result<u32, String> {\n    if num <= 0 {\n        return Err(\"input must be a positive integer\".to_string());\n    }\n\n    // Isolate the rightmost set bit using n & -n\n    let rightmost_bit = num & -num;\n\n    // Calculate position: log2(rightmost_bit) + 1\n    // We use trailing_zeros which gives us the 0-based position\n    // and add 1 to make it 1-based\n    let position = rightmost_bit.trailing_zeros() + 1;\n\n    Ok(position)\n}\n\n/// Alternative implementation using a different algorithm approach.\n///\n/// This version demonstrates the mathematical relationship between\n/// the rightmost set bit position and log2.\n///\n/// # Examples\n///\n/// ```\n/// # use the_algorithms_rust::bit_manipulation::index_of_rightmost_set_bit_log;\n/// assert_eq!(index_of_rightmost_set_bit_log(18).unwrap(), 2);\n/// assert_eq!(index_of_rightmost_set_bit_log(12).unwrap(), 3);\n/// ```\npub fn index_of_rightmost_set_bit_log(num: i32) -> Result<u32, String> {\n    if num <= 0 {\n        return Err(\"input must be a positive integer\".to_string());\n    }\n\n    // Isolate the rightmost set bit\n    let rightmost_bit = num & -num;\n\n    // Use f64 log2 and convert to position\n    let position = (rightmost_bit as f64).log2() as u32 + 1;\n\n    Ok(position)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_basic_cases() {\n        // 18 = 10010 in binary, rightmost set bit at position 2\n        assert_eq!(index_of_rightmost_set_bit(18).unwrap(), 2);\n\n        // 12 = 1100 in binary, rightmost set bit at position 3\n        assert_eq!(index_of_rightmost_set_bit(12).unwrap(), 3);\n\n        // 5 = 101 in binary, rightmost set bit at position 1\n        assert_eq!(index_of_rightmost_set_bit(5).unwrap(), 1);\n    }\n\n    #[test]\n    fn test_powers_of_two() {\n        // 1 = 1 in binary, position 1\n        assert_eq!(index_of_rightmost_set_bit(1).unwrap(), 1);\n\n        // 2 = 10 in binary, position 2\n        assert_eq!(index_of_rightmost_set_bit(2).unwrap(), 2);\n\n        // 4 = 100 in binary, position 3\n        assert_eq!(index_of_rightmost_set_bit(4).unwrap(), 3);\n\n        // 8 = 1000 in binary, position 4\n        assert_eq!(index_of_rightmost_set_bit(8).unwrap(), 4);\n\n        // 16 = 10000 in binary, position 5\n        assert_eq!(index_of_rightmost_set_bit(16).unwrap(), 5);\n\n        // 32 = 100000 in binary, position 6\n        assert_eq!(index_of_rightmost_set_bit(32).unwrap(), 6);\n    }\n\n    #[test]\n    fn test_odd_numbers() {\n        // All odd numbers have rightmost set bit at position 1\n        assert_eq!(index_of_rightmost_set_bit(1).unwrap(), 1);\n        assert_eq!(index_of_rightmost_set_bit(3).unwrap(), 1);\n        assert_eq!(index_of_rightmost_set_bit(7).unwrap(), 1);\n        assert_eq!(index_of_rightmost_set_bit(15).unwrap(), 1);\n        assert_eq!(index_of_rightmost_set_bit(31).unwrap(), 1);\n    }\n\n    #[test]\n    fn test_even_numbers() {\n        // 6 = 110 in binary, rightmost set bit at position 2\n        assert_eq!(index_of_rightmost_set_bit(6).unwrap(), 2);\n\n        // 10 = 1010 in binary, rightmost set bit at position 2\n        assert_eq!(index_of_rightmost_set_bit(10).unwrap(), 2);\n\n        // 20 = 10100 in binary, rightmost set bit at position 3\n        assert_eq!(index_of_rightmost_set_bit(20).unwrap(), 3);\n    }\n\n    #[test]\n    fn test_zero() {\n        assert!(index_of_rightmost_set_bit(0).is_err());\n        assert_eq!(\n            index_of_rightmost_set_bit(0).unwrap_err(),\n            \"input must be a positive integer\"\n        );\n    }\n\n    #[test]\n    fn test_negative_numbers() {\n        assert!(index_of_rightmost_set_bit(-1).is_err());\n        assert!(index_of_rightmost_set_bit(-10).is_err());\n        assert_eq!(\n            index_of_rightmost_set_bit(-5).unwrap_err(),\n            \"input must be a positive integer\"\n        );\n    }\n\n    #[test]\n    fn test_large_numbers() {\n        // 1024 = 10000000000 in binary, position 11\n        assert_eq!(index_of_rightmost_set_bit(1024).unwrap(), 11);\n\n        // 1023 = 1111111111 in binary, position 1\n        assert_eq!(index_of_rightmost_set_bit(1023).unwrap(), 1);\n\n        // 2048 = 100000000000 in binary, position 12\n        assert_eq!(index_of_rightmost_set_bit(2048).unwrap(), 12);\n    }\n\n    #[test]\n    fn test_consecutive_numbers() {\n        // Testing a range to ensure correctness\n        assert_eq!(index_of_rightmost_set_bit(14).unwrap(), 2); // 1110\n        assert_eq!(index_of_rightmost_set_bit(15).unwrap(), 1); // 1111\n        assert_eq!(index_of_rightmost_set_bit(16).unwrap(), 5); // 10000\n        assert_eq!(index_of_rightmost_set_bit(17).unwrap(), 1); // 10001\n    }\n\n    #[test]\n    fn test_log_version() {\n        // Test the alternative log-based implementation\n        assert_eq!(index_of_rightmost_set_bit_log(18).unwrap(), 2);\n        assert_eq!(index_of_rightmost_set_bit_log(12).unwrap(), 3);\n        assert_eq!(index_of_rightmost_set_bit_log(5).unwrap(), 1);\n        assert_eq!(index_of_rightmost_set_bit_log(16).unwrap(), 5);\n    }\n\n    #[test]\n    fn test_both_implementations_match() {\n        // Verify both implementations give the same results\n        for i in 1..=100 {\n            assert_eq!(\n                index_of_rightmost_set_bit(i).unwrap(),\n                index_of_rightmost_set_bit_log(i).unwrap()\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/sum_of_two_integers.rs",
    "content": "//! This module provides a function to add two integers without using the `+` operator.\n//! It relies on bitwise operations (XOR and AND) to compute the sum, simulating the addition process.\n\n/// Adds two integers using bitwise operations.\n///\n/// # Arguments\n///\n/// * `a` - The first integer to be added.\n/// * `b` - The second integer to be added.\n///\n/// # Returns\n///\n/// * `isize` - The result of adding the two integers.\npub fn add_two_integers(mut a: isize, mut b: isize) -> isize {\n    let mut carry;\n\n    while b != 0 {\n        let sum = a ^ b;\n        carry = (a & b) << 1;\n        a = sum;\n        b = carry;\n    }\n\n    a\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_add_two_integers {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (a, b) = $test_case;\n                    assert_eq!(add_two_integers(a, b), a + b);\n                    assert_eq!(add_two_integers(b, a), a + b);\n                }\n            )*\n        };\n    }\n\n    test_add_two_integers! {\n        test_add_two_integers_positive: (3, 5),\n        test_add_two_integers_large_positive: (100, 200),\n        test_add_two_integers_edge_positive: (65535, 1),\n        test_add_two_integers_negative: (-10, 6),\n        test_add_two_integers_both_negative: (-50, -30),\n        test_add_two_integers_edge_negative: (-1, -1),\n        test_add_two_integers_zero: (0, 0),\n        test_add_two_integers_zero_with_positive: (0, 42),\n        test_add_two_integers_zero_with_negative: (0, -42),\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/swap_odd_even_bits.rs",
    "content": "/// Swaps odd and even bits in an integer.\n///\n/// This function separates the even bits (0, 2, 4, 6, etc.) and odd bits (1, 3, 5, 7, etc.)\n/// using bitwise AND operations, then swaps them by shifting and combining with OR.\n///\n/// # Arguments\n///\n/// * `num` - A 32-bit unsigned integer\n///\n/// # Returns\n///\n/// A new integer with odd and even bits swapped\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::swap_odd_even_bits;\n///\n/// assert_eq!(swap_odd_even_bits(0), 0);\n/// assert_eq!(swap_odd_even_bits(1), 2);\n/// assert_eq!(swap_odd_even_bits(2), 1);\n/// assert_eq!(swap_odd_even_bits(3), 3);\n/// assert_eq!(swap_odd_even_bits(4), 8);\n/// assert_eq!(swap_odd_even_bits(5), 10);\n/// assert_eq!(swap_odd_even_bits(6), 9);\n/// assert_eq!(swap_odd_even_bits(23), 43);\n/// ```\npub fn swap_odd_even_bits(num: u32) -> u32 {\n    // Get all even bits - 0xAAAAAAAA is a 32-bit number with all even bits set to 1\n    let even_bits = num & 0xAAAAAAAA;\n\n    // Get all odd bits - 0x55555555 is a 32-bit number with all odd bits set to 1\n    let odd_bits = num & 0x55555555;\n\n    // Right shift even bits and left shift odd bits and swap them\n    (even_bits >> 1) | (odd_bits << 1)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_swap_odd_even_bits() {\n        assert_eq!(swap_odd_even_bits(0), 0);\n        assert_eq!(swap_odd_even_bits(1), 2);\n        assert_eq!(swap_odd_even_bits(2), 1);\n        assert_eq!(swap_odd_even_bits(3), 3);\n        assert_eq!(swap_odd_even_bits(4), 8);\n        assert_eq!(swap_odd_even_bits(5), 10);\n        assert_eq!(swap_odd_even_bits(6), 9);\n        assert_eq!(swap_odd_even_bits(23), 43);\n        assert_eq!(swap_odd_even_bits(24), 36);\n    }\n\n    #[test]\n    fn test_edge_cases() {\n        // All bits set\n        assert_eq!(swap_odd_even_bits(0xFFFFFFFF), 0xFFFFFFFF);\n\n        // Alternating patterns\n        assert_eq!(swap_odd_even_bits(0xAAAAAAAA), 0x55555555);\n        assert_eq!(swap_odd_even_bits(0x55555555), 0xAAAAAAAA);\n    }\n\n    #[test]\n    fn test_power_of_two() {\n        assert_eq!(swap_odd_even_bits(16), 32);\n        assert_eq!(swap_odd_even_bits(32), 16);\n        assert_eq!(swap_odd_even_bits(64), 128);\n    }\n}\n"
  },
  {
    "path": "src/bit_manipulation/twos_complement.rs",
    "content": "//! Two's Complement Representation\n//!\n//! Two's complement is a mathematical operation on binary numbers and a binary signed\n//! number representation. It is widely used in computing as the most common method of\n//! representing signed integers on computers.\n//!\n//! For more information: <https://en.wikipedia.org/wiki/Two%27s_complement>\n\n/// Takes a negative integer and returns its two's complement binary representation.\n///\n/// The two's complement of a negative number is calculated by finding the binary\n/// representation that, when added to the positive value with the same magnitude,\n/// equals 2^n (where n is the number of bits).\n///\n/// # Arguments\n///\n/// * `number` - A non-positive integer (0 or negative)\n///\n/// # Returns\n///\n/// A `Result` containing:\n/// - `Ok(String)` - The two's complement representation with \"0b\" prefix\n/// - `Err(String)` - An error message if the input is positive\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::bit_manipulation::twos_complement;\n///\n/// assert_eq!(twos_complement(0).unwrap(), \"0b0\");\n/// assert_eq!(twos_complement(-1).unwrap(), \"0b11\");\n/// assert_eq!(twos_complement(-5).unwrap(), \"0b1011\");\n/// assert_eq!(twos_complement(-17).unwrap(), \"0b101111\");\n/// assert_eq!(twos_complement(-207).unwrap(), \"0b100110001\");\n///\n/// // Positive numbers return an error\n/// assert!(twos_complement(1).is_err());\n/// ```\n///\n/// # Errors\n///\n/// Returns an error if the input number is positive.\npub fn twos_complement(number: i32) -> Result<String, String> {\n    if number > 0 {\n        return Err(\"input must be a negative integer\".to_string());\n    }\n\n    if number == 0 {\n        return Ok(\"0b0\".to_string());\n    }\n\n    // Calculate the number of bits needed for the binary representation\n    // (excluding the sign bit in the original representation)\n    let binary_number_length = format!(\"{:b}\", number.abs()).len();\n\n    // Calculate two's complement value\n    // This is equivalent to: abs(number) - 2^binary_number_length\n    let twos_complement_value = (number.abs() as i64) - (1_i64 << binary_number_length);\n\n    // Format as binary string (removing the negative sign)\n    let mut twos_complement_str = format!(\"{:b}\", twos_complement_value.abs());\n\n    // Add leading zeros if necessary\n    let padding_zeros = binary_number_length.saturating_sub(twos_complement_str.len());\n    if padding_zeros > 0 {\n        twos_complement_str = format!(\"{}{twos_complement_str}\", \"0\".repeat(padding_zeros));\n    }\n\n    // Add leading '1' to indicate negative number in two's complement\n    Ok(format!(\"0b1{twos_complement_str}\"))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_zero() {\n        assert_eq!(twos_complement(0).unwrap(), \"0b0\");\n    }\n\n    #[test]\n    fn test_negative_one() {\n        assert_eq!(twos_complement(-1).unwrap(), \"0b11\");\n    }\n\n    #[test]\n    fn test_negative_five() {\n        assert_eq!(twos_complement(-5).unwrap(), \"0b1011\");\n    }\n\n    #[test]\n    fn test_negative_seventeen() {\n        assert_eq!(twos_complement(-17).unwrap(), \"0b101111\");\n    }\n\n    #[test]\n    fn test_negative_two_hundred_seven() {\n        assert_eq!(twos_complement(-207).unwrap(), \"0b100110001\");\n    }\n\n    #[test]\n    fn test_negative_small_values() {\n        assert_eq!(twos_complement(-2).unwrap(), \"0b110\");\n        assert_eq!(twos_complement(-3).unwrap(), \"0b101\");\n        assert_eq!(twos_complement(-4).unwrap(), \"0b1100\");\n    }\n\n    #[test]\n    fn test_negative_larger_values() {\n        assert_eq!(twos_complement(-128).unwrap(), \"0b110000000\");\n        assert_eq!(twos_complement(-255).unwrap(), \"0b100000001\");\n        assert_eq!(twos_complement(-1000).unwrap(), \"0b10000011000\");\n    }\n\n    #[test]\n    fn test_positive_number_returns_error() {\n        let result = twos_complement(1);\n        assert!(result.is_err());\n        assert_eq!(result.unwrap_err(), \"input must be a negative integer\");\n    }\n\n    #[test]\n    fn test_large_positive_number_returns_error() {\n        let result = twos_complement(100);\n        assert!(result.is_err());\n        assert_eq!(result.unwrap_err(), \"input must be a negative integer\");\n    }\n\n    #[test]\n    fn test_edge_case_negative_powers_of_two() {\n        assert_eq!(twos_complement(-8).unwrap(), \"0b11000\");\n        assert_eq!(twos_complement(-16).unwrap(), \"0b110000\");\n        assert_eq!(twos_complement(-32).unwrap(), \"0b1100000\");\n        assert_eq!(twos_complement(-64).unwrap(), \"0b11000000\");\n    }\n}\n"
  },
  {
    "path": "src/ciphers/README.md",
    "content": "## Ciphers\n\n### [Caesar](./caesar.rs)\n![alt text][caesar]\nIn cryptography, a **Caesar cipher**, also known as Caesar's cipher, the shift cipher, Caesar's code or Caesar shift, is one of the simplest and most widely known encryption techniques.<br>\nIt is **a type of substitution cipher** in which each letter in the plaintext is replaced by a letter some fixed number of positions down the alphabet. For example, with a left shift of 3, D would be replaced by A, E would become B, and so on. <br>\nThe method is named after **Julius Caesar**, who used it in his private correspondence.<br>\nThe encryption step performed by a Caesar cipher is often incorporated as part of more complex schemes, such as the Vigenère cipher, and still has modern application in the ROT13 system. As with all single-alphabet substitution ciphers, the Caesar cipher is easily broken and in modern practice offers essentially no communication security.\n###### Source: [Wikipedia](https://en.wikipedia.org/wiki/Caesar_cipher)\n\n### [Polybius](./polybius.rs)\nThe **Polybius square**, also known as the Polybius checkerboard, is a device invented by the ancient Greeks Cleoxenus and Democleitus, and made famous by the historian and scholar Polybius.<br>\nThe device is used for fractionating plaintext characters so that they can be represented by a smaller set of symbols, which is useful for telegraphy, steganography, and cryptography.<br>\nThe **Polybius square** is also used as a basic cipher called the Polybius cipher. This cipher is a **substitution cipher** with characters being substituted for pairs of digits.\n\n#### Example cipher\n Δ | 1 | 2 | 3 |  4  | 5\n---|---|---|---| --- |---\n1  | a | b | c |  d  | e\n2  | f | g | h | i/j | k\n3  | l | m | n |  o  | p\n4  | q | r | s |  t  | u\n5  | v | w | x |  y  | z\n###### Source: [Wikipedia](https://en.wikipedia.org/wiki/Polybius_square)\n\n### [Vigenère](./vigenere.rs)\nThe **Vigenère cipher** is a method of encrypting alphabetic text by using a series of **interwoven Caesar ciphers** based on the letters of a keyword. It is **a form of polyalphabetic substitution**.<br>\nThe Vigenère cipher has been reinvented many times. The method was originally described by Giovan Battista Bellaso in his 1553 book La cifra del. Sig. Giovan Battista Bellaso; however, the scheme was later misattributed to Blaise de Vigenère in the 19th century, and is now widely known as the \"Vigenère cipher\".<br>\nThough the cipher is easy to understand and implement, for three centuries it resisted all attempts to break it; this earned it the description **le chiffre indéchiffrable**(French for 'the indecipherable cipher'). \nMany people have tried to implement encryption schemes that are essentially Vigenère ciphers. Friedrich Kasiski was the first to publish a general method of deciphering a Vigenère cipher in 1863.\n###### Source: [Wikipedia](https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher)\n\n### [SHA-2](./sha256.rs)\nSHA-2 (Secure Hash Algorithm 2) is a set of cryptographic hash functions designed by the United States National Security Agency (NSA) and first published in 2001. They are built using the Merkle–Damgård structure, from a one-way compression function itself built using the Davies–Meyer structure from a (classified) specialized block cipher. \n###### Source: [Wikipedia](https://en.wikipedia.org/wiki/SHA-2)\n\n### [Transposition](./transposition.rs)\nIn cryptography, a **transposition cipher** is a method of encryption by which the positions held by units of plaintext (which are commonly characters or groups of characters) are shifted according to a regular system, so that the ciphertext constitutes a permutation of the plaintext. That is, the order of the units is changed (the plaintext is reordered).<br> \nMathematically a bijective function is used on the characters' positions to encrypt and an inverse function to decrypt.\n###### Source: [Wikipedia](https://en.wikipedia.org/wiki/Transposition_cipher)\n\n[caesar]: https://upload.wikimedia.org/wikipedia/commons/4/4a/Caesar_cipher_left_shift_of_3.svg\n\n### [AES](./aes.rs)\nThe Advanced Encryption Standard (AES), also known by its original name Rijndael (Dutch pronunciation: [ˈrɛindaːl]), is a specification for the encryption of electronic data established by the U.S. National Institute of Standards and Technology (NIST) in 2001.\n\n###### Source: [Wikipedia](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard)\n\n![aes](https://upload.wikimedia.org/wikipedia/commons/5/50/AES_%28Rijndael%29_Round_Function.png)"
  },
  {
    "path": "src/ciphers/aes.rs",
    "content": "const AES_WORD_SIZE: usize = 4;\nconst AES_BLOCK_SIZE: usize = 16;\nconst AES_NUM_BLOCK_WORDS: usize = AES_BLOCK_SIZE / AES_WORD_SIZE;\n\ntype Byte = u8;\ntype Word = u32;\n\ntype AesWord = [Byte; AES_WORD_SIZE];\n\n/// Precalculated values for x to the power of 2 in Rijndaels galois field.\n/// Used as 'RCON' during the key expansion.\nconst RCON: [Word; 256] = [\n    // 0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F\n    0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,\n    0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,\n    0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,\n    0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,\n    0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,\n    0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,\n    0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,\n    0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,\n    0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,\n    0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,\n    0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,\n    0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,\n    0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,\n    0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,\n    0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,\n    0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d,\n];\n\n/// Rijndael S-box Substitution table used for encryption in the subBytes\n/// step, as well as the key expansion.\nconst SBOX: [Byte; 256] = [\n    // 0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F\n    0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,\n    0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,\n    0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,\n    0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,\n    0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,\n    0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,\n    0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,\n    0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,\n    0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,\n    0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,\n    0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,\n    0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,\n    0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,\n    0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,\n    0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,\n    0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,\n];\n\n/// Inverse Rijndael S-box Substitution table used for decryption in the\n/// subBytesDec step.\nconst INV_SBOX: [Byte; 256] = [\n    // 0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F\n    0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,\n    0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,\n    0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,\n    0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,\n    0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,\n    0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,\n    0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,\n    0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,\n    0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,\n    0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,\n    0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,\n    0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,\n    0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,\n    0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,\n    0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,\n    0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D,\n];\n\n#[rustfmt::skip]\nconst GF_MUL_TABLE: [[Byte; 256]; 16] = [\n    /* 0 */ [0u8; 256],\n    /* 1 */ \n    [\n        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, \n        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, \n        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, \n        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, \n        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, \n        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, \n        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, \n        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, \n        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, \n        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, \n        0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, \n        0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, \n        0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, \n        0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, \n        0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, \n        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,\n    ],\n    /* 2 */ \n    [\n        0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,\n        0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,\n        0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,\n        0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,\n        0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,\n        0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,\n        0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,\n        0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,\n        0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,\n        0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,\n        0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,\n        0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,\n        0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,\n        0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,\n        0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,\n        0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5\n    ],\n    /* 3 */ \n    [\n        0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,\n        0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,\n        0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,\n        0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41,\n        0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1,\n        0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,\n        0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1,\n        0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81,\n        0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,\n        0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba,\n        0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,\n        0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,\n        0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,\n        0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,\n        0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,\n        0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a,\n    ],\n    /* 4 */ [0u8; 256],\n    /* 5 */ [0u8; 256],\n    /* 6 */ [0u8; 256],\n    /* 7 */ [0u8; 256],\n    /* 8 */ [0u8; 256],\n    /* 9 */ \n    [\n        0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,\n        0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,\n        0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,\n        0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc,\n        0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01,\n        0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91,\n        0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a,\n        0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa,\n        0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b,\n        0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b,\n        0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0,\n        0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30,\n        0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed,\n        0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d,\n        0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,\n        0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46,\n    ],\n    /* A */ [0u8; 256],\n    /* B */ \n    [\n        0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,\n        0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,\n        0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,\n        0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2,\n        0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f,\n        0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f,\n        0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4,\n        0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54,\n        0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e,\n        0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e,\n        0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5,\n        0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55,\n        0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68,\n        0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8,\n        0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,\n        0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3,\n    ],\n    /* C */ [0u8; 256],\n    /* D */ \n    [\n        0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,\n        0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,\n        0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,\n        0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20,\n        0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26,\n        0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6,\n        0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d,\n        0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d,\n        0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91,\n        0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41,\n        0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a,\n        0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa,\n        0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc,\n        0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c,\n        0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,\n        0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97\n    ],\n    /* E */ \n    [\n        0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,\n        0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,\n        0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,\n        0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61,\n        0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7,\n        0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17,\n        0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c,\n        0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc,\n        0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b,\n        0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb,\n        0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0,\n        0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20,\n        0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6,\n        0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56,\n        0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,\n        0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d\n    ],\n    /* F */ [0u8; 256],\n];\n\npub enum AesKey {\n    AesKey128([Byte; 16]),\n    AesKey192([Byte; 24]),\n    AesKey256([Byte; 32]),\n}\n\n#[derive(Clone, Copy)]\nenum AesMode {\n    Encryption,\n    Decryption,\n}\n\npub fn aes_encrypt(plain_text: &[Byte], key: AesKey) -> Vec<Byte> {\n    let (key, num_rounds) = match key {\n        AesKey::AesKey128(key) => (Vec::from(key), 10),\n        AesKey::AesKey192(key) => (Vec::from(key), 12),\n        AesKey::AesKey256(key) => (Vec::from(key), 14),\n    };\n\n    let round_keys = key_expansion(&key, num_rounds);\n    let mut data = padding::<Byte>(plain_text, AES_BLOCK_SIZE);\n\n    let round_key = &round_keys[0..AES_BLOCK_SIZE];\n    add_round_key(&mut data, round_key);\n\n    for round in 1..num_rounds {\n        sub_bytes_blocks(&mut data, AesMode::Encryption);\n        shift_rows_blocks(&mut data, AesMode::Encryption);\n        mix_column_blocks(&mut data, AesMode::Encryption);\n        let round_key = &round_keys[round * AES_BLOCK_SIZE..(round + 1) * AES_BLOCK_SIZE];\n        add_round_key(&mut data, round_key);\n    }\n\n    sub_bytes_blocks(&mut data, AesMode::Encryption);\n    shift_rows_blocks(&mut data, AesMode::Encryption);\n    let round_key = &round_keys[num_rounds * AES_BLOCK_SIZE..(num_rounds + 1) * AES_BLOCK_SIZE];\n    add_round_key(&mut data, round_key);\n\n    data\n}\n\npub fn aes_decrypt(cipher_text: &[Byte], key: AesKey) -> Vec<Byte> {\n    let (key, num_rounds) = match key {\n        AesKey::AesKey128(key) => (Vec::from(key), 10),\n        AesKey::AesKey192(key) => (Vec::from(key), 12),\n        AesKey::AesKey256(key) => (Vec::from(key), 14),\n    };\n\n    let round_keys = key_expansion(&key, num_rounds);\n    let mut data = padding::<Byte>(cipher_text, AES_BLOCK_SIZE);\n\n    let round_key = &round_keys[num_rounds * AES_BLOCK_SIZE..(num_rounds + 1) * AES_BLOCK_SIZE];\n    add_round_key(&mut data, round_key);\n    shift_rows_blocks(&mut data, AesMode::Decryption);\n    sub_bytes_blocks(&mut data, AesMode::Decryption);\n\n    for round in (1..num_rounds).rev() {\n        let round_key = &round_keys[round * AES_BLOCK_SIZE..(round + 1) * AES_BLOCK_SIZE];\n        add_round_key(&mut data, round_key);\n        mix_column_blocks(&mut data, AesMode::Decryption);\n        shift_rows_blocks(&mut data, AesMode::Decryption);\n        sub_bytes_blocks(&mut data, AesMode::Decryption);\n    }\n\n    let round_key = &round_keys[0..AES_BLOCK_SIZE];\n    add_round_key(&mut data, round_key);\n\n    data\n}\n\nfn key_expansion(init_key: &[Byte], num_rounds: usize) -> Vec<Byte> {\n    let nr = num_rounds;\n    // number of words in initial key\n    let nk = init_key.len() / AES_WORD_SIZE;\n    let nb = AES_NUM_BLOCK_WORDS;\n\n    let key = init_key\n        .chunks(AES_WORD_SIZE)\n        .map(bytes_to_word)\n        .collect::<Vec<Word>>();\n    let mut key = padding::<Word>(&key, nk * (nr + 1));\n\n    for i in nk..nb * (nr + 1) {\n        let mut temp_word = key[i - 1];\n        if i % nk == 0 {\n            temp_word = sub_word(rot_word(temp_word), AesMode::Encryption) ^ RCON[i / nk];\n        } else if nk > 6 && i % nk == 4 {\n            temp_word = sub_word(temp_word, AesMode::Encryption);\n        }\n        key[i] = key[i - nk] ^ temp_word;\n    }\n\n    key.iter()\n        .map(|&w| word_to_bytes(w))\n        .collect::<Vec<AesWord>>()\n        .concat()\n}\n\nfn add_round_key(data: &mut [Byte], round_key: &[Byte]) {\n    assert!(data.len().is_multiple_of(AES_BLOCK_SIZE) && round_key.len() == AES_BLOCK_SIZE);\n    let num_blocks = data.len() / AES_BLOCK_SIZE;\n    data.iter_mut()\n        .zip(round_key.repeat(num_blocks))\n        .for_each(|(s, k)| *s ^= k);\n}\n\nfn sub_bytes_blocks(data: &mut [Byte], mode: AesMode) {\n    for block in data.chunks_mut(AES_BLOCK_SIZE) {\n        sub_bytes(block, mode);\n    }\n}\n\nfn shift_rows_blocks(blocks: &mut [Byte], mode: AesMode) {\n    for block in blocks.chunks_mut(AES_BLOCK_SIZE) {\n        transpose_block(block);\n        shift_rows(block, mode);\n        transpose_block(block);\n    }\n}\n\nfn mix_column_blocks(data: &mut [Byte], mode: AesMode) {\n    for block in data.chunks_mut(AES_BLOCK_SIZE) {\n        transpose_block(block);\n        mix_column(block, mode);\n        transpose_block(block);\n    }\n}\n\nfn padding<T: Clone + Default>(data: &[T], block_size: usize) -> Vec<T> {\n    if data.len().is_multiple_of(block_size) {\n        Vec::from(data)\n    } else {\n        let num_blocks = data.len() / block_size + 1;\n        let mut padded = Vec::from(data);\n        padded.append(&mut vec![\n            T::default();\n            num_blocks * block_size - data.len()\n        ]);\n        padded\n    }\n}\n\nfn sub_word(word: Word, mode: AesMode) -> Word {\n    let mut bytes = word_to_bytes(word);\n    sub_bytes(&mut bytes, mode);\n    bytes_to_word(&bytes)\n}\n\nfn sub_bytes(data: &mut [Byte], mode: AesMode) {\n    let sbox = match mode {\n        AesMode::Encryption => &SBOX,\n        AesMode::Decryption => &INV_SBOX,\n    };\n    for data_byte in data {\n        *data_byte = sbox[*data_byte as usize];\n    }\n}\n\nfn shift_rows(block: &mut [Byte], mode: AesMode) {\n    // skip the first row, index begin from 1\n    for row in 1..4 {\n        let mut row_word: AesWord = [0u8; 4];\n        row_word.copy_from_slice(&block[row * 4..row * 4 + 4]);\n        for col in 0..4 {\n            block[row * 4 + col] = match mode {\n                AesMode::Encryption => row_word[(col + row) % 4],\n                AesMode::Decryption => row_word[(col + 4 - row) % 4],\n            }\n        }\n    }\n}\n\nfn mix_column(block: &mut [Byte], mode: AesMode) {\n    let mix_col_mat = match mode {\n        AesMode::Encryption => [\n            [0x02, 0x03, 0x01, 0x01],\n            [0x01, 0x02, 0x03, 0x01],\n            [0x01, 0x01, 0x02, 0x03],\n            [0x03, 0x01, 0x01, 0x02],\n        ],\n        AesMode::Decryption => [\n            [0x0e, 0x0b, 0x0d, 0x09],\n            [0x09, 0x0e, 0x0b, 0x0d],\n            [0x0d, 0x09, 0x0e, 0x0b],\n            [0x0b, 0x0d, 0x09, 0x0e],\n        ],\n    };\n\n    for col in 0..4 {\n        let col_word = block\n            .iter()\n            .zip(0..AES_BLOCK_SIZE)\n            .filter_map(|(&x, i)| if i % 4 == col { Some(x) } else { None })\n            .collect::<Vec<u8>>();\n        for row in 0..4 {\n            let mut word = 0;\n            for i in 0..4 {\n                word ^= GF_MUL_TABLE[mix_col_mat[row][i]][col_word[i] as usize] as Word\n            }\n            block[row * 4 + col] = word as Byte;\n        }\n    }\n}\n\nfn transpose_block(block: &mut [u8]) {\n    let mut src_block = [0u8; AES_BLOCK_SIZE];\n    src_block.copy_from_slice(block);\n    for row in 0..4 {\n        for col in 0..4 {\n            block[row * 4 + col] = src_block[col * 4 + row];\n        }\n    }\n}\n\nfn bytes_to_word(bytes: &[Byte]) -> Word {\n    assert!(bytes.len() == AES_WORD_SIZE);\n    let mut word = 0;\n    for (i, &byte) in bytes.iter().enumerate() {\n        word |= (byte as Word) << (8 * i);\n    }\n    word\n}\n\nfn word_to_bytes(word: Word) -> AesWord {\n    let mut bytes = [0; AES_WORD_SIZE];\n    for (i, byte) in bytes.iter_mut().enumerate() {\n        let bits_shift = 8 * i;\n        *byte = ((word & (0xff << bits_shift)) >> bits_shift) as Byte;\n    }\n    bytes\n}\n\nfn rot_word(word: Word) -> Word {\n    let mut bytes = word_to_bytes(word);\n    let init = bytes[0];\n    bytes[0] = bytes[1];\n    bytes[1] = bytes[2];\n    bytes[2] = bytes[3];\n    bytes[3] = init;\n    bytes_to_word(&bytes)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_aes_128() {\n        let plain: [u8; 16] = [\n            0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37,\n            0x07, 0x34,\n        ];\n        let key: [u8; 16] = [\n            0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf,\n            0x4f, 0x3c,\n        ];\n        let cipher: [u8; 16] = [\n            0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a,\n            0x0b, 0x32,\n        ];\n        let encrypted = aes_encrypt(&plain, AesKey::AesKey128(key));\n        assert_eq!(cipher, encrypted[..]);\n        let decrypted = aes_decrypt(&encrypted, AesKey::AesKey128(key));\n        assert_eq!(plain, decrypted[..]);\n    }\n\n    #[test]\n    fn test_aes_192() {\n        let plain: [u8; 16] = [\n            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,\n            0xee, 0xff,\n        ];\n        let key: [u8; 24] = [\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,\n            0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n        ];\n        let cipher: [u8; 16] = [\n            0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d,\n            0x71, 0x91,\n        ];\n        let encrypted = aes_encrypt(&plain, AesKey::AesKey192(key));\n        assert_eq!(cipher, encrypted[..]);\n        let decrypted = aes_decrypt(&encrypted, AesKey::AesKey192(key));\n        assert_eq!(plain, decrypted[..]);\n    }\n\n    #[test]\n    fn test_aes_256() {\n        let plain: [u8; 16] = [\n            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,\n            0xee, 0xff,\n        ];\n        let key: [u8; 32] = [\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,\n            0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,\n            0x1c, 0x1d, 0x1e, 0x1f,\n        ];\n        let cipher: [u8; 16] = [\n            0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49,\n            0x60, 0x89,\n        ];\n        let encrypted = aes_encrypt(&plain, AesKey::AesKey256(key));\n        assert_eq!(cipher, encrypted[..]);\n        let decrypted = aes_decrypt(&encrypted, AesKey::AesKey256(key));\n        assert_eq!(plain, decrypted[..]);\n    }\n\n    #[test]\n    fn test_str() {\n        let str = \"Hello, cipher world!\";\n        let plain = str.as_bytes();\n        let key = [\n            0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf,\n            0x4f, 0x3c,\n        ];\n        let encrypted = aes_encrypt(plain, AesKey::AesKey128(key));\n        let decrypted = aes_decrypt(&encrypted, AesKey::AesKey128(key));\n        assert_eq!(\n            str,\n            String::from_utf8(decrypted).unwrap().trim_end_matches('\\0')\n        );\n    }\n}\n"
  },
  {
    "path": "src/ciphers/affine_cipher.rs",
    "content": "//! Affine Cipher\n//!\n//! The affine cipher is a type of monoalphabetic substitution cipher where each\n//! character in the alphabet is mapped to its numeric equivalent, encrypted using\n//! a mathematical function, and converted back to a character.\n//!\n//! # Algorithm\n//!\n//! The encryption function is: `E(x) = (ax + b) mod m`\n//! The decryption function is: `D(x) = a^(-1)(x - b) mod m`\n//!\n//! Where:\n//! - `x` is the numeric position of the character\n//! - `a` and `b` are the keys (key_a and key_b)\n//! - `m` is the size of the symbol set\n//! - `a^(-1)` is the modular multiplicative inverse of `a` modulo `m`\n//!\n//! # Key Requirements\n//!\n//! - `key_a` must be coprime with the symbol set size (gcd(key_a, m) = 1)\n//! - `key_a` must not be 1 (cipher becomes too weak)\n//! - `key_b` must not be 0 (cipher becomes too weak)\n//! - `key_b` must be between 0 and symbol set size - 1\n//!\n//! # References\n//!\n//! - [Affine Cipher - Wikipedia](https://en.wikipedia.org/wiki/Affine_cipher)\n\n/// Symbol set used for the affine cipher - all printable ASCII characters\nconst SYMBOLS: &str = r##\" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"##;\n\n/// Calculates the greatest common divisor using the iterative Euclidean algorithm.\n///\n/// # Arguments\n///\n/// * `a` - First number\n/// * `b` - Second number\n///\n/// # Returns\n///\n/// The GCD of a and b\nfn gcd(mut a: usize, mut b: usize) -> usize {\n    while b != 0 {\n        let temp = b;\n        b = a % b;\n        a = temp;\n    }\n    a\n}\n\n/// Finds the modular multiplicative inverse of `a` modulo `m`.\n///\n/// Uses the Extended Euclidean Algorithm to find x such that:\n/// (a * x) mod m = 1\n///\n/// # Arguments\n///\n/// * `a` - The number to find the inverse of\n/// * `m` - The modulus\n///\n/// # Returns\n///\n/// `Some(inverse)` if the inverse exists, `None` otherwise\nfn find_mod_inverse(a: i64, m: i64) -> Option<i64> {\n    if gcd(a as usize, m as usize) != 1 {\n        return None; // No inverse exists\n    }\n\n    // Extended Euclidean Algorithm\n    let (mut u1, mut u2, mut u3) = (1i64, 0i64, a);\n    let (mut v1, mut v2, mut v3) = (0i64, 1i64, m);\n\n    while v3 != 0 {\n        let q = u3 / v3;\n        let t1 = u1 - q * v1;\n        let t2 = u2 - q * v2;\n        let t3 = u3 - q * v3;\n\n        u1 = v1;\n        u2 = v2;\n        u3 = v3;\n        v1 = t1;\n        v2 = t2;\n        v3 = t3;\n    }\n\n    let inverse = u1 % m;\n    if inverse < 0 {\n        Some(inverse + m)\n    } else {\n        Some(inverse)\n    }\n}\n\n/// Validates the encryption/decryption keys.\n///\n/// # Arguments\n///\n/// * `key_a` - The multiplicative key\n/// * `key_b` - The additive key\n/// * `is_encrypt` - Whether this is for encryption (applies additional checks)\n///\n/// # Returns\n///\n/// `Ok(())` if keys are valid, `Err(String)` with error message otherwise\nfn check_keys(key_a: usize, key_b: usize, is_encrypt: bool) -> Result<(), String> {\n    let symbols_len = SYMBOLS.len();\n\n    if is_encrypt {\n        if key_a == 1 {\n            return Err(\n                \"The affine cipher becomes weak when key A is set to 1. Choose a different key\"\n                    .to_string(),\n            );\n        }\n        if key_b == 0 {\n            return Err(\n                \"The affine cipher becomes weak when key B is set to 0. Choose a different key\"\n                    .to_string(),\n            );\n        }\n    }\n\n    if key_a == 0 {\n        return Err(\"Key A must be greater than 0\".to_string());\n    }\n\n    if key_b >= symbols_len {\n        return Err(format!(\"Key B must be between 0 and {}\", symbols_len - 1));\n    }\n\n    if gcd(key_a, symbols_len) != 1 {\n        return Err(format!(\n            \"Key A ({key_a}) and the symbol set size ({symbols_len}) are not relatively prime. Choose a different key\"\n        ));\n    }\n\n    Ok(())\n}\n\n/// Encrypts a message using the affine cipher.\n///\n/// # Arguments\n///\n/// * `key` - The encryption key (encoded as key_a * SYMBOLS.len() + key_b)\n/// * `message` - The plaintext message to encrypt\n///\n/// # Returns\n///\n/// `Ok(String)` with the encrypted message, or `Err(String)` if keys are invalid\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::ciphers::affine_encrypt;\n///\n/// let encrypted = affine_encrypt(4545, \"The affine cipher is a type of monoalphabetic substitution cipher.\").unwrap();\n/// assert_eq!(encrypted, \"VL}p MM{I}p~{HL}Gp{vp pFsH}pxMpyxIx JHL O}F{~pvuOvF{FuF{xIp~{HL}Gi\");\n/// ```\npub fn affine_encrypt(key: usize, message: &str) -> Result<String, String> {\n    let symbols_len = SYMBOLS.len();\n    let key_a = key / symbols_len;\n    let key_b = key % symbols_len;\n\n    check_keys(key_a, key_b, true)?;\n\n    let mut cipher_text = String::new();\n\n    for symbol in message.chars() {\n        if let Some(sym_index) = SYMBOLS.find(symbol) {\n            let encrypted_index = (sym_index * key_a + key_b) % symbols_len;\n            cipher_text.push(SYMBOLS.chars().nth(encrypted_index).unwrap());\n        } else {\n            // Keep symbols not in SYMBOLS unchanged\n            cipher_text.push(symbol);\n        }\n    }\n\n    Ok(cipher_text)\n}\n\n/// Decrypts a message using the affine cipher.\n///\n/// # Arguments\n///\n/// * `key` - The decryption key (same as encryption key)\n/// * `message` - The ciphertext message to decrypt\n///\n/// # Returns\n///\n/// `Ok(String)` with the decrypted message, or `Err(String)` if keys are invalid\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::ciphers::affine_decrypt;\n///\n/// let decrypted = affine_decrypt(4545, \"VL}p MM{I}p~{HL}Gp{vp pFsH}pxMpyxIx JHL O}F{~pvuOvF{FuF{xIp~{HL}Gi\").unwrap();\n/// assert_eq!(decrypted, \"The affine cipher is a type of monoalphabetic substitution cipher.\");\n/// ```\npub fn affine_decrypt(key: usize, message: &str) -> Result<String, String> {\n    let symbols_len = SYMBOLS.len();\n    let key_a = key / symbols_len;\n    let key_b = key % symbols_len;\n\n    check_keys(key_a, key_b, false)?;\n\n    let mod_inverse_of_key_a = find_mod_inverse(key_a as i64, symbols_len as i64)\n        .ok_or_else(|| format!(\"Could not find modular inverse of key A ({key_a})\"))?;\n\n    let mut plain_text = String::new();\n\n    for symbol in message.chars() {\n        if let Some(sym_index) = SYMBOLS.find(symbol) {\n            let decrypted_index = ((sym_index as i64 - key_b as i64) * mod_inverse_of_key_a)\n                .rem_euclid(symbols_len as i64) as usize;\n            plain_text.push(SYMBOLS.chars().nth(decrypted_index).unwrap());\n        } else {\n            // Keep symbols not in SYMBOLS unchanged\n            plain_text.push(symbol);\n        }\n    }\n\n    Ok(plain_text)\n}\n\n/// Generates a random valid key for the affine cipher.\n///\n/// The key is generated such that:\n/// - key_a is coprime with the symbol set size\n/// - key_b is not 0\n/// - Both keys are within valid ranges\n///\n/// # Returns\n///\n/// A random valid key encoded as key_a * SYMBOLS.len() + key_b\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::ciphers::affine_generate_key;\n///\n/// let key = affine_generate_key();\n/// assert!(key >= 2);\n/// ```\npub fn affine_generate_key() -> usize {\n    use rand::RngExt;\n    let mut rng = rand::rng();\n    let symbols_len = SYMBOLS.len();\n\n    loop {\n        let key_a = rng.random_range(2..symbols_len);\n        let key_b = rng.random_range(1..symbols_len);\n\n        if gcd(key_a, symbols_len) == 1 {\n            return key_a * symbols_len + key_b;\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_gcd() {\n        assert_eq!(gcd(48, 18), 6);\n        assert_eq!(gcd(18, 48), 6);\n        assert_eq!(gcd(100, 50), 50);\n        assert_eq!(gcd(17, 13), 1);\n        assert_eq!(gcd(1, 1), 1);\n        assert_eq!(gcd(0, 5), 5);\n    }\n\n    #[test]\n    fn test_find_mod_inverse() {\n        assert_eq!(find_mod_inverse(3, 11), Some(4));\n        assert_eq!(find_mod_inverse(7, 26), Some(15));\n        assert_eq!(find_mod_inverse(2, 5), Some(3));\n        assert_eq!(find_mod_inverse(4, 6), None); // No inverse (not coprime)\n    }\n\n    #[test]\n    fn test_encrypt_decrypt_example() {\n        let message = \"The affine cipher is a type of monoalphabetic substitution cipher.\";\n        let key = 4545;\n\n        let encrypted = affine_encrypt(key, message).unwrap();\n        assert_eq!(\n            encrypted,\n            \"VL}p MM{I}p~{HL}Gp{vp pFsH}pxMpyxIx JHL O}F{~pvuOvF{FuF{xIp~{HL}Gi\"\n        );\n\n        let decrypted = affine_decrypt(key, &encrypted).unwrap();\n        assert_eq!(decrypted, message);\n    }\n\n    #[test]\n    fn test_encrypt_simple() {\n        let key = 4545;\n        let message = \"Hello World!\";\n        let encrypted = affine_encrypt(key, message).unwrap();\n\n        // Verify it's different from original\n        assert_ne!(encrypted, message);\n\n        // Verify we can decrypt it back\n        let decrypted = affine_decrypt(key, &encrypted).unwrap();\n        assert_eq!(decrypted, message);\n    }\n\n    #[test]\n    fn test_roundtrip_various_messages() {\n        let key = 4545;\n        let messages = vec![\n            \"This is a test!\",\n            \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\",\n            \"0123456789\",\n            \"Special chars: !@#$%^&*()\",\n            \"Mixed Case And Numbers 123\",\n        ];\n\n        for message in messages {\n            let encrypted = affine_encrypt(key, message).unwrap();\n            let decrypted = affine_decrypt(key, &encrypted).unwrap();\n            assert_eq!(decrypted, message);\n        }\n    }\n\n    #[test]\n    fn test_empty_string() {\n        let key = 4545;\n        let message = \"\";\n        let encrypted = affine_encrypt(key, message).unwrap();\n        assert_eq!(encrypted, \"\");\n        let decrypted = affine_decrypt(key, &encrypted).unwrap();\n        assert_eq!(decrypted, \"\");\n    }\n\n    #[test]\n    fn test_invalid_key_a_is_one() {\n        let symbols_len = SYMBOLS.len();\n        let key = symbols_len + 5; // key_a = 1\n\n        let result = affine_encrypt(key, \"test\");\n        assert!(result.is_err());\n        assert!(result.unwrap_err().contains(\"weak when key A is set to 1\"));\n    }\n\n    #[test]\n    fn test_invalid_key_b_is_zero() {\n        let symbols_len = SYMBOLS.len();\n        let key = 5 * symbols_len; // key_b = 0\n\n        let result = affine_encrypt(key, \"test\");\n        assert!(result.is_err());\n        assert!(result.unwrap_err().contains(\"weak when key B is set to 0\"));\n    }\n\n    #[test]\n    fn test_invalid_key_not_coprime() {\n        let symbols_len = SYMBOLS.len();\n        // Use key_a = 5, since gcd(5, 95) = 5 (not coprime)\n        let key = 5 * symbols_len + 10; // key_a = 5, key_b = 10\n\n        let result = affine_encrypt(key, \"test\");\n        assert!(result.is_err());\n        assert!(result.unwrap_err().contains(\"not relatively prime\"));\n    }\n\n    #[test]\n    fn test_key_b_too_large() {\n        let symbols_len = SYMBOLS.len();\n        let key = 3 * symbols_len + symbols_len; // key_b = symbols_len (too large)\n\n        let result = affine_encrypt(key, \"test\");\n        assert!(result.is_err());\n        // This will actually have key_b = 0 after modulo, so it will fail for different reason\n        // Let me recalculate: if key = 3 * 95 + 95 = 380, then key_a = 380 / 95 = 4, key_b = 380 % 95 = 0\n        // So it will fail because key_b = 0\n    }\n\n    #[test]\n    fn test_symbols_not_in_set() {\n        let key = 4545;\n        let message = \"Hello\\nWorld\\t!\"; // Contains newline and tab\n        let encrypted = affine_encrypt(key, message).unwrap();\n\n        // Newline and tab should remain unchanged\n        assert!(encrypted.contains('\\n'));\n        assert!(encrypted.contains('\\t'));\n\n        let decrypted = affine_decrypt(key, &encrypted).unwrap();\n        assert_eq!(decrypted, message);\n    }\n\n    #[test]\n    fn test_generate_key() {\n        // Generate a key and test it works\n        let key = affine_generate_key();\n        let message = \"Test message for generated key\";\n\n        let encrypted = affine_encrypt(key, message).unwrap();\n        let decrypted = affine_decrypt(key, &encrypted).unwrap();\n        assert_eq!(decrypted, message);\n    }\n\n    #[test]\n    fn test_generate_key_validity() {\n        // Generate multiple keys and verify they're all valid\n        for _ in 0..10 {\n            let key = affine_generate_key();\n            let symbols_len = SYMBOLS.len();\n            let key_a = key / symbols_len;\n            let key_b = key % symbols_len;\n\n            // Check that the keys meet requirements\n            assert!(key_a > 1);\n            assert!(key_b > 0);\n            assert!(key_b < symbols_len);\n            assert_eq!(gcd(key_a, symbols_len), 1);\n        }\n    }\n\n    #[test]\n    fn test_all_symbols() {\n        let key = 4545;\n\n        // Test that all symbols in SYMBOLS can be encrypted and decrypted\n        for symbol in SYMBOLS.chars() {\n            let message = symbol.to_string();\n            let encrypted = affine_encrypt(key, &message).unwrap();\n            let decrypted = affine_decrypt(key, &encrypted).unwrap();\n            assert_eq!(decrypted, message);\n        }\n    }\n\n    #[test]\n    fn test_different_keys_produce_different_ciphertexts() {\n        let message = \"Hello World\";\n        let key1 = 4545;\n        let key2 = 3456;\n\n        let encrypted1 = affine_encrypt(key1, message).unwrap();\n        let encrypted2 = affine_encrypt(key2, message).unwrap();\n\n        assert_ne!(encrypted1, encrypted2);\n    }\n\n    #[test]\n    fn test_long_message() {\n        let key = 4545;\n        let message = \"The quick brown fox jumps over the lazy dog. \".repeat(10);\n\n        let encrypted = affine_encrypt(key, &message).unwrap();\n        let decrypted = affine_decrypt(key, &encrypted).unwrap();\n        assert_eq!(decrypted, message);\n    }\n}\n"
  },
  {
    "path": "src/ciphers/another_rot13.rs",
    "content": "pub fn another_rot13(text: &str) -> String {\n    let input = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n    let output = \"NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm\";\n    text.chars()\n        .map(|c| match input.find(c) {\n            Some(i) => output.chars().nth(i).unwrap(),\n            None => c,\n        })\n        .collect()\n}\n\n#[cfg(test)]\nmod tests {\n    // Note this useful idiom: importing names from outer (for mod tests) scope.\n    use super::*;\n\n    #[test]\n    fn test_simple() {\n        assert_eq!(another_rot13(\"ABCzyx\"), \"NOPmlk\");\n    }\n\n    #[test]\n    fn test_every_alphabet_with_space() {\n        assert_eq!(\n            another_rot13(\"The quick brown fox jumps over the lazy dog\"),\n            \"Gur dhvpx oebja sbk whzcf bire gur ynml qbt\"\n        );\n    }\n\n    #[test]\n    fn test_non_alphabet() {\n        assert_eq!(another_rot13(\"🎃 Jack-o'-lantern\"), \"🎃 Wnpx-b'-ynagrea\");\n    }\n}\n"
  },
  {
    "path": "src/ciphers/baconian_cipher.rs",
    "content": "// Author : cyrixninja\n//Program to encode and decode Baconian or Bacon's Cipher\n//Wikipedia reference : https://en.wikipedia.org/wiki/Bacon%27s_cipher\n// Bacon's cipher or the Baconian cipher is a method of steganographic message encoding devised by Francis Bacon in 1605.\n// A message is concealed in the presentation of text, rather than its content. Bacon cipher is categorized as both a substitution cipher (in plain code) and a concealment cipher (using the two typefaces).\n\n// Encode Baconian Cipher\npub fn baconian_encode(message: &str) -> String {\n    let alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n    let baconian = [\n        \"AAAAA\", \"AAAAB\", \"AAABA\", \"AAABB\", \"AABAA\", \"AABAB\", \"AABBA\", \"AABBB\", \"ABAAA\", \"ABAAB\",\n        \"ABABA\", \"ABABB\", \"ABBAA\", \"ABBAB\", \"ABBBA\", \"ABBBB\", \"BAAAA\", \"BAAAB\", \"BAABA\", \"BAABB\",\n        \"BABAA\", \"BABAB\", \"BABBA\", \"BABBB\",\n    ];\n\n    message\n        .chars()\n        .map(|c| {\n            if let Some(index) = alphabet.find(c.to_ascii_uppercase()) {\n                baconian[index].to_string()\n            } else {\n                c.to_string()\n            }\n        })\n        .collect()\n}\n\n// Decode Baconian Cipher\npub fn baconian_decode(encoded: &str) -> String {\n    let baconian = [\n        \"AAAAA\", \"AAAAB\", \"AAABA\", \"AAABB\", \"AABAA\", \"AABAB\", \"AABBA\", \"AABBB\", \"ABAAA\", \"ABAAB\",\n        \"ABABA\", \"ABABB\", \"ABBAA\", \"ABBAB\", \"ABBBA\", \"ABBBB\", \"BAAAA\", \"BAAAB\", \"BAABA\", \"BAABB\",\n        \"BABAA\", \"BABAB\", \"BABBA\", \"BABBB\",\n    ];\n    let alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\n    encoded\n        .as_bytes()\n        .chunks(5)\n        .map(|chunk| {\n            if let Some(index) = baconian\n                .iter()\n                .position(|&x| x == String::from_utf8_lossy(chunk))\n            {\n                alphabet.chars().nth(index).unwrap()\n            } else {\n                ' '\n            }\n        })\n        .collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_baconian_encoding() {\n        let message = \"HELLO\";\n        let encoded = baconian_encode(message);\n        assert_eq!(encoded, \"AABBBAABAAABABBABABBABBBA\");\n    }\n\n    #[test]\n    fn test_baconian_decoding() {\n        let message = \"AABBBAABAAABABBABABBABBBA\";\n        let decoded = baconian_decode(message);\n        assert_eq!(decoded, \"HELLO\");\n    }\n}\n"
  },
  {
    "path": "src/ciphers/base16.rs",
    "content": "//! Base16 encoding and decoding implementation.\n//!\n//! Base16, also known as hexadecimal encoding, represents binary data using 16 ASCII characters\n//! (0-9 and A-F). Each byte is represented by exactly two hexadecimal digits.\n//!\n//! This implementation follows RFC 3548 Section 6 specifications:\n//! - Uses uppercase characters (A-F) for encoding\n//! - Requires uppercase input for decoding\n//! - Validates that encoded data has an even number of characters\n\n/// Encodes the given bytes into base16 (hexadecimal) format.\n///\n/// Each byte is converted to two uppercase hexadecimal characters.\n///\n/// # Arguments\n///\n/// * `data` - A byte slice to encode\n///\n/// # Returns\n///\n/// A `String` containing the uppercase hexadecimal representation of the input data.\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::ciphers::base16_encode;\n/// assert_eq!(base16_encode(b\"Hello World!\"), \"48656C6C6F20576F726C6421\");\n/// assert_eq!(base16_encode(b\"HELLO WORLD!\"), \"48454C4C4F20574F524C4421\");\n/// assert_eq!(base16_encode(b\"\"), \"\");\n/// ```\npub fn base16_encode(data: &[u8]) -> String {\n    use std::fmt::Write;\n    data.iter().fold(String::new(), |mut output, byte| {\n        write!(output, \"{byte:02X}\").unwrap();\n        output\n    })\n}\n\n/// Decodes base16 (hexadecimal) encoded data into bytes.\n///\n/// This function validates the input according to RFC 3548 Section 6:\n/// - The data must have an even number of characters\n/// - The data must only contain uppercase hexadecimal characters (0-9, A-F)\n///\n/// # Arguments\n///\n/// * `data` - A string slice containing uppercase hexadecimal characters\n///\n/// # Returns\n///\n/// * `Ok(Vec<u8>)` - Successfully decoded bytes\n/// * `Err(String)` - Error message if the input is invalid\n///\n/// # Errors\n///\n/// Returns an error if:\n/// - The input has an odd number of characters\n/// - The input contains characters other than 0-9 and A-F\n/// - The input contains lowercase hexadecimal characters (a-f)\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::ciphers::base16_decode;\n/// assert_eq!(base16_decode(\"48656C6C6F20576F726C6421\").unwrap(), b\"Hello World!\");\n/// assert_eq!(base16_decode(\"48454C4C4F20574F524C4421\").unwrap(), b\"HELLO WORLD!\");\n/// assert_eq!(base16_decode(\"\").unwrap(), b\"\");\n/// ```\n///\n/// Invalid inputs return errors:\n///\n/// ```\n/// use the_algorithms_rust::ciphers::base16_decode;\n/// assert!(base16_decode(\"486\").is_err()); // Odd number of characters\n/// assert!(base16_decode(\"48656c6c6f20576f726c6421\").is_err()); // Lowercase hex\n/// assert!(base16_decode(\"This is not base16 encoded data.\").is_err()); // Invalid characters\n/// ```\npub fn base16_decode(data: &str) -> Result<Vec<u8>, String> {\n    // Check if data has an even number of characters\n    if !data.len().is_multiple_of(2) {\n        return Err(\"Base16 encoded data is invalid:\\n\\\n             Data does not have an even number of hex digits.\"\n            .to_string());\n    }\n\n    // Check if all characters are valid uppercase hexadecimal (0-9, A-F)\n    // This follows RFC 3548 section 6 which specifies uppercase\n    if !data\n        .chars()\n        .all(|c| c.is_ascii_hexdigit() && !c.is_lowercase())\n    {\n        return Err(\"Base16 encoded data is invalid:\\n\\\n             Data is not uppercase hex or it contains invalid characters.\"\n            .to_string());\n    }\n\n    // Decode pairs of hexadecimal characters into bytes\n    let mut result = Vec::with_capacity(data.len() / 2);\n    for i in (0..data.len()).step_by(2) {\n        let hex_pair = &data[i..i + 2];\n        match u8::from_str_radix(hex_pair, 16) {\n            Ok(byte) => result.push(byte),\n            Err(_) => {\n                return Err(\"Base16 encoded data is invalid:\\n\\\n                     Failed to decode hex pair.\"\n                    .to_string())\n            }\n        }\n    }\n\n    Ok(result)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_encode_hello_world() {\n        assert_eq!(base16_encode(b\"Hello World!\"), \"48656C6C6F20576F726C6421\");\n    }\n\n    #[test]\n    fn test_encode_hello_world_uppercase() {\n        assert_eq!(base16_encode(b\"HELLO WORLD!\"), \"48454C4C4F20574F524C4421\");\n    }\n\n    #[test]\n    fn test_encode_empty() {\n        assert_eq!(base16_encode(b\"\"), \"\");\n    }\n\n    #[test]\n    fn test_encode_special_characters() {\n        assert_eq!(base16_encode(b\"\\x00\\x01\\xFF\"), \"0001FF\");\n    }\n\n    #[test]\n    fn test_encode_all_bytes() {\n        let data: Vec<u8> = (0..=255).collect();\n        let encoded = base16_encode(&data);\n        assert_eq!(encoded.len(), 512); // 256 bytes * 2 hex chars each\n    }\n\n    #[test]\n    fn test_decode_hello_world() {\n        assert_eq!(\n            base16_decode(\"48656C6C6F20576F726C6421\").unwrap(),\n            b\"Hello World!\"\n        );\n    }\n\n    #[test]\n    fn test_decode_hello_world_uppercase() {\n        assert_eq!(\n            base16_decode(\"48454C4C4F20574F524C4421\").unwrap(),\n            b\"HELLO WORLD!\"\n        );\n    }\n\n    #[test]\n    fn test_decode_empty() {\n        assert_eq!(base16_decode(\"\").unwrap(), b\"\");\n    }\n\n    #[test]\n    fn test_decode_special_characters() {\n        assert_eq!(base16_decode(\"0001FF\").unwrap(), b\"\\x00\\x01\\xFF\");\n    }\n\n    #[test]\n    fn test_decode_odd_length() {\n        let result = base16_decode(\"486\");\n        assert!(result.is_err());\n        assert!(result\n            .unwrap_err()\n            .contains(\"does not have an even number of hex digits\"));\n    }\n\n    #[test]\n    fn test_decode_lowercase_hex() {\n        let result = base16_decode(\"48656c6c6f20576f726c6421\");\n        assert!(result.is_err());\n        assert!(result\n            .unwrap_err()\n            .contains(\"not uppercase hex or it contains invalid characters\"));\n    }\n\n    #[test]\n    fn test_decode_invalid_characters() {\n        let result = base16_decode(\"This is not base16 encoded data.\");\n        assert!(result.is_err());\n        assert!(result\n            .unwrap_err()\n            .contains(\"not uppercase hex or it contains invalid characters\"));\n    }\n\n    #[test]\n    fn test_decode_mixed_case() {\n        let result = base16_decode(\"48656C6c6F\"); // Mixed upper and lowercase\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn test_roundtrip() {\n        let original = b\"The quick brown fox jumps over the lazy dog\";\n        let encoded = base16_encode(original);\n        let decoded = base16_decode(&encoded).unwrap();\n        assert_eq!(decoded, original);\n    }\n\n    #[test]\n    fn test_roundtrip_all_bytes() {\n        let original: Vec<u8> = (0..=255).collect();\n        let encoded = base16_encode(&original);\n        let decoded = base16_decode(&encoded).unwrap();\n        assert_eq!(decoded, original);\n    }\n\n    #[test]\n    fn test_roundtrip_empty() {\n        let original = b\"\";\n        let encoded = base16_encode(original);\n        let decoded = base16_decode(&encoded).unwrap();\n        assert_eq!(decoded, original);\n    }\n}\n"
  },
  {
    "path": "src/ciphers/base32.rs",
    "content": "//! Base32 encoding and decoding implementation.\n//!\n//! Base32 is a binary-to-text encoding scheme that represents binary data using 32 ASCII characters\n//! (A-Z and 2-7). It's commonly used when case-insensitive encoding is needed or when avoiding\n//! characters that might be confused (like 0/O or 1/l).\n//!\n//! This implementation follows the standard Base32 alphabet as defined in RFC 4648.\n\nconst B32_CHARSET: &[u8; 32] = b\"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567\";\n\n/// Encodes the given bytes into base32.\n///\n/// The function converts binary data into base32 format using the standard alphabet.\n/// Output is padded with '=' characters to make the length a multiple of 8.\n///\n/// # Arguments\n///\n/// * `data` - A byte slice to encode\n///\n/// # Returns\n///\n/// A `Vec<u8>` containing the base32-encoded data with padding.\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::ciphers::base32_encode;\n/// assert_eq!(base32_encode(b\"Hello World!\"), b\"JBSWY3DPEBLW64TMMQQQ====\");\n/// assert_eq!(base32_encode(b\"123456\"), b\"GEZDGNBVGY======\");\n/// assert_eq!(base32_encode(b\"some long complex string\"), b\"ONXW2ZJANRXW4ZZAMNXW24DMMV4CA43UOJUW4ZY=\");\n/// ```\npub fn base32_encode(data: &[u8]) -> Vec<u8> {\n    if data.is_empty() {\n        return Vec::new();\n    }\n\n    // Convert bytes to binary string representation\n    use std::fmt::Write;\n    let mut binary_data = String::with_capacity(data.len() * 8);\n    for byte in data {\n        write!(binary_data, \"{byte:08b}\").unwrap();\n    }\n\n    // Pad binary data to be a multiple of 5 bits\n    let padding_needed = (5 - (binary_data.len() % 5)) % 5;\n    for _ in 0..padding_needed {\n        binary_data.push('0');\n    }\n\n    // Convert 5-bit chunks to base32 characters\n    let mut result = Vec::new();\n    for chunk in binary_data.as_bytes().chunks(5) {\n        let chunk_str = std::str::from_utf8(chunk).unwrap();\n        let index = usize::from_str_radix(chunk_str, 2).unwrap();\n        result.push(B32_CHARSET[index]);\n    }\n\n    // Pad result to be a multiple of 8 characters\n    while !result.len().is_multiple_of(8) {\n        result.push(b'=');\n    }\n\n    result\n}\n\n/// Decodes base32-encoded data into bytes.\n///\n/// The function decodes base32 format back to binary data, removing padding characters.\n///\n/// # Arguments\n///\n/// * `data` - A byte slice containing base32-encoded data\n///\n/// # Returns\n///\n/// * `Ok(Vec<u8>)` - Successfully decoded bytes\n/// * `Err(String)` - Error message if the input is invalid\n///\n/// # Errors\n///\n/// Returns an error if:\n/// - The input contains invalid base32 characters\n/// - The input cannot be properly decoded\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::ciphers::base32_decode;\n/// assert_eq!(base32_decode(b\"JBSWY3DPEBLW64TMMQQQ====\").unwrap(), b\"Hello World!\");\n/// assert_eq!(base32_decode(b\"GEZDGNBVGY======\").unwrap(), b\"123456\");\n/// assert_eq!(base32_decode(b\"ONXW2ZJANRXW4ZZAMNXW24DMMV4CA43UOJUW4ZY=\").unwrap(), b\"some long complex string\");\n/// ```\npub fn base32_decode(data: &[u8]) -> Result<Vec<u8>, String> {\n    if data.is_empty() {\n        return Ok(Vec::new());\n    }\n\n    // Remove padding and convert to string\n    let data_str =\n        std::str::from_utf8(data).map_err(|_| \"Invalid UTF-8 in base32 data\".to_string())?;\n    let data_stripped = data_str.trim_end_matches('=');\n\n    // Convert base32 characters to binary string\n    use std::fmt::Write;\n    let mut binary_chunks = String::with_capacity(data_stripped.len() * 5);\n    for ch in data_stripped.chars() {\n        // Find the index of this character in the charset\n        let index = B32_CHARSET\n            .iter()\n            .position(|&c| c == ch as u8)\n            .ok_or_else(|| format!(\"Invalid base32 character: {ch}\"))?;\n\n        // Convert index to 5-bit binary string\n        write!(binary_chunks, \"{index:05b}\").unwrap();\n    }\n\n    // Convert 8-bit chunks back to bytes\n    let mut result = Vec::new();\n    for chunk in binary_chunks.as_bytes().chunks(8) {\n        if chunk.len() == 8 {\n            let chunk_str = std::str::from_utf8(chunk).unwrap();\n            let byte_value = u8::from_str_radix(chunk_str, 2)\n                .map_err(|_| \"Failed to parse binary chunk\".to_string())?;\n            result.push(byte_value);\n        }\n    }\n\n    Ok(result)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_encode_hello_world() {\n        assert_eq!(base32_encode(b\"Hello World!\"), b\"JBSWY3DPEBLW64TMMQQQ====\");\n    }\n\n    #[test]\n    fn test_encode_numbers() {\n        assert_eq!(base32_encode(b\"123456\"), b\"GEZDGNBVGY======\");\n    }\n\n    #[test]\n    fn test_encode_long_string() {\n        assert_eq!(\n            base32_encode(b\"some long complex string\"),\n            b\"ONXW2ZJANRXW4ZZAMNXW24DMMV4CA43UOJUW4ZY=\"\n        );\n    }\n\n    #[test]\n    fn test_encode_empty() {\n        assert_eq!(base32_encode(b\"\"), b\"\");\n    }\n\n    #[test]\n    fn test_encode_single_char() {\n        assert_eq!(base32_encode(b\"A\"), b\"IE======\");\n    }\n\n    #[test]\n    fn test_decode_hello_world() {\n        assert_eq!(\n            base32_decode(b\"JBSWY3DPEBLW64TMMQQQ====\").unwrap(),\n            b\"Hello World!\"\n        );\n    }\n\n    #[test]\n    fn test_decode_numbers() {\n        assert_eq!(base32_decode(b\"GEZDGNBVGY======\").unwrap(), b\"123456\");\n    }\n\n    #[test]\n    fn test_decode_long_string() {\n        assert_eq!(\n            base32_decode(b\"ONXW2ZJANRXW4ZZAMNXW24DMMV4CA43UOJUW4ZY=\").unwrap(),\n            b\"some long complex string\"\n        );\n    }\n\n    #[test]\n    fn test_decode_empty() {\n        assert_eq!(base32_decode(b\"\").unwrap(), b\"\");\n    }\n\n    #[test]\n    fn test_decode_single_char() {\n        assert_eq!(base32_decode(b\"IE======\").unwrap(), b\"A\");\n    }\n\n    #[test]\n    fn test_decode_without_padding() {\n        assert_eq!(\n            base32_decode(b\"JBSWY3DPEBLW64TMMQQQ\").unwrap(),\n            b\"Hello World!\"\n        );\n    }\n\n    #[test]\n    fn test_decode_invalid_character() {\n        let result = base32_decode(b\"INVALID!@#$\");\n        assert!(result.is_err());\n        assert!(result.unwrap_err().contains(\"Invalid base32 character\"));\n    }\n\n    #[test]\n    fn test_roundtrip_hello() {\n        let original = b\"Hello\";\n        let encoded = base32_encode(original);\n        let decoded = base32_decode(&encoded).unwrap();\n        assert_eq!(decoded, original);\n    }\n\n    #[test]\n    fn test_roundtrip_various_strings() {\n        let test_cases = vec![\n            b\"a\" as &[u8],\n            b\"ab\",\n            b\"abc\",\n            b\"abcd\",\n            b\"abcde\",\n            b\"The quick brown fox jumps over the lazy dog\",\n            b\"1234567890\",\n            b\"!@#$%^&*()\",\n        ];\n\n        for original in test_cases {\n            let encoded = base32_encode(original);\n            let decoded = base32_decode(&encoded).unwrap();\n            assert_eq!(decoded, original, \"Failed for: {original:?}\");\n        }\n    }\n\n    #[test]\n    fn test_all_charset_characters() {\n        // Test that all characters in the charset can be encoded/decoded\n        for i in 0..32 {\n            let data = vec![i * 8]; // Arbitrary byte values\n            let encoded = base32_encode(&data);\n            let decoded = base32_decode(&encoded).unwrap();\n            assert_eq!(decoded, data);\n        }\n    }\n\n    #[test]\n    fn test_binary_data() {\n        let binary_data = vec![0x00, 0x01, 0x02, 0xFF, 0xFE, 0xFD];\n        let encoded = base32_encode(&binary_data);\n        let decoded = base32_decode(&encoded).unwrap();\n        assert_eq!(decoded, binary_data);\n    }\n\n    #[test]\n    fn test_padding_variations() {\n        // Test different amounts of padding\n        let test_cases: Vec<(&[u8], &[u8])> = vec![\n            (b\"f\", b\"MY======\"),\n            (b\"fo\", b\"MZXQ====\"),\n            (b\"foo\", b\"MZXW6===\"),\n            (b\"foob\", b\"MZXW6YQ=\"),\n            (b\"fooba\", b\"MZXW6YTB\"),\n            (b\"foobar\", b\"MZXW6YTBOI======\"),\n        ];\n\n        for (input, expected) in test_cases {\n            let encoded = base32_encode(input);\n            assert_eq!(encoded, expected, \"Encoding failed for: {input:?}\");\n            let decoded = base32_decode(&encoded).unwrap();\n            assert_eq!(decoded, input, \"Roundtrip failed for: {input:?}\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/ciphers/base64.rs",
    "content": "/*\n    A Rust implementation of a base64 encoder and decoder.\n    Written from scratch.\n*/\n\n// The charset and padding used for en- and decoding.\nconst CHARSET: &[u8; 64] = b\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nconst PADDING: char = '=';\n\n/*\n    Combines the two provided bytes into an u16,\n    and collects 6 bits from it using an AND mask:\n\n    Example:\n    Bytes: X and Y\n    (Bits of those bytes will be signified using the names of their byte)\n    Offset: 4\n\n    `combined` = 0bXXXXXXXXYYYYYYYY\n    AND mask:\n    0b1111110000000000 >> offset (4) = 0b0000111111000000\n    `combined` with mask applied:\n    0b0000XXYYYY000000\n    Shift the value right by (16 bit number) - (6 bit mask) - (4 offset) = 6:\n    0b0000000000XXYYYY\n    And then turn it into an u8:\n    0b00XXYYYY (Return value)\n*/\nfn collect_six_bits(from: (u8, u8), offset: u8) -> u8 {\n    let combined: u16 = ((from.0 as u16) << 8) | (from.1 as u16);\n    ((combined & (0b1111110000000000u16 >> offset)) >> (10 - offset)) as u8\n}\n\npub fn base64_encode(data: &[u8]) -> String {\n    let mut bits_encoded = 0usize;\n    let mut encoded_string = String::new();\n    // Using modulo twice to prevent an underflow, Wolfram|Alpha says this is optimal\n    let padding_needed = ((6 - (data.len() * 8) % 6) / 2) % 3;\n    loop {\n        let lower_byte_index_to_encode = bits_encoded / 8usize; // Integer division\n        if lower_byte_index_to_encode == data.len() {\n            break;\n        }\n        let lower_byte_to_encode = data[lower_byte_index_to_encode];\n        let upper_byte_to_encode = if (lower_byte_index_to_encode + 1) == data.len() {\n            0u8 // Padding\n        } else {\n            data[lower_byte_index_to_encode + 1]\n        };\n        let bytes_to_encode = (lower_byte_to_encode, upper_byte_to_encode);\n        let offset: u8 = (bits_encoded % 8) as u8;\n        encoded_string.push(CHARSET[collect_six_bits(bytes_to_encode, offset) as usize] as char);\n        bits_encoded += 6;\n    }\n    for _ in 0..padding_needed {\n        encoded_string.push(PADDING);\n    }\n    encoded_string\n}\n\n/*\n    Performs the exact inverse of the above description of `base64_encode`\n*/\npub fn base64_decode(data: &str) -> Result<Vec<u8>, (&str, u8)> {\n    let mut collected_bits = 0;\n    let mut byte_buffer = 0u16;\n    let mut databytes = data.bytes();\n    let mut outputbytes = Vec::<u8>::new();\n    'decodeloop: loop {\n        while collected_bits < 8 {\n            if let Some(nextbyte) = databytes.next() {\n                // Finds the first occurrence of the latest byte\n                if let Some(idx) = CHARSET.iter().position(|&x| x == nextbyte) {\n                    byte_buffer |= ((idx & 0b00111111) as u16) << (10 - collected_bits);\n                    collected_bits += 6;\n                } else if nextbyte == (PADDING as u8) {\n                    collected_bits -= 2; // Padding only comes at the end so this works\n                } else {\n                    return Err((\n                        \"Failed to decode base64: Expected byte from charset, found invalid byte.\",\n                        nextbyte,\n                    ));\n                }\n            } else {\n                break 'decodeloop;\n            }\n        }\n        outputbytes.push(((0b1111111100000000 & byte_buffer) >> 8) as u8);\n        byte_buffer &= 0b0000000011111111;\n        byte_buffer <<= 8;\n        collected_bits -= 8;\n    }\n    if collected_bits != 0 {\n        return Err((\"Failed to decode base64: Invalid padding.\", collected_bits));\n    }\n    Ok(outputbytes)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn pregenerated_random_bytes_encode() {\n        macro_rules! test_encode {\n            ($left: expr, $right: expr) => {\n                assert_eq!(base64_encode(&$left.to_vec()), $right);\n            };\n        }\n        test_encode!(\n            b\"\\xd31\\xc9\\x87D\\xfe\\xaa\\xb3\\xff\\xef\\x8c\\x0eoD\",\n            \"0zHJh0T+qrP/74wOb0Q=\"\n        );\n        test_encode!(\n            b\"\\x9f\\x0e8\\xbc\\xf5\\xd0-\\xb4.\\xd4\\xf0?\\x8f\\xe7\\t{.\\xff/6\\xcbTY!\\xae9\\x82\",\n            \"nw44vPXQLbQu1PA/j+cJey7/LzbLVFkhrjmC\"\n        );\n        test_encode!(b\"\\x7f3\\x15\\x1a\\xd3\\xf91\\x9bS\\xa44=\", \"fzMVGtP5MZtTpDQ9\");\n        test_encode!(\n            b\"7:\\xf5\\xd1[\\xbfV/P\\x18\\x03\\x00\\xdc\\xcd\\xa1\\xecG\",\n            \"Nzr10Vu/Vi9QGAMA3M2h7Ec=\"\n        );\n        test_encode!(\n            b\"\\xc3\\xc9\\x18={\\xc4\\x08\\x97wN\\xda\\x81\\x84?\\x94\\xe6\\x9e\",\n            \"w8kYPXvECJd3TtqBhD+U5p4=\"\n        );\n        test_encode!(\n            b\"\\x8cJ\\xf8e\\x13\\r\\x8fw\\xa8\\xe6G\\xce\\x93c*\\xe7M\\xb6\\xd7\",\n            \"jEr4ZRMNj3eo5kfOk2Mq50221w==\"\n        );\n        test_encode!(\n            b\"\\xde\\xc4~\\xb2}\\xb1\\x14F.~\\xa1z|s\\x90\\x8dd\\x9b\\x04\\x81\\xf2\\x92{\",\n            \"3sR+sn2xFEYufqF6fHOQjWSbBIHykns=\"\n        );\n        test_encode!(\n            b\"\\xf0y\\t\\x14\\xd161n\\x03e\\xed\\x0e\\x05\\xdf\\xc1\\xb9\\xda\",\n            \"8HkJFNE2MW4DZe0OBd/Budo=\"\n        );\n        test_encode!(\n            b\"*.\\x8e\\x1d@\\x1ac\\xdd;\\x9a\\xcc \\x0c\\xc2KI\",\n            \"Ki6OHUAaY907mswgDMJLSQ==\"\n        );\n        test_encode!(b\"\\xd6\\x829\\x82\\xbc\\x00\\xc9\\xfe\\x03\", \"1oI5grwAyf4D\");\n        test_encode!(\n            b\"\\r\\xf2\\xb4\\xd4\\xa1g\\x8fhl\\xaa@\\x98\\x00\\xda\\x95\",\n            \"DfK01KFnj2hsqkCYANqV\"\n        );\n        test_encode!(\n            b\"\\x1a\\xfaV\\x1a\\xc2e\\xc0\\xad\\xef|\\x07\\xcf\\xa9\\xb7O\",\n            \"GvpWGsJlwK3vfAfPqbdP\"\n        );\n        test_encode!(b\"\\xc20{_\\x81\\xac\", \"wjB7X4Gs\");\n        test_encode!(\n            b\"B\\xa85\\xac\\xe9\\x0ev-\\x8bT\\xb3|\\xde\",\n            \"Qqg1rOkOdi2LVLN83g==\"\n        );\n        test_encode!(\n            b\"\\x05\\xe0\\xeeSs\\xfdY9\\x0b7\\x84\\xfc-\\xec\",\n            \"BeDuU3P9WTkLN4T8Lew=\"\n        );\n        test_encode!(\n            b\"Qj\\x92\\xfa?\\xa5\\xe3_[\\xde\\x82\\x97{$\\xb2\\xf9\\xd5\\x98\\x0cy\\x15\\xe4R\\x8d\",\n            \"UWqS+j+l419b3oKXeySy+dWYDHkV5FKN\"\n        );\n        test_encode!(b\"\\x853\\xe0\\xc0\\x1d\\xc1\", \"hTPgwB3B\");\n        test_encode!(b\"}2\\xd0\\x13m\\x8d\\x8f#\\x9c\\xf5,\\xc7\", \"fTLQE22NjyOc9SzH\");\n    }\n\n    #[test]\n    fn pregenerated_random_bytes_decode() {\n        macro_rules! test_decode {\n            ($left: expr, $right: expr) => {\n                assert_eq!(\n                    base64_decode(&String::from($left)).unwrap(),\n                    $right.to_vec()\n                );\n            };\n        }\n        test_decode!(\n            \"0zHJh0T+qrP/74wOb0Q=\",\n            b\"\\xd31\\xc9\\x87D\\xfe\\xaa\\xb3\\xff\\xef\\x8c\\x0eoD\"\n        );\n        test_decode!(\n            \"nw44vPXQLbQu1PA/j+cJey7/LzbLVFkhrjmC\",\n            b\"\\x9f\\x0e8\\xbc\\xf5\\xd0-\\xb4.\\xd4\\xf0?\\x8f\\xe7\\t{.\\xff/6\\xcbTY!\\xae9\\x82\"\n        );\n        test_decode!(\"fzMVGtP5MZtTpDQ9\", b\"\\x7f3\\x15\\x1a\\xd3\\xf91\\x9bS\\xa44=\");\n        test_decode!(\n            \"Nzr10Vu/Vi9QGAMA3M2h7Ec=\",\n            b\"7:\\xf5\\xd1[\\xbfV/P\\x18\\x03\\x00\\xdc\\xcd\\xa1\\xecG\"\n        );\n        test_decode!(\n            \"w8kYPXvECJd3TtqBhD+U5p4=\",\n            b\"\\xc3\\xc9\\x18={\\xc4\\x08\\x97wN\\xda\\x81\\x84?\\x94\\xe6\\x9e\"\n        );\n        test_decode!(\n            \"jEr4ZRMNj3eo5kfOk2Mq50221w==\",\n            b\"\\x8cJ\\xf8e\\x13\\r\\x8fw\\xa8\\xe6G\\xce\\x93c*\\xe7M\\xb6\\xd7\"\n        );\n        test_decode!(\n            \"3sR+sn2xFEYufqF6fHOQjWSbBIHykns=\",\n            b\"\\xde\\xc4~\\xb2}\\xb1\\x14F.~\\xa1z|s\\x90\\x8dd\\x9b\\x04\\x81\\xf2\\x92{\"\n        );\n        test_decode!(\n            \"8HkJFNE2MW4DZe0OBd/Budo=\",\n            b\"\\xf0y\\t\\x14\\xd161n\\x03e\\xed\\x0e\\x05\\xdf\\xc1\\xb9\\xda\"\n        );\n        test_decode!(\n            \"Ki6OHUAaY907mswgDMJLSQ==\",\n            b\"*.\\x8e\\x1d@\\x1ac\\xdd;\\x9a\\xcc \\x0c\\xc2KI\"\n        );\n        test_decode!(\"1oI5grwAyf4D\", b\"\\xd6\\x829\\x82\\xbc\\x00\\xc9\\xfe\\x03\");\n        test_decode!(\n            \"DfK01KFnj2hsqkCYANqV\",\n            b\"\\r\\xf2\\xb4\\xd4\\xa1g\\x8fhl\\xaa@\\x98\\x00\\xda\\x95\"\n        );\n        test_decode!(\n            \"GvpWGsJlwK3vfAfPqbdP\",\n            b\"\\x1a\\xfaV\\x1a\\xc2e\\xc0\\xad\\xef|\\x07\\xcf\\xa9\\xb7O\"\n        );\n        test_decode!(\"wjB7X4Gs\", b\"\\xc20{_\\x81\\xac\");\n        test_decode!(\n            \"Qqg1rOkOdi2LVLN83g==\",\n            b\"B\\xa85\\xac\\xe9\\x0ev-\\x8bT\\xb3|\\xde\"\n        );\n        test_decode!(\n            \"BeDuU3P9WTkLN4T8Lew=\",\n            b\"\\x05\\xe0\\xeeSs\\xfdY9\\x0b7\\x84\\xfc-\\xec\"\n        );\n        test_decode!(\n            \"UWqS+j+l419b3oKXeySy+dWYDHkV5FKN\",\n            b\"Qj\\x92\\xfa?\\xa5\\xe3_[\\xde\\x82\\x97{$\\xb2\\xf9\\xd5\\x98\\x0cy\\x15\\xe4R\\x8d\"\n        );\n        test_decode!(\"hTPgwB3B\", b\"\\x853\\xe0\\xc0\\x1d\\xc1\");\n        test_decode!(\"fTLQE22NjyOc9SzH\", b\"}2\\xd0\\x13m\\x8d\\x8f#\\x9c\\xf5,\\xc7\");\n    }\n\n    #[test]\n    fn encode_decode() {\n        macro_rules! test_e_d {\n            ($text: expr) => {\n                assert_eq!(\n                    base64_decode(&base64_encode(&$text.to_vec())).unwrap(),\n                    $text\n                );\n            };\n        }\n        test_e_d!(b\"green\");\n        test_e_d!(b\"The quick brown fox jumped over the lazy dog.\");\n        test_e_d!(b\"Lorem Ipsum sit dolor amet.\");\n        test_e_d!(b\"0\");\n        test_e_d!(b\"01\");\n        test_e_d!(b\"012\");\n        test_e_d!(b\"0123\");\n        test_e_d!(b\"0123456789\");\n    }\n\n    #[test]\n    fn decode_encode() {\n        macro_rules! test_d_e {\n            ($data: expr) => {\n                assert_eq!(\n                    base64_encode(&base64_decode(&String::from($data)).unwrap()),\n                    String::from($data)\n                );\n            };\n        }\n        test_d_e!(\"TG9uZyBsaXZlIGVhc3RlciBlZ2dzIDop\");\n        test_d_e!(\"SGFwcHkgSGFja3RvYmVyZmVzdCE=\");\n        test_d_e!(\"PVRoZSBBbGdvcml0aG1zPQ==\");\n    }\n}\n"
  },
  {
    "path": "src/ciphers/base85.rs",
    "content": "//! Base85 (Ascii85) encoding and decoding\n//!\n//! Ascii85 is a form of binary-to-text encoding developed by Adobe Systems.\n//! It encodes 4 bytes into 5 ASCII characters from the range 33-117 ('!' to 'u').\n//!\n//! # References\n//! - [Wikipedia: Ascii85](https://en.wikipedia.org/wiki/Ascii85)\n\n/// Converts a base-10 number to base-85 representation\nfn base10_to_85(mut d: u32) -> String {\n    if d == 0 {\n        return String::new();\n    }\n\n    let mut result = String::new();\n    while d > 0 {\n        result.push((d % 85 + 33) as u8 as char);\n        d /= 85;\n    }\n    result\n}\n\n/// Converts base-85 digits to a base-10 number\nfn base85_to_10(digits: &[u8]) -> u32 {\n    digits\n        .iter()\n        .rev()\n        .enumerate()\n        .map(|(i, &ch)| (ch as u32) * 85_u32.pow(i as u32))\n        .sum()\n}\n\n/// Encodes binary data using Base85 encoding\n///\n/// # Arguments\n/// * `data` - The binary data to encode\n///\n/// # Returns\n/// * `Vec<u8>` - The Base85 encoded data\n///\n/// # Examples\n/// ```\n/// use the_algorithms_rust::ciphers::base85_encode;\n///\n/// assert_eq!(base85_encode(b\"\"), b\"\");\n/// assert_eq!(base85_encode(b\"12345\"), b\"0etOA2#\");\n/// assert_eq!(base85_encode(b\"base 85\"), b\"@UX=h+?24\");\n/// ```\npub fn base85_encode(data: &[u8]) -> Vec<u8> {\n    if data.is_empty() {\n        return Vec::new();\n    }\n\n    // Convert input bytes to binary string\n    let mut binary_data = String::new();\n    for &byte in data {\n        use std::fmt::Write;\n        write!(&mut binary_data, \"{byte:08b}\").unwrap();\n    }\n\n    // Calculate padding needed to make length a multiple of 32\n    let remainder = binary_data.len() % 32;\n    let null_values = if remainder == 0 {\n        0\n    } else {\n        (32 - remainder) / 8\n    };\n\n    // Pad binary data to multiple of 32 bits\n    while !binary_data.len().is_multiple_of(32) {\n        binary_data.push('0');\n    }\n\n    // Split into 32-bit chunks and convert to base-85\n    let mut result = String::new();\n    for chunk in binary_data.as_bytes().chunks(32) {\n        let chunk_str = std::str::from_utf8(chunk).unwrap();\n        let value = u32::from_str_radix(chunk_str, 2).unwrap();\n        let mut encoded = base10_to_85(value);\n\n        // Reverse the string (as per original Python logic)\n        encoded = encoded.chars().rev().collect();\n        result.push_str(&encoded);\n    }\n\n    // Remove padding characters if necessary\n    if null_values % 4 != 0 {\n        let trim_len = result.len() - null_values;\n        result.truncate(trim_len);\n    }\n\n    result.into_bytes()\n}\n\n/// Decodes Base85 encoded data back to binary\n///\n/// # Arguments\n/// * `data` - The Base85 encoded data to decode\n///\n/// # Returns\n/// * `Vec<u8>` - The decoded binary data\n///\n/// # Examples\n/// ```\n/// use the_algorithms_rust::ciphers::base85_decode;\n///\n/// assert_eq!(base85_decode(b\"\"), b\"\");\n/// assert_eq!(base85_decode(b\"0etOA2#\"), b\"12345\");\n/// assert_eq!(base85_decode(b\"@UX=h+?24\"), b\"base 85\");\n/// ```\npub fn base85_decode(data: &[u8]) -> Vec<u8> {\n    if data.is_empty() {\n        return Vec::new();\n    }\n\n    // Calculate padding needed\n    let remainder = data.len() % 5;\n    let null_values = if remainder == 0 { 0 } else { 5 - remainder };\n\n    // Create padded data\n    let mut padded_data = data.to_vec();\n    padded_data.extend(std::iter::repeat_n(b'u', null_values));\n\n    // Process in 5-byte chunks\n    let mut results = Vec::new();\n    for chunk in padded_data.chunks(5) {\n        // Convert ASCII characters to base-85 digits\n        let b85_segment: Vec<u8> = chunk.iter().map(|&b| b - 33).collect();\n\n        // Convert base-85 to base-10\n        let value = base85_to_10(&b85_segment);\n\n        // Convert to binary string (32 bits)\n        let binary = format!(\"{value:032b}\");\n        results.push(binary);\n    }\n\n    // Convert binary strings to characters\n    let mut char_chunks = Vec::new();\n    for binary_str in results {\n        for byte_str in binary_str.as_bytes().chunks(8) {\n            let byte_string = std::str::from_utf8(byte_str).unwrap();\n            let byte_value = u8::from_str_radix(byte_string, 2).unwrap();\n            char_chunks.push(byte_value);\n        }\n    }\n\n    // Calculate offset for trimming\n    let offset = if null_values % 5 == 0 {\n        0\n    } else {\n        -(null_values as isize)\n    };\n    let result_len = if offset < 0 {\n        (char_chunks.len() as isize + offset) as usize\n    } else {\n        char_chunks.len()\n    };\n\n    char_chunks.truncate(result_len);\n    char_chunks\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_encode_empty() {\n        assert_eq!(base85_encode(b\"\"), b\"\");\n    }\n\n    #[test]\n    fn test_encode_12345() {\n        assert_eq!(base85_encode(b\"12345\"), b\"0etOA2#\");\n    }\n\n    #[test]\n    fn test_encode_base85() {\n        assert_eq!(base85_encode(b\"base 85\"), b\"@UX=h+?24\");\n    }\n\n    #[test]\n    fn test_decode_empty() {\n        assert_eq!(base85_decode(b\"\"), b\"\");\n    }\n\n    #[test]\n    fn test_decode_12345() {\n        assert_eq!(base85_decode(b\"0etOA2#\"), b\"12345\");\n    }\n\n    #[test]\n    fn test_decode_base85() {\n        assert_eq!(base85_decode(b\"@UX=h+?24\"), b\"base 85\");\n    }\n\n    #[test]\n    fn test_encode_decode_roundtrip() {\n        let test_cases = vec![\n            b\"Hello, World!\".to_vec(),\n            b\"The quick brown fox\".to_vec(),\n            b\"Rust\".to_vec(),\n            b\"a\".to_vec(),\n        ];\n\n        for test_case in test_cases {\n            let encoded = base85_encode(&test_case);\n            let decoded = base85_decode(&encoded);\n            assert_eq!(decoded, test_case);\n        }\n    }\n}\n"
  },
  {
    "path": "src/ciphers/blake2b.rs",
    "content": "// For specification go to https://www.rfc-editor.org/rfc/rfc7693\n\nuse std::cmp::{max, min};\nuse std::convert::{TryFrom, TryInto};\n\ntype Word = u64;\n\nconst BB: usize = 128;\n\nconst U64BYTES: usize = (u64::BITS as usize) / 8;\n\ntype Block = [Word; BB / U64BYTES];\n\nconst KK_MAX: usize = 64;\nconst NN_MAX: u8 = 64;\n\n// Array of round constants used in mixing function G\nconst RC: [u32; 4] = [32, 24, 16, 63];\n\n// IV[i] = floor(2**64 * frac(sqrt(prime(i+1)))) where prime(i) is the ith prime number\nconst IV: [Word; 8] = [\n    0x6A09E667F3BCC908,\n    0xBB67AE8584CAA73B,\n    0x3C6EF372FE94F82B,\n    0xA54FF53A5F1D36F1,\n    0x510E527FADE682D1,\n    0x9B05688C2B3E6C1F,\n    0x1F83D9ABFB41BD6B,\n    0x5BE0CD19137E2179,\n];\n\nconst SIGMA: [[usize; 16]; 10] = [\n    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],\n    [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],\n    [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],\n    [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],\n    [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],\n    [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],\n    [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],\n    [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],\n    [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],\n    [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],\n];\n\n#[inline]\nconst fn blank_block() -> Block {\n    [0u64; BB / U64BYTES]\n}\n\n// Overflowing addition\n#[inline]\nfn add(a: &mut Word, b: Word) {\n    *a = a.overflowing_add(b).0;\n}\n\n#[inline]\nconst fn ceil(dividend: usize, divisor: usize) -> usize {\n    (dividend / divisor) + (!dividend.is_multiple_of(divisor) as usize)\n}\n\nfn g(v: &mut [Word; 16], a: usize, b: usize, c: usize, d: usize, x: Word, y: Word) {\n    for (m, r) in [x, y].into_iter().zip(RC.chunks(2)) {\n        let v_b = v[b];\n        add(&mut v[a], v_b);\n        add(&mut v[a], m);\n\n        v[d] = (v[d] ^ v[a]).rotate_right(r[0]);\n\n        let v_d = v[d];\n        add(&mut v[c], v_d);\n\n        v[b] = (v[b] ^ v[c]).rotate_right(r[1]);\n    }\n}\n\nfn f(h: &mut [Word; 8], m: Block, t: u128, flag: bool) {\n    let mut v: [Word; 16] = [0; 16];\n\n    for (i, (h_i, iv_i)) in h.iter().zip(IV.iter()).enumerate() {\n        v[i] = *h_i;\n        v[i + 8] = *iv_i;\n    }\n\n    v[12] ^= (t % (u64::MAX as u128)) as u64;\n    v[13] ^= (t >> 64) as u64;\n\n    if flag {\n        v[14] = !v[14];\n    }\n\n    for i in 0..12 {\n        let s = SIGMA[i % 10];\n\n        let mut s_index = 0;\n        for j in 0..4 {\n            g(\n                &mut v,\n                j,\n                j + 4,\n                j + 8,\n                j + 12,\n                m[s[s_index]],\n                m[s[s_index + 1]],\n            );\n\n            s_index += 2;\n        }\n\n        let i1d = |col, row| {\n            let col = col % 4;\n            let row = row % 4;\n\n            (row * 4) + col\n        };\n\n        for j in 0..4 {\n            // Produces indeces for diagonals of a 4x4 matrix starting at 0,j\n            let idx: Vec<usize> = (0..4).map(|n| i1d(j + n, n) as usize).collect();\n\n            g(\n                &mut v,\n                idx[0],\n                idx[1],\n                idx[2],\n                idx[3],\n                m[s[s_index]],\n                m[s[s_index + 1]],\n            );\n\n            s_index += 2;\n        }\n    }\n\n    for (i, n) in h.iter_mut().enumerate() {\n        *n ^= v[i] ^ v[i + 8];\n    }\n}\n\nfn blake2(d: Vec<Block>, ll: u128, kk: Word, nn: Word) -> Vec<u8> {\n    let mut h: [Word; 8] = IV\n        .iter()\n        .take(8)\n        .copied()\n        .collect::<Vec<Word>>()\n        .try_into()\n        .unwrap();\n\n    h[0] ^= 0x01010000u64 ^ (kk << 8) ^ nn;\n\n    if d.len() > 1 {\n        for (i, w) in d.iter().enumerate().take(d.len() - 1) {\n            f(&mut h, *w, (i as u128 + 1) * BB as u128, false);\n        }\n    }\n\n    let ll = if kk > 0 { ll + BB as u128 } else { ll };\n    f(&mut h, d[d.len() - 1], ll, true);\n\n    h.iter()\n        .flat_map(|n| n.to_le_bytes())\n        .take(nn as usize)\n        .collect()\n}\n\n// Take arbitrarily long slice of u8's and turn up to 8 bytes into u64\nfn bytes_to_word(bytes: &[u8]) -> Word {\n    if let Ok(arr) = <[u8; U64BYTES]>::try_from(bytes) {\n        Word::from_le_bytes(arr)\n    } else {\n        let mut arr = [0u8; 8];\n        for (a_i, b_i) in arr.iter_mut().zip(bytes) {\n            *a_i = *b_i;\n        }\n\n        Word::from_le_bytes(arr)\n    }\n}\n\npub fn blake2b(m: &[u8], k: &[u8], nn: u8) -> Vec<u8> {\n    let kk = min(k.len(), KK_MAX);\n    let nn = min(nn, NN_MAX);\n\n    // Prevent user from giving a key that is too long\n    let k = &k[..kk];\n\n    let dd = max(ceil(kk, BB) + ceil(m.len(), BB), 1);\n\n    let mut blocks: Vec<Block> = vec![blank_block(); dd];\n\n    // Copy key into blocks\n    for (w, c) in blocks[0].iter_mut().zip(k.chunks(U64BYTES)) {\n        *w = bytes_to_word(c);\n    }\n\n    let first_index = (kk > 0) as usize;\n\n    // Copy bytes from message into blocks\n    for (i, c) in m.chunks(U64BYTES).enumerate() {\n        let block_index = first_index + (i / (BB / U64BYTES));\n        let word_in_block = i % (BB / U64BYTES);\n\n        blocks[block_index][word_in_block] = bytes_to_word(c);\n    }\n\n    blake2(blocks, m.len() as u128, kk as u64, nn as Word)\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    macro_rules! digest_test {\n        ($fname:ident, $message:expr, $key:expr, $nn:literal, $expected:expr) => {\n            #[test]\n            fn $fname() {\n                let digest = blake2b($message, $key, $nn);\n\n                let expected = Vec::from($expected);\n\n                assert_eq!(digest, expected);\n            }\n        };\n    }\n\n    digest_test!(\n        blake2b_from_rfc,\n        &[0x61, 0x62, 0x63],\n        &[0; 0],\n        64,\n        [\n            0xBA, 0x80, 0xA5, 0x3F, 0x98, 0x1C, 0x4D, 0x0D, 0x6A, 0x27, 0x97, 0xB6, 0x9F, 0x12,\n            0xF6, 0xE9, 0x4C, 0x21, 0x2F, 0x14, 0x68, 0x5A, 0xC4, 0xB7, 0x4B, 0x12, 0xBB, 0x6F,\n            0xDB, 0xFF, 0xA2, 0xD1, 0x7D, 0x87, 0xC5, 0x39, 0x2A, 0xAB, 0x79, 0x2D, 0xC2, 0x52,\n            0xD5, 0xDE, 0x45, 0x33, 0xCC, 0x95, 0x18, 0xD3, 0x8A, 0xA8, 0xDB, 0xF1, 0x92, 0x5A,\n            0xB9, 0x23, 0x86, 0xED, 0xD4, 0x00, 0x99, 0x23\n        ]\n    );\n\n    digest_test!(\n        blake2b_empty,\n        &[0; 0],\n        &[0; 0],\n        64,\n        [\n            0x78, 0x6a, 0x02, 0xf7, 0x42, 0x01, 0x59, 0x03, 0xc6, 0xc6, 0xfd, 0x85, 0x25, 0x52,\n            0xd2, 0x72, 0x91, 0x2f, 0x47, 0x40, 0xe1, 0x58, 0x47, 0x61, 0x8a, 0x86, 0xe2, 0x17,\n            0xf7, 0x1f, 0x54, 0x19, 0xd2, 0x5e, 0x10, 0x31, 0xaf, 0xee, 0x58, 0x53, 0x13, 0x89,\n            0x64, 0x44, 0x93, 0x4e, 0xb0, 0x4b, 0x90, 0x3a, 0x68, 0x5b, 0x14, 0x48, 0xb7, 0x55,\n            0xd5, 0x6f, 0x70, 0x1a, 0xfe, 0x9b, 0xe2, 0xce\n        ]\n    );\n\n    digest_test!(\n        blake2b_empty_with_key,\n        &[0; 0],\n        &[\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,\n            0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,\n            0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,\n            0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,\n            0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f\n        ],\n        64,\n        [\n            0x10, 0xeb, 0xb6, 0x77, 0x00, 0xb1, 0x86, 0x8e, 0xfb, 0x44, 0x17, 0x98, 0x7a, 0xcf,\n            0x46, 0x90, 0xae, 0x9d, 0x97, 0x2f, 0xb7, 0xa5, 0x90, 0xc2, 0xf0, 0x28, 0x71, 0x79,\n            0x9a, 0xaa, 0x47, 0x86, 0xb5, 0xe9, 0x96, 0xe8, 0xf0, 0xf4, 0xeb, 0x98, 0x1f, 0xc2,\n            0x14, 0xb0, 0x05, 0xf4, 0x2d, 0x2f, 0xf4, 0x23, 0x34, 0x99, 0x39, 0x16, 0x53, 0xdf,\n            0x7a, 0xef, 0xcb, 0xc1, 0x3f, 0xc5, 0x15, 0x68\n        ]\n    );\n\n    digest_test!(\n        blake2b_key_shortin,\n        &[0],\n        &[\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,\n            0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,\n            0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,\n            0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,\n            0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f\n        ],\n        64,\n        [\n            0x96, 0x1f, 0x6d, 0xd1, 0xe4, 0xdd, 0x30, 0xf6, 0x39, 0x01, 0x69, 0x0c, 0x51, 0x2e,\n            0x78, 0xe4, 0xb4, 0x5e, 0x47, 0x42, 0xed, 0x19, 0x7c, 0x3c, 0x5e, 0x45, 0xc5, 0x49,\n            0xfd, 0x25, 0xf2, 0xe4, 0x18, 0x7b, 0x0b, 0xc9, 0xfe, 0x30, 0x49, 0x2b, 0x16, 0xb0,\n            0xd0, 0xbc, 0x4e, 0xf9, 0xb0, 0xf3, 0x4c, 0x70, 0x03, 0xfa, 0xc0, 0x9a, 0x5e, 0xf1,\n            0x53, 0x2e, 0x69, 0x43, 0x02, 0x34, 0xce, 0xbd\n        ]\n    );\n\n    digest_test!(\n        blake2b_keyed_filled,\n        &[\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,\n            0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,\n            0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,\n            0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,\n            0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f\n        ],\n        &[\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,\n            0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,\n            0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,\n            0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,\n            0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f\n        ],\n        64,\n        [\n            0x65, 0x67, 0x6d, 0x80, 0x06, 0x17, 0x97, 0x2f, 0xbd, 0x87, 0xe4, 0xb9, 0x51, 0x4e,\n            0x1c, 0x67, 0x40, 0x2b, 0x7a, 0x33, 0x10, 0x96, 0xd3, 0xbf, 0xac, 0x22, 0xf1, 0xab,\n            0xb9, 0x53, 0x74, 0xab, 0xc9, 0x42, 0xf1, 0x6e, 0x9a, 0xb0, 0xea, 0xd3, 0x3b, 0x87,\n            0xc9, 0x19, 0x68, 0xa6, 0xe5, 0x09, 0xe1, 0x19, 0xff, 0x07, 0x78, 0x7b, 0x3e, 0xf4,\n            0x83, 0xe1, 0xdc, 0xdc, 0xcf, 0x6e, 0x30, 0x22\n        ]\n    );\n}\n"
  },
  {
    "path": "src/ciphers/caesar.rs",
    "content": "const ERROR_MESSAGE: &str = \"Rotation must be in the range [0, 25]\";\nconst ALPHABET_LENGTH: u8 = b'z' - b'a' + 1;\n\n/// Encrypts a given text using the Caesar cipher technique.\n///\n/// In cryptography, a Caesar cipher, also known as Caesar's cipher, the shift cipher, Caesar's code,\n/// or Caesar shift, is one of the simplest and most widely known encryption techniques.\n/// It is a type of substitution cipher in which each letter in the plaintext is replaced by a letter\n/// some fixed number of positions down the alphabet.\n///\n/// # Arguments\n///\n/// * `text` - The text to be encrypted.\n/// * `rotation` - The number of rotations (shift) to be applied. It should be within the range [0, 25].\n///\n/// # Returns\n///\n/// Returns a `Result` containing the encrypted string if successful, or an error message if the rotation\n/// is out of the valid range.\n///\n/// # Errors\n///\n/// Returns an error if the rotation value is out of the valid range [0, 25]\npub fn caesar(text: &str, rotation: isize) -> Result<String, &'static str> {\n    if !(0..ALPHABET_LENGTH as isize).contains(&rotation) {\n        return Err(ERROR_MESSAGE);\n    }\n\n    let result = text\n        .chars()\n        .map(|c| {\n            if c.is_ascii_alphabetic() {\n                shift_char(c, rotation)\n            } else {\n                c\n            }\n        })\n        .collect();\n\n    Ok(result)\n}\n\n/// Shifts a single ASCII alphabetic character by a specified number of positions in the alphabet.\n///\n/// # Arguments\n///\n/// * `c` - The ASCII alphabetic character to be shifted.\n/// * `rotation` - The number of positions to shift the character. Should be within the range [0, 25].\n///\n/// # Returns\n///\n/// Returns the shifted ASCII alphabetic character.\nfn shift_char(c: char, rotation: isize) -> char {\n    let first = if c.is_ascii_lowercase() { b'a' } else { b'A' };\n    let rotation = rotation as u8; // Safe cast as rotation is within [0, 25]\n\n    (((c as u8 - first) + rotation) % ALPHABET_LENGTH + first) as char\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_caesar_happy_path {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (text, rotation, expected) = $test_case;\n                    assert_eq!(caesar(&text, rotation).unwrap(), expected);\n\n                    let backward_rotation = if rotation == 0 { 0 } else { ALPHABET_LENGTH as isize - rotation };\n                    assert_eq!(caesar(&expected, backward_rotation).unwrap(), text);\n                }\n            )*\n        };\n    }\n\n    macro_rules! test_caesar_error_cases {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (text, rotation) = $test_case;\n                    assert_eq!(caesar(&text, rotation), Err(ERROR_MESSAGE));\n                }\n            )*\n        };\n    }\n\n    #[test]\n    fn alphabet_length_should_be_26() {\n        assert_eq!(ALPHABET_LENGTH, 26);\n    }\n\n    test_caesar_happy_path! {\n        empty_text: (\"\", 13, \"\"),\n        rot_13: (\"rust\", 13, \"ehfg\"),\n        unicode: (\"attack at dawn 攻\", 5, \"fyyfhp fy ifbs 攻\"),\n        rotation_within_alphabet_range: (\"Hello, World!\", 3, \"Khoor, Zruog!\"),\n        no_rotation: (\"Hello, World!\", 0, \"Hello, World!\"),\n        rotation_at_alphabet_end: (\"Hello, World!\", 25, \"Gdkkn, Vnqkc!\"),\n        longer: (\"The quick brown fox jumps over the lazy dog.\", 5, \"Ymj vznhp gwtbs ktc ozrux tajw ymj qfed itl.\"),\n        non_alphabetic_characters: (\"12345!@#$%\", 3, \"12345!@#$%\"),\n        uppercase_letters: (\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\", 1, \"BCDEFGHIJKLMNOPQRSTUVWXYZA\"),\n        mixed_case: (\"HeLlO WoRlD\", 7, \"OlSsV DvYsK\"),\n        with_whitespace: (\"Hello, World!\", 13, \"Uryyb, Jbeyq!\"),\n        with_special_characters: (\"Hello!@#$%^&*()_+World\", 4, \"Lipps!@#$%^&*()_+Asvph\"),\n        with_numbers: (\"Abcd1234XYZ\", 10, \"Klmn1234HIJ\"),\n    }\n\n    test_caesar_error_cases! {\n        negative_rotation: (\"Hello, World!\", -5),\n        empty_input_negative_rotation: (\"\", -1),\n        empty_input_large_rotation: (\"\", 27),\n        large_rotation: (\"Large rotation\", 139),\n    }\n}\n"
  },
  {
    "path": "src/ciphers/chacha.rs",
    "content": "macro_rules! quarter_round {\n    ($a:expr,$b:expr,$c:expr,$d:expr) => {\n        $a = $a.wrapping_add($b);\n        $d = ($d ^ $a).rotate_left(16);\n        $c = $c.wrapping_add($d);\n        $b = ($b ^ $c).rotate_left(12);\n        $a = $a.wrapping_add($b);\n        $d = ($d ^ $a).rotate_left(8);\n        $c = $c.wrapping_add($d);\n        $b = ($b ^ $c).rotate_left(7);\n    };\n}\n\n#[allow(dead_code)]\n// \"expand 32-byte k\", written in little-endian order\npub const C: [u32; 4] = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574];\n\n/// ChaCha20 implementation based on RFC8439\n///\n/// ChaCha20 is a stream cipher developed independently by Daniel J. Bernstein.\\\n/// To use it, the `chacha20` function should be called with appropriate\n/// parameters and the output of the function should be XORed with plain text.\n///\n/// `chacha20` function takes as input an array of 16 32-bit integers (512 bits)\n/// of which 128 bits is the constant 'expand 32-byte k', 256 bits is the key,\n/// and 128 bits are nonce and counter. According to RFC8439, the nonce should\n/// be 96 bits long, which leaves 32 bits for the counter. Given that the block\n/// length is 512 bits, this leaves enough counter values to encrypt 256GB of\n/// data.\n///\n/// The 16 input numbers can be thought of as the elements of a 4x4 matrix like\n/// the one below, on which we do the main operations of the cipher.\n///\n/// ```text\n/// +----+----+----+----+\n/// | 00 | 01 | 02 | 03 |\n/// +----+----+----+----+\n/// | 04 | 05 | 06 | 07 |\n/// +----+----+----+----+\n/// | 08 | 09 | 10 | 11 |\n/// +----+----+----+----+\n/// | 12 | 13 | 14 | 15 |\n/// +----+----+----+----+\n/// ```\n///\n/// As per the diagram below, `input[0, 1, 2, 3]` are the constants mentioned\n/// above, `input[4..=11]` is filled with the key, and `input[6..=9]` should be\n/// filled with nonce and counter values. The output of the function is stored\n/// in `output` variable and can be XORed with the plain text to produce the\n/// cipher text.\n///\n/// ```text\n/// +------+------+------+------+\n/// |      |      |      |      |\n/// | C[0] | C[1] | C[2] | C[3] |\n/// |      |      |      |      |\n/// +------+------+------+------+\n/// |      |      |      |      |\n/// | key0 | key1 | key2 | key3 |\n/// |      |      |      |      |\n/// +------+------+------+------+\n/// |      |      |      |      |\n/// | key4 | key5 | key6 | key7 |\n/// |      |      |      |      |\n/// +------+------+------+------+\n/// |      |      |      |      |\n/// | ctr0 | no.0 | no.1 | no.2 |\n/// |      |      |      |      |\n/// +------+------+------+------+\n/// ```\n///\n/// Note that the constants, the key, and the nonce should be written in\n/// little-endian order, meaning that for example if the key is 01:02:03:04\n/// (in hex), it corresponds to the integer `0x04030201`. It is important to\n/// know that the hex value of the counter is meaningless, and only its integer\n/// value matters, and it should start with (for example) `0x00000000`, and then\n/// `0x00000001` and so on until `0xffffffff`. Keep in mind that as soon as we get\n/// from bytes to words, we stop caring about their representation in memory,\n/// and we only need the math to be correct.\n///\n/// The output of the function can be used without any change, as long as the\n/// plain text has the same endianness. For example if the plain text is\n/// \"hello world\", and the first word of the output is `0x01020304`, then the\n/// first byte of plain text ('h') should be XORed with the least-significant\n/// byte of `0x01020304`, which is `0x04`.\npub fn chacha20(input: &[u32; 16], output: &mut [u32; 16]) {\n    output.copy_from_slice(&input[..]);\n    for _ in 0..10 {\n        // Odd round (column round)\n        quarter_round!(output[0], output[4], output[8], output[12]); //  column 1\n        quarter_round!(output[1], output[5], output[9], output[13]); //  column 2\n        quarter_round!(output[2], output[6], output[10], output[14]); // column 3\n        quarter_round!(output[3], output[7], output[11], output[15]); // column 4\n\n        // Even round (diagonal round)\n        quarter_round!(output[0], output[5], output[10], output[15]); // diag 1\n        quarter_round!(output[1], output[6], output[11], output[12]); // diag 2\n        quarter_round!(output[2], output[7], output[8], output[13]); //  diag 3\n        quarter_round!(output[3], output[4], output[9], output[14]); //  diag 4\n    }\n    for (a, &b) in output.iter_mut().zip(input.iter()) {\n        *a = a.wrapping_add(b);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::fmt::Write;\n\n    fn output_hex(inp: &[u32; 16]) -> String {\n        let mut res = String::new();\n        res.reserve(512 / 4);\n        for &x in inp {\n            write!(&mut res, \"{x:08x}\").unwrap();\n        }\n        res\n    }\n\n    #[test]\n    // test vector 1\n    fn basic_tv1() {\n        let mut inp = [0u32; 16];\n        let mut out = [0u32; 16];\n        inp[0] = C[0];\n        inp[1] = C[1];\n        inp[2] = C[2];\n        inp[3] = C[3];\n        inp[4] = 0x03020100; // The key is 00:01:02:..:1f (hex)\n        inp[5] = 0x07060504;\n        inp[6] = 0x0b0a0908;\n        inp[7] = 0x0f0e0d0c;\n        inp[8] = 0x13121110;\n        inp[9] = 0x17161514;\n        inp[10] = 0x1b1a1918;\n        inp[11] = 0x1f1e1d1c;\n        inp[12] = 0x00000001; // The value of counter is 1 (an integer). Nonce:\n        inp[13] = 0x09000000; // 00:00:00:09\n        inp[14] = 0x4a000000; // 00:00:00:4a\n        inp[15] = 0x00000000; // 00:00:00:00\n        chacha20(&inp, &mut out);\n        assert_eq!(\n            output_hex(&out),\n            concat!(\n                \"e4e7f11015593bd11fdd0f50c47120a3c7f4d1c70368c0339aaa22044e6cd4c3\",\n                \"466482d209aa9f0705d7c214a2028bd9d19c12b5b94e16dee883d0cb4e3c50a2\"\n            )\n        );\n    }\n}\n"
  },
  {
    "path": "src/ciphers/diffie_hellman.rs",
    "content": "// Based on the TheAlgorithms/Python\n// RFC 3526 - More Modular Exponential (MODP) Diffie-Hellman groups for\n// Internet Key Exchange (IKE) https://tools.ietf.org/html/rfc3526\n\nuse num_bigint::BigUint;\nuse num_traits::{Num, Zero};\nuse std::{\n    collections::HashMap,\n    sync::LazyLock,\n    time::{SystemTime, UNIX_EPOCH},\n};\n\n// A map of predefined prime numbers for different bit lengths, as specified in RFC 3526\nstatic PRIMES: LazyLock<HashMap<u8, BigUint>> = LazyLock::new(|| {\n    let mut m: HashMap<u8, BigUint> = HashMap::new();\n    m.insert(\n        // 1536-bit\n        5,\n        BigUint::parse_bytes(\n            b\"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1\\\n                29024E088A67CC74020BBEA63B139B22514A08798E3404DD\\\n                EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245\\\n                E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED\\\n                EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D\\\n                C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F\\\n                83655D23DCA3AD961C62F356208552BB9ED529077096966D\\\n                670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF\",\n            16,\n        )\n        .unwrap(),\n    );\n    m.insert(\n        // 2048-bit\n        14,\n        BigUint::parse_bytes(\n            b\"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1\\\n            29024E088A67CC74020BBEA63B139B22514A08798E3404DD\\\n            EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245\\\n            E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED\\\n            EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D\\\n            C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F\\\n            83655D23DCA3AD961C62F356208552BB9ED529077096966D\\\n            670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B\\\n            E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9\\\n            DE2BCBF6955817183995497CEA956AE515D2261898FA0510\\\n            15728E5A8AACAA68FFFFFFFFFFFFFFFF\",\n            16,\n        )\n        .unwrap(),\n    );\n\n    m.insert(\n        // 3072-bit\n        15,\n        BigUint::parse_bytes(\n            b\"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1\\\n            29024E088A67CC74020BBEA63B139B22514A08798E3404DD\\\n            EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245\\\n            E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED\\\n            EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D\\\n            C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F\\\n            83655D23DCA3AD961C62F356208552BB9ED529077096966D\\\n            670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B\\\n            E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9\\\n            DE2BCBF6955817183995497CEA956AE515D2261898FA0510\\\n            15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64\\\n            ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7\\\n            ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B\\\n            F12FFA06D98A0864D87602733EC86A64521F2B18177B200C\\\n            BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31\\\n            43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF\",\n            16,\n        )\n        .unwrap(),\n    );\n    m.insert(\n        // 4096-bit\n        16,\n        BigUint::parse_bytes(\n            b\"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1\\\n            29024E088A67CC74020BBEA63B139B22514A08798E3404DD\\\n            EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245\\\n            E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED\\\n            EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D\\\n            C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F\\\n            83655D23DCA3AD961C62F356208552BB9ED529077096966D\\\n            670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B\\\n            E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9\\\n            DE2BCBF6955817183995497CEA956AE515D2261898FA0510\\\n            15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64\\\n            ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7\\\n            ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B\\\n            F12FFA06D98A0864D87602733EC86A64521F2B18177B200C\\\n            BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31\\\n            43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7\\\n            88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA\\\n            2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6\\\n            287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED\\\n            1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9\\\n            93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199\\\n            FFFFFFFFFFFFFFFF\",\n            16,\n        )\n        .unwrap(),\n    );\n    m.insert(\n        // 6144-bit\n        17,\n        BigUint::parse_bytes(\n            b\"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08\\\n             8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B\\\n             302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9\\\n             A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6\\\n             49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8\\\n             FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D\\\n             670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C\\\n             180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718\\\n             3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D\\\n             04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D\\\n             B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226\\\n             1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C\\\n             BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC\\\n             E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26\\\n             99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB\\\n             04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2\\\n             233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127\\\n             D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492\\\n             36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406\\\n             AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918\\\n             DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151\\\n             2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03\\\n             F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F\\\n             BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA\\\n             CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B\\\n             B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632\\\n             387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E\\\n             6DCC4024FFFFFFFFFFFFFFFF\",\n            16,\n        )\n        .unwrap(),\n    );\n\n    m.insert(\n        // 8192-bit\n        18,\n        BigUint::parse_bytes(\n            b\"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1\\\n               29024E088A67CC74020BBEA63B139B22514A08798E3404DD\\\n               EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245\\\n               E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED\\\n               EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D\\\n               C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F\\\n               83655D23DCA3AD961C62F356208552BB9ED529077096966D\\\n               670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B\\\n               E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9\\\n               DE2BCBF6955817183995497CEA956AE515D2261898FA0510\\\n               15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64\\\n               ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7\\\n               ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B\\\n               F12FFA06D98A0864D87602733EC86A64521F2B18177B200C\\\n               BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31\\\n               43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7\\\n               88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA\\\n               2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6\\\n               287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED\\\n               1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9\\\n               93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492\\\n               36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD\\\n               F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831\\\n               179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B\\\n               DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF\\\n               5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6\\\n               D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3\\\n               23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA\\\n               CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328\\\n               06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C\\\n               DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE\\\n               12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4\\\n               38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300\\\n               741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568\\\n               3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9\\\n               22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B\\\n               4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A\\\n               062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36\\\n               4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1\\\n               B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92\\\n               4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47\\\n               9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71\\\n               60C980DD98EDD3DFFFFFFFFFFFFFFFFF\",\n            16,\n        )\n        .unwrap(),\n    );\n    m\n});\n\n/// Generating random number, should use num_bigint::RandomBits if possible.\nfn rand() -> usize {\n    SystemTime::now()\n        .duration_since(UNIX_EPOCH)\n        .unwrap()\n        .subsec_nanos() as usize\n}\n\npub struct DiffieHellman {\n    prime: BigUint,\n    private_key: BigUint,\n    public_key: BigUint,\n    generator: u8,\n}\n\nimpl DiffieHellman {\n    // Diffie-Hellman key exchange algorithm is based on the following mathematical concepts:\n\n    //  - A large prime number p (known as the prime modulus) is chosen and shared by both parties.\n\n    //  - A base number g (known as the generator) is chosen and shared by both parties.\n\n    //  - Each party generates a private key a or b (which are secret and only known to that party) and calculates a corresponding public key A or B using the following formulas:\n    //          - A = g^a mod p\n    //          - B = g^b mod p\n\n    //  - Each party then exchanges their public keys with each other.\n\n    //  - Each party then calculates the shared secret key s using the following formula:\n    //          - s = B^a mod p or s = A^b mod p\n\n    // Both parties now have the same shared secret key s which can be used for encryption or authentication.\n\n    pub fn new(group: Option<u8>) -> Self {\n        let _group = group.unwrap_or(14);\n\n        if !PRIMES.contains_key(&_group) {\n            panic!(\"group not in primes\")\n        }\n\n        // generate private key\n        let private_key: BigUint = BigUint::from(rand());\n\n        Self {\n            prime: PRIMES[&_group].clone(),\n            private_key,\n            generator: 2, // the generator is 2 for all the primes if this would not be the case it can be added to hashmap\n            public_key: BigUint::default(),\n        }\n    }\n\n    /// get private key as hexadecimal String\n    pub fn get_private_key(&self) -> String {\n        self.private_key.to_str_radix(16)\n    }\n\n    /// Generate public key A = g**a mod p\n    pub fn generate_public_key(&mut self) -> String {\n        self.public_key = BigUint::from(self.generator).modpow(&self.private_key, &self.prime);\n        self.public_key.to_str_radix(16)\n    }\n\n    pub fn is_valid_public_key(&self, key_str: &str) -> bool {\n        // the unwrap_or_else will make sure it is false, because 2 <= 0 and therefor False is returned\n        let key = BigUint::from_str_radix(key_str, 16)\n            .unwrap_or_else(|_| BigUint::parse_bytes(b\"0\", 16).unwrap());\n\n        // Check if the other public key is valid based on NIST SP800-56\n        if BigUint::from(2_u8) <= key\n            && key <= &self.prime - BigUint::from(2_u8)\n            && !key\n                .modpow(\n                    &((&self.prime - BigUint::from(1_u8)) / BigUint::from(2_u8)),\n                    &self.prime,\n                )\n                .is_zero()\n        {\n            return true;\n        }\n        false\n    }\n\n    /// Generate the shared key\n    pub fn generate_shared_key(self, other_key_str: &str) -> Option<String> {\n        let other_key = BigUint::from_str_radix(other_key_str, 16)\n            .unwrap_or_else(|_| BigUint::parse_bytes(b\"0\", 16).unwrap());\n        if !self.is_valid_public_key(&other_key.to_str_radix(16)) {\n            return None;\n        }\n\n        let shared_key = other_key.modpow(&self.private_key, &self.prime);\n        Some(shared_key.to_str_radix(16))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn verify_invalid_pub_key() {\n        let diffie = DiffieHellman::new(Some(14));\n        assert!(!diffie.is_valid_public_key(\"0000\"));\n    }\n\n    #[test]\n    fn verify_valid_pub_key() {\n        let diffie = DiffieHellman::new(Some(14));\n        assert!(diffie.is_valid_public_key(\"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245\"));\n    }\n\n    #[test]\n    fn verify_invalid_pub_key_same_as_prime() {\n        let diffie = DiffieHellman::new(Some(14));\n        assert!(!diffie.is_valid_public_key(\n            \"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1\\\n        29024E088A67CC74020BBEA63B139B22514A08798E3404DD\\\n        EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245\\\n        E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED\\\n        EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D\\\n        C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F\\\n        83655D23DCA3AD961C62F356208552BB9ED529077096966D\\\n        670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B\\\n        E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9\\\n        DE2BCBF6955817183995497CEA956AE515D2261898FA0510\\\n        15728E5A8AACAA68FFFFFFFFFFFFFFFF\"\n        ));\n    }\n\n    #[test]\n    fn verify_key_exchange() {\n        let mut alice = DiffieHellman::new(Some(16));\n        let mut bob = DiffieHellman::new(Some(16));\n\n        // Private key not used, showed for illustrative purpose\n        let _alice_private = alice.get_private_key();\n        let alice_public = alice.generate_public_key();\n\n        // Private key not used, showed for illustrative purpose\n        let _bob_private = bob.get_private_key();\n        let bob_public = bob.generate_public_key();\n\n        // generating shared key using the struct implemenations\n        let alice_shared = alice.generate_shared_key(bob_public.as_str()).unwrap();\n        let bob_shared = bob.generate_shared_key(alice_public.as_str()).unwrap();\n        assert_eq!(alice_shared, bob_shared);\n    }\n}\n"
  },
  {
    "path": "src/ciphers/hashing_traits.rs",
    "content": "pub trait Hasher<const DIGEST_BYTES: usize> {\n    /// return a new instance with default parameters\n    fn new_default() -> Self;\n\n    /// Add new data\n    fn update(&mut self, data: &[u8]);\n\n    /// Returns the hash of current data. If it is necessary does finalization\n    /// work on the instance, thus it may no longer make sense to do `update`\n    /// after calling this.\n    fn get_hash(&mut self) -> [u8; DIGEST_BYTES];\n}\n\n/// HMAC based on RFC2104, applicable to many cryptographic hash functions\npub struct HMAC<const KEY_BYTES: usize, const DIGEST_BYTES: usize, H: Hasher<DIGEST_BYTES>> {\n    pub inner_internal_state: H,\n    pub outer_internal_state: H,\n}\n\nimpl<const KEY_BYTES: usize, const DIGEST_BYTES: usize, H: Hasher<DIGEST_BYTES>>\n    HMAC<KEY_BYTES, DIGEST_BYTES, H>\n{\n    pub fn new_default() -> Self {\n        HMAC {\n            inner_internal_state: H::new_default(),\n            outer_internal_state: H::new_default(),\n        }\n    }\n\n    /// Note that `key` must be no longer than `KEY_BYTES`. According to RFC,\n    /// if it is so, you should replace it with its hash. We do not do this\n    /// automatically due to fear of `DIGEST_BYTES` not being the same as\n    /// `KEY_BYTES` or even being longer than it\n    pub fn add_key(&mut self, key: &[u8]) -> Result<(), &'static str> {\n        match key.len().cmp(&KEY_BYTES) {\n            std::cmp::Ordering::Less | std::cmp::Ordering::Equal => {\n                let mut tmp_key = [0u8; KEY_BYTES];\n                for (d, s) in tmp_key.iter_mut().zip(key.iter()) {\n                    *d = *s;\n                }\n                // key ^ 0x363636.. should be used as inner key\n                for b in tmp_key.iter_mut() {\n                    *b ^= 0x36;\n                }\n                self.inner_internal_state.update(&tmp_key);\n                // key ^ 0x5c5c5c.. should be used as outer key, but the key is\n                // already XORed with 0x363636.. , so it must now be XORed with\n                // 0x6a6a6a..\n                for b in tmp_key.iter_mut() {\n                    *b ^= 0x6a;\n                }\n                self.outer_internal_state.update(&tmp_key);\n                Ok(())\n            }\n            _ => Err(\"Key is longer than `KEY_BYTES`.\"),\n        }\n    }\n\n    pub fn update(&mut self, data: &[u8]) {\n        self.inner_internal_state.update(data);\n    }\n\n    pub fn finalize(&mut self) -> [u8; DIGEST_BYTES] {\n        self.outer_internal_state\n            .update(&self.inner_internal_state.get_hash());\n        self.outer_internal_state.get_hash()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::super::sha256::tests::get_hash_string;\n    use super::super::SHA256;\n    use super::HMAC;\n\n    #[test]\n    fn sha256_basic() {\n        // To test this, use the following command on linux:\n        // echo -n \"Hello World\" | openssl sha256 -hex -mac HMAC -macopt hexkey:\"deadbeef\"\n        let mut hmac: HMAC<64, 32, SHA256> = HMAC::new_default();\n        hmac.add_key(&[0xde, 0xad, 0xbe, 0xef]).unwrap();\n        hmac.update(b\"Hello World\");\n        let hash = hmac.finalize();\n        assert_eq!(\n            get_hash_string(&hash),\n            \"f585fc4536e8e7f378437465b65b6c2eb79036409b18a7d28b6d4c46d3a156f8\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/ciphers/hill_cipher.rs",
    "content": "//! Hill Cipher\n//!\n//! The Hill Cipher is a polygraphic substitution cipher based on linear algebra.\n//!\n//! # Algorithm\n//!\n//! Let the order of the encryption key be N (as it is a square matrix).\n//! The text is divided into batches of length N and converted to numerical vectors\n//! by a simple mapping starting with A=0 and so on.\n//!\n//! The key matrix is multiplied with the batch vector to obtain the encoded vector.\n//! After multiplication, modular 36 calculations map results to alphanumerics.\n//!\n//! For decryption, the modular inverse of the encryption key is computed and used\n//! with the same process to recover the original message.\n//!\n//! # Constraints\n//!\n//! The determinant of the encryption key matrix must be coprime with 36.\n//!\n//! # Note\n//!\n//! - Only alphanumeric characters are considered\n//! - Text is padded to a multiple of the key size using the last character\n//! - Decrypted text may have padding characters at the end\n//!\n//! # References\n//!\n//! - <https://apprendre-en-ligne.net/crypto/hill/Hillciph.pdf>\n//! - <https://www.youtube.com/watch?v=kfmNeskzs2o>\n\nconst KEY_STRING: &str = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\";\nconst MODULUS: i32 = 36;\n\n/// Hill Cipher implementation\npub struct HillCipher {\n    encrypt_key: Vec<Vec<i32>>,\n    break_key: usize,\n}\n\nimpl HillCipher {\n    /// Creates a new Hill Cipher with the given encryption key matrix.\n    ///\n    /// # Arguments\n    ///\n    /// * `encrypt_key` - An NxN square matrix\n    ///\n    /// # Returns\n    ///\n    /// `Err` if the matrix is invalid or determinant is not coprime with 36\n    pub fn new(mut encrypt_key: Vec<Vec<i32>>) -> Result<Self, String> {\n        if encrypt_key.is_empty() {\n            return Err(\"Encryption key cannot be empty\".to_string());\n        }\n\n        let n = encrypt_key.len();\n\n        // Check if matrix is square\n        for row in &encrypt_key {\n            if row.len() != n {\n                return Err(\"Encryption key must be a square matrix\".to_string());\n            }\n        }\n\n        // Apply modulus to all elements\n        for row in &mut encrypt_key {\n            for val in row {\n                *val = val.rem_euclid(MODULUS);\n            }\n        }\n\n        let break_key = n;\n        let cipher = HillCipher {\n            encrypt_key,\n            break_key,\n        };\n\n        cipher.check_determinant()?;\n        Ok(cipher)\n    }\n\n    fn replace_letter(&self, letter: char) -> Option<usize> {\n        KEY_STRING.chars().position(|c| c == letter)\n    }\n\n    fn replace_digit(&self, num: i32) -> char {\n        KEY_STRING.chars().nth(num as usize).unwrap_or('A')\n    }\n\n    fn determinant(matrix: &[Vec<i32>]) -> i32 {\n        let n = matrix.len();\n\n        if n == 1 {\n            return matrix[0][0];\n        }\n\n        if n == 2 {\n            return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];\n        }\n\n        let mut det = 0;\n        for col in 0..n {\n            let minor = Self::get_minor(matrix, 0, col);\n            let sign = if col % 2 == 0 { 1 } else { -1 };\n            det += sign * matrix[0][col] * Self::determinant(&minor);\n        }\n\n        det\n    }\n\n    fn get_minor(matrix: &[Vec<i32>], row: usize, col: usize) -> Vec<Vec<i32>> {\n        matrix\n            .iter()\n            .enumerate()\n            .filter(|(i, _)| *i != row)\n            .map(|(_, r)| {\n                r.iter()\n                    .enumerate()\n                    .filter(|(j, _)| *j != col)\n                    .map(|(_, &val)| val)\n                    .collect()\n            })\n            .collect()\n    }\n\n    fn cofactor_matrix(matrix: &[Vec<i32>]) -> Vec<Vec<i32>> {\n        let n = matrix.len();\n        let mut cofactors = vec![vec![0; n]; n];\n\n        for i in 0..n {\n            for j in 0..n {\n                let minor = Self::get_minor(matrix, i, j);\n                let sign = if (i + j) % 2 == 0 { 1 } else { -1 };\n                cofactors[i][j] = sign * Self::determinant(&minor);\n            }\n        }\n\n        cofactors\n    }\n\n    fn transpose(matrix: &[Vec<i32>]) -> Vec<Vec<i32>> {\n        let n = matrix.len();\n        let mut result = vec![vec![0; n]; n];\n\n        for i in 0..n {\n            for j in 0..n {\n                result[j][i] = matrix[i][j];\n            }\n        }\n\n        result\n    }\n\n    fn mod_inverse(a: i32, m: i32) -> Option<i32> {\n        let a = a.rem_euclid(m);\n        (1..m).find(|&x| (a * x) % m == 1)\n    }\n\n    fn gcd(mut a: i32, mut b: i32) -> i32 {\n        a = a.abs();\n        b = b.abs();\n\n        while b != 0 {\n            let temp = b;\n            b = a % b;\n            a = temp;\n        }\n\n        a\n    }\n\n    fn check_determinant(&self) -> Result<(), String> {\n        let det = Self::determinant(&self.encrypt_key);\n        let det_mod = det.rem_euclid(MODULUS);\n\n        if Self::gcd(det_mod, MODULUS) != 1 {\n            return Err(format!(\n                \"Determinant modular {MODULUS} of encryption key ({det_mod}) is not coprime w.r.t {MODULUS}. Try another key.\"\n            ));\n        }\n\n        Ok(())\n    }\n\n    fn process_text(&self, text: &str) -> String {\n        let mut chars: Vec<char> = text\n            .to_uppercase()\n            .chars()\n            .filter(|c| KEY_STRING.contains(*c))\n            .collect();\n\n        if chars.is_empty() {\n            return String::new();\n        }\n\n        let last_char = *chars.last().unwrap();\n        while !chars.len().is_multiple_of(self.break_key) {\n            chars.push(last_char);\n        }\n\n        chars.into_iter().collect()\n    }\n\n    /// Encrypts the given text using the Hill cipher.\n    pub fn encrypt(&self, text: &str) -> String {\n        let processed = self.process_text(text);\n        let mut encrypted = String::new();\n\n        for i in (0..processed.len()).step_by(self.break_key) {\n            let batch: String = processed.chars().skip(i).take(self.break_key).collect();\n            let vec: Vec<i32> = batch\n                .chars()\n                .map(|c| self.replace_letter(c).unwrap() as i32)\n                .collect();\n\n            let mut encrypted_vec = vec![0; self.break_key];\n            for row in 0..self.break_key {\n                let mut sum = 0;\n                for col in 0..self.break_key {\n                    sum += self.encrypt_key[row][col] * vec[col];\n                }\n                encrypted_vec[row] = sum.rem_euclid(MODULUS);\n            }\n\n            for &num in &encrypted_vec {\n                encrypted.push(self.replace_digit(num));\n            }\n        }\n\n        encrypted\n    }\n\n    fn make_decrypt_key(&self) -> Vec<Vec<i32>> {\n        let det = Self::determinant(&self.encrypt_key);\n        let det_mod = det.rem_euclid(MODULUS);\n        let det_inv = Self::mod_inverse(det_mod, MODULUS)\n            .expect(\"Determinant should be coprime with modulus\");\n\n        let cofactors = Self::cofactor_matrix(&self.encrypt_key);\n        let adjugate = Self::transpose(&cofactors);\n\n        let n = self.break_key;\n        let mut decrypt_key = vec![vec![0; n]; n];\n\n        for i in 0..n {\n            for j in 0..n {\n                decrypt_key[i][j] = (det_inv * adjugate[i][j]).rem_euclid(MODULUS);\n            }\n        }\n\n        decrypt_key\n    }\n\n    /// Decrypts the given text using the Hill cipher.\n    pub fn decrypt(&self, text: &str) -> String {\n        let decrypt_key = self.make_decrypt_key();\n        let processed = self.process_text(text);\n        let mut decrypted = String::new();\n\n        for i in (0..processed.len()).step_by(self.break_key) {\n            let batch: String = processed.chars().skip(i).take(self.break_key).collect();\n            let vec: Vec<i32> = batch\n                .chars()\n                .map(|c| self.replace_letter(c).unwrap() as i32)\n                .collect();\n\n            let mut decrypted_vec = vec![0; self.break_key];\n            for row in 0..self.break_key {\n                let mut sum = 0;\n                for col in 0..self.break_key {\n                    sum += decrypt_key[row][col] * vec[col];\n                }\n                decrypted_vec[row] = sum.rem_euclid(MODULUS);\n            }\n\n            for &num in &decrypted_vec {\n                decrypted.push(self.replace_digit(num));\n            }\n        }\n\n        decrypted\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_encrypt() {\n        let key = vec![vec![2, 5], vec![1, 6]];\n        let cipher = HillCipher::new(key).unwrap();\n        assert_eq!(cipher.encrypt(\"testing hill cipher\"), \"WHXYJOLM9C6XT085LL\");\n        assert_eq!(cipher.encrypt(\"hello\"), \"85FF00\");\n    }\n\n    #[test]\n    fn test_decrypt() {\n        let key = vec![vec![2, 5], vec![1, 6]];\n        let cipher = HillCipher::new(key).unwrap();\n        assert_eq!(cipher.decrypt(\"WHXYJOLM9C6XT085LL\"), \"TESTINGHILLCIPHERR\");\n        assert_eq!(cipher.decrypt(\"85FF00\"), \"HELLOO\");\n    }\n\n    #[test]\n    fn test_encrypt_decrypt_roundtrip() {\n        let key = vec![vec![2, 5], vec![1, 6]];\n        let cipher = HillCipher::new(key).unwrap();\n        let original = \"HELLO WORLD\";\n        let encrypted = cipher.encrypt(original);\n        let decrypted = cipher.decrypt(&encrypted);\n\n        // Note: decrypted might have padding\n        assert!(decrypted.starts_with(\"HELLOWORLD\"));\n    }\n\n    #[test]\n    fn test_process_text() {\n        let key = vec![vec![2, 5], vec![1, 6]];\n        let cipher = HillCipher::new(key).unwrap();\n        assert_eq!(\n            cipher.process_text(\"Testing Hill Cipher\"),\n            \"TESTINGHILLCIPHERR\"\n        );\n        assert_eq!(cipher.process_text(\"hello\"), \"HELLOO\");\n    }\n\n    #[test]\n    fn test_replace_letter() {\n        let key = vec![vec![2, 5], vec![1, 6]];\n        let cipher = HillCipher::new(key).unwrap();\n        assert_eq!(cipher.replace_letter('T'), Some(19));\n        assert_eq!(cipher.replace_letter('0'), Some(26));\n        assert_eq!(cipher.replace_letter('A'), Some(0));\n    }\n\n    #[test]\n    fn test_replace_digit() {\n        let key = vec![vec![2, 5], vec![1, 6]];\n        let cipher = HillCipher::new(key).unwrap();\n        assert_eq!(cipher.replace_digit(19), 'T');\n        assert_eq!(cipher.replace_digit(26), '0');\n        assert_eq!(cipher.replace_digit(0), 'A');\n    }\n\n    #[test]\n    fn test_invalid_determinant() {\n        // Matrix with determinant not coprime with 36\n        let key = vec![vec![2, 4], vec![1, 2]]; // det = 0\n        assert!(HillCipher::new(key).is_err());\n    }\n\n    #[test]\n    fn test_3x3_matrix() {\n        // Matrix with determinant = 1 (coprime with 36)\n        let key = vec![vec![1, 2, 3], vec![0, 1, 4], vec![5, 6, 0]];\n        let cipher = HillCipher::new(key).unwrap();\n        let encrypted = cipher.encrypt(\"ACT\");\n        let decrypted = cipher.decrypt(&encrypted);\n        assert_eq!(decrypted, \"ACT\");\n    }\n\n    #[test]\n    fn test_gcd() {\n        assert_eq!(HillCipher::gcd(48, 18), 6);\n        assert_eq!(HillCipher::gcd(7, 36), 1);\n        assert_eq!(HillCipher::gcd(12, 36), 12);\n    }\n\n    #[test]\n    fn test_mod_inverse() {\n        assert_eq!(HillCipher::mod_inverse(7, 36), Some(31));\n        assert_eq!(HillCipher::mod_inverse(1, 36), Some(1));\n        assert_eq!(HillCipher::mod_inverse(2, 36), None); // 2 and 36 are not coprime\n    }\n}\n"
  },
  {
    "path": "src/ciphers/kernighan.rs",
    "content": "pub fn kernighan(n: u32) -> i32 {\n    let mut count = 0;\n    let mut n = n;\n\n    while n > 0 {\n        n = n & (n - 1);\n        count += 1;\n    }\n\n    count\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn count_set_bits() {\n        assert_eq!(kernighan(0b0000_0000_0000_0000_0000_0000_0000_1011), 3);\n        assert_eq!(kernighan(0b0000_0000_0000_0000_0000_0000_1000_0000), 1);\n        assert_eq!(kernighan(0b1111_1111_1111_1111_1111_1111_1111_1101), 31);\n    }\n}\n"
  },
  {
    "path": "src/ciphers/mod.rs",
    "content": "mod aes;\nmod affine_cipher;\nmod another_rot13;\nmod baconian_cipher;\nmod base16;\nmod base32;\nmod base64;\nmod base85;\nmod blake2b;\nmod caesar;\nmod chacha;\nmod diffie_hellman;\nmod hashing_traits;\nmod hill_cipher;\nmod kernighan;\nmod morse_code;\nmod polybius;\nmod rail_fence;\nmod rot13;\nmod rsa_cipher;\nmod salsa;\nmod sha256;\nmod sha3;\nmod tea;\nmod theoretical_rot13;\nmod transposition;\nmod trifid;\nmod vernam;\nmod vigenere;\nmod xor;\n\npub use self::aes::{aes_decrypt, aes_encrypt, AesKey};\npub use self::affine_cipher::{affine_decrypt, affine_encrypt, affine_generate_key};\npub use self::another_rot13::another_rot13;\npub use self::baconian_cipher::{baconian_decode, baconian_encode};\npub use self::base16::{base16_decode, base16_encode};\npub use self::base32::{base32_decode, base32_encode};\npub use self::base64::{base64_decode, base64_encode};\npub use self::base85::{base85_decode, base85_encode};\npub use self::blake2b::blake2b;\npub use self::caesar::caesar;\npub use self::chacha::chacha20;\npub use self::diffie_hellman::DiffieHellman;\npub use self::hashing_traits::Hasher;\npub use self::hashing_traits::HMAC;\npub use self::hill_cipher::HillCipher;\npub use self::kernighan::kernighan;\npub use self::morse_code::{decode, encode};\npub use self::polybius::{decode_ascii, encode_ascii};\npub use self::rail_fence::{rail_fence_decrypt, rail_fence_encrypt};\npub use self::rot13::rot13;\npub use self::rsa_cipher::{\n    decrypt, decrypt_text, encrypt, encrypt_text, generate_keypair, PrivateKey, PublicKey,\n};\npub use self::salsa::salsa20;\npub use self::sha256::SHA256;\npub use self::sha3::{sha3_224, sha3_256, sha3_384, sha3_512};\npub use self::tea::{tea_decrypt, tea_encrypt};\npub use self::theoretical_rot13::theoretical_rot13;\npub use self::transposition::transposition;\npub use self::trifid::{trifid_decrypt, trifid_encrypt};\npub use self::vernam::{vernam_decrypt, vernam_encrypt};\npub use self::vigenere::vigenere;\npub use self::xor::xor;\n"
  },
  {
    "path": "src/ciphers/morse_code.rs",
    "content": "use std::collections::HashMap;\nuse std::io;\n\nconst UNKNOWN_CHARACTER: &str = \"........\";\nconst _UNKNOWN_MORSE_CHARACTER: &str = \"_\";\n\npub fn encode(message: &str) -> String {\n    let dictionary = _morse_dictionary();\n    message\n        .chars()\n        .map(|char| char.to_uppercase().to_string())\n        .map(|letter| dictionary.get(letter.as_str()))\n        .map(|option| (*option.unwrap_or(&UNKNOWN_CHARACTER)).to_string())\n        .collect::<Vec<String>>()\n        .join(\" \")\n}\n\n// Declarative macro for creating readable map declarations, for more info see https://doc.rust-lang.org/book/ch19-06-macros.html\nmacro_rules! map {\n    ($($key:expr => $value:expr),* $(,)?) => {\n        std::iter::Iterator::collect(IntoIterator::into_iter([$(($key, $value),)*]))\n    };\n}\n\nfn _morse_dictionary() -> HashMap<&'static str, &'static str> {\n    map! {\n        \"A\" => \".-\",      \"B\" => \"-...\",    \"C\" => \"-.-.\",\n        \"D\" => \"-..\",     \"E\" => \".\",       \"F\" => \"..-.\",\n        \"G\" => \"--.\",     \"H\" => \"....\",    \"I\" => \"..\",\n        \"J\" => \".---\",    \"K\" => \"-.-\",     \"L\" => \".-..\",\n        \"M\" => \"--\",      \"N\" => \"-.\",      \"O\" => \"---\",\n        \"P\" => \".--.\",    \"Q\" => \"--.-\",    \"R\" => \".-.\",\n        \"S\" => \"...\",     \"T\" => \"-\",       \"U\" => \"..-\",\n        \"V\" => \"...-\",    \"W\" => \".--\",     \"X\" => \"-..-\",\n        \"Y\" => \"-.--\",    \"Z\" => \"--..\",\n\n        \"1\" => \".----\",   \"2\" => \"..---\",   \"3\" => \"...--\",\n        \"4\" => \"....-\",   \"5\" => \".....\",   \"6\" => \"-....\",\n        \"7\" => \"--...\",   \"8\" => \"---..\",   \"9\" => \"----.\",\n        \"0\" => \"-----\",\n\n        \"&\" => \".-...\",   \"@\" => \".--.-.\",  \":\" => \"---...\",\n        \",\" => \"--..--\",  \".\" => \".-.-.-\",  \"'\" => \".----.\",\n        \"\\\"\" => \".-..-.\", \"?\" => \"..--..\",  \"/\" => \"-..-.\",\n        \"=\" => \"-...-\",   \"+\" => \".-.-.\",   \"-\" => \"-....-\",\n        \"(\" => \"-.--.\",   \")\" => \"-.--.-\",  \" \" => \"/\",\n        \"!\" => \"-.-.--\",\n    }\n}\n\nfn _morse_to_alphanumeric_dictionary() -> HashMap<&'static str, &'static str> {\n    map! {\n        \".-\"   =>  \"A\",      \"-...\" => \"B\",    \"-.-.\" => \"C\",\n        \"-..\"  =>  \"D\",      \".\"    => \"E\",       \"..-.\" => \"F\",\n        \"--.\"  =>  \"G\",      \"....\" => \"H\",    \"..\" => \"I\",\n        \".---\" =>  \"J\",     \"-.-\" => \"K\",     \".-..\" => \"L\",\n        \"--\"   =>  \"M\",       \"-.\" => \"N\",      \"---\" => \"O\",\n        \".--.\" =>  \"P\",     \"--.-\" => \"Q\",    \".-.\" => \"R\",\n        \"...\"  =>  \"S\",      \"-\" => \"T\",       \"..-\" => \"U\",\n        \"...-\" =>  \"V\",     \".--\" => \"W\",     \"-..-\" => \"X\",\n        \"-.--\" =>  \"Y\",     \"--..\" => \"Z\",\n\n        \".----\" => \"1\",    \"..---\" => \"2\",   \"...--\" => \"3\",\n        \"....-\" => \"4\",    \".....\" => \"5\",   \"-....\" => \"6\",\n        \"--...\" => \"7\",    \"---..\" => \"8\",   \"----.\" => \"9\",\n        \"-----\" => \"0\",\n\n        \".-...\" => \"&\",    \".--.-.\" => \"@\",  \"---...\" => \":\",\n        \"--..--\" => \",\",   \".-.-.-\" => \".\",  \".----.\" => \"'\",\n        \".-..-.\" => \"\\\"\",  \"..--..\" => \"?\",  \"-..-.\" => \"/\",\n        \"-...-\" => \"=\",   \".-.-.\" => \"+\",   \"-....-\" => \"-\",\n        \"-.--.\" => \"(\",   \"-.--.-\" => \")\",  \"/\" => \" \",\n        \"-.-.--\" => \"!\",  \" \" => \" \",       \"\" => \"\"\n    }\n}\n\nfn _check_part(string: &str) -> bool {\n    for c in string.chars() {\n        match c {\n            '.' | '-' | ' ' => (),\n            _ => return false,\n        }\n    }\n    true\n}\n\nfn _check_all_parts(string: &str) -> bool {\n    string.split('/').all(_check_part)\n}\n\nfn _decode_token(string: &str) -> String {\n    (*_morse_to_alphanumeric_dictionary()\n        .get(string)\n        .unwrap_or(&_UNKNOWN_MORSE_CHARACTER))\n    .to_string()\n}\n\nfn _decode_part(string: &str) -> String {\n    string.split(' ').map(_decode_token).collect::<String>()\n}\n\n/// Convert morse code to ascii.\n///\n/// Given a morse code, return the corresponding message.\n/// If the code is invalid, the undecipherable part of the code is replaced by `_`.\npub fn decode(string: &str) -> Result<String, io::Error> {\n    if !_check_all_parts(string) {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            \"Invalid morse code\",\n        ));\n    }\n\n    let mut partitions: Vec<String> = vec![];\n\n    for part in string.split('/') {\n        partitions.push(_decode_part(part));\n    }\n\n    Ok(partitions.join(\" \"))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn encrypt_only_letters() {\n        let message = \"Hello Morse\";\n        let cipher = encode(message);\n        assert_eq!(\n            cipher,\n            \".... . .-.. .-.. --- / -- --- .-. ... .\".to_string()\n        )\n    }\n\n    #[test]\n    fn encrypt_letters_and_special_characters() {\n        let message = \"What's a great day!\";\n        let cipher = encode(message);\n        assert_eq!(\n            cipher,\n            \".-- .... .- - .----. ... / .- / --. .-. . .- - / -.. .- -.-- -.-.--\".to_string()\n        )\n    }\n\n    #[test]\n    fn encrypt_message_with_unsupported_character() {\n        let message = \"Error?? {}\";\n        let cipher = encode(message);\n        assert_eq!(\n            cipher,\n            \". .-. .-. --- .-. ..--.. ..--.. / ........ ........\".to_string()\n        )\n    }\n\n    #[test]\n    fn decrypt_valid_morsecode_with_spaces() {\n        let expected = \"Hello Morse! How's it goin, \\\"eh\\\"?\"\n            .to_string()\n            .to_uppercase();\n        let encypted = encode(&expected);\n        let result = decode(&encypted).unwrap();\n\n        assert_eq!(expected, result);\n    }\n\n    #[test]\n    fn decrypt_valid_character_set_invalid_morsecode() {\n        let expected = format!(\n            \"{_UNKNOWN_MORSE_CHARACTER}{_UNKNOWN_MORSE_CHARACTER}{_UNKNOWN_MORSE_CHARACTER}{_UNKNOWN_MORSE_CHARACTER} {_UNKNOWN_MORSE_CHARACTER}\",\n        );\n\n        let encypted = \".-.-.--.-.-. --------. ..---.-.-. .-.-.--.-.-. / .-.-.--.-.-.\".to_string();\n        let result = decode(&encypted).unwrap();\n\n        assert_eq!(expected, result);\n    }\n\n    #[test]\n    fn decrypt_invalid_morsecode_with_spaces() {\n        let encypted = \"1... . .-.. .-.. --- / -- --- .-. ... .\";\n        let result = decode(encypted).map_err(|e| e.kind());\n        let expected = Err(io::ErrorKind::InvalidData);\n\n        assert_eq!(expected, result);\n    }\n}\n"
  },
  {
    "path": "src/ciphers/polybius.rs",
    "content": "/// Encode an ASCII string into its location in a Polybius square.\n/// Only alphabetical characters are encoded.\npub fn encode_ascii(string: &str) -> String {\n    string\n        .chars()\n        .map(|c| match c {\n            'a' | 'A' => \"11\",\n            'b' | 'B' => \"12\",\n            'c' | 'C' => \"13\",\n            'd' | 'D' => \"14\",\n            'e' | 'E' => \"15\",\n            'f' | 'F' => \"21\",\n            'g' | 'G' => \"22\",\n            'h' | 'H' => \"23\",\n            'i' | 'I' | 'j' | 'J' => \"24\",\n            'k' | 'K' => \"25\",\n            'l' | 'L' => \"31\",\n            'm' | 'M' => \"32\",\n            'n' | 'N' => \"33\",\n            'o' | 'O' => \"34\",\n            'p' | 'P' => \"35\",\n            'q' | 'Q' => \"41\",\n            'r' | 'R' => \"42\",\n            's' | 'S' => \"43\",\n            't' | 'T' => \"44\",\n            'u' | 'U' => \"45\",\n            'v' | 'V' => \"51\",\n            'w' | 'W' => \"52\",\n            'x' | 'X' => \"53\",\n            'y' | 'Y' => \"54\",\n            'z' | 'Z' => \"55\",\n            _ => \"\",\n        })\n        .collect()\n}\n\n/// Decode a string of ints into their corresponding\n/// letters in a Polybius square.\n///\n/// Any invalid characters, or whitespace will be ignored.\npub fn decode_ascii(string: &str) -> String {\n    string\n        .chars()\n        .filter(|c| !c.is_whitespace())\n        .collect::<String>()\n        .as_bytes()\n        .chunks(2)\n        .map(|s| match std::str::from_utf8(s) {\n            Ok(v) => v.parse::<i32>().unwrap_or(0),\n            Err(_) => 0,\n        })\n        .map(|i| match i {\n            11 => 'A',\n            12 => 'B',\n            13 => 'C',\n            14 => 'D',\n            15 => 'E',\n            21 => 'F',\n            22 => 'G',\n            23 => 'H',\n            24 => 'I',\n            25 => 'K',\n            31 => 'L',\n            32 => 'M',\n            33 => 'N',\n            34 => 'O',\n            35 => 'P',\n            41 => 'Q',\n            42 => 'R',\n            43 => 'S',\n            44 => 'T',\n            45 => 'U',\n            51 => 'V',\n            52 => 'W',\n            53 => 'X',\n            54 => 'Y',\n            55 => 'Z',\n            _ => ' ',\n        })\n        .collect::<String>()\n        .replace(' ', \"\")\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{decode_ascii, encode_ascii};\n\n    #[test]\n    fn encode_empty() {\n        assert_eq!(encode_ascii(\"\"), \"\");\n    }\n\n    #[test]\n    fn encode_valid_string() {\n        assert_eq!(encode_ascii(\"This is a test\"), \"4423244324431144154344\");\n    }\n\n    #[test]\n    fn encode_emoji() {\n        assert_eq!(encode_ascii(\"🙂\"), \"\");\n    }\n\n    #[test]\n    fn decode_empty() {\n        assert_eq!(decode_ascii(\"\"), \"\");\n    }\n\n    #[test]\n    fn decode_valid_string() {\n        assert_eq!(\n            decode_ascii(\"44 23 24 43 24 43 11 44 15 43 44 \"),\n            \"THISISATEST\"\n        );\n    }\n\n    #[test]\n    fn decode_emoji() {\n        assert_eq!(decode_ascii(\"🙂\"), \"\");\n    }\n\n    #[test]\n    fn decode_string_with_whitespace() {\n        assert_eq!(\n            decode_ascii(\"44\\n23\\t\\r24\\r\\n43   2443\\n 11 \\t 44\\r \\r15 \\n43 44\"),\n            \"THISISATEST\"\n        );\n    }\n\n    #[test]\n    fn decode_unknown_string() {\n        assert_eq!(decode_ascii(\"94 63 64 83 64 48 77 00 05 47 48 \"), \"\");\n    }\n\n    #[test]\n    fn decode_odd_length() {\n        assert_eq!(decode_ascii(\"11 22 33 4\"), \"AGN\");\n    }\n\n    #[test]\n    fn encode_and_decode() {\n        let string = \"Do you ever wonder why we're here?\";\n        let encode = encode_ascii(string);\n        assert_eq!(\n            \"1434543445155115425234331415425223545215421523154215\",\n            encode,\n        );\n        assert_eq!(\"DOYOUEVERWONDERWHYWEREHERE\", decode_ascii(&encode));\n    }\n}\n"
  },
  {
    "path": "src/ciphers/rail_fence.rs",
    "content": "// wiki: https://en.wikipedia.org/wiki/Rail_fence_cipher\npub fn rail_fence_encrypt(plain_text: &str, key: usize) -> String {\n    let mut cipher = vec![Vec::new(); key];\n\n    for (c, i) in plain_text.chars().zip(zigzag(key)) {\n        cipher[i].push(c);\n    }\n\n    return cipher.iter().flatten().collect::<String>();\n}\n\npub fn rail_fence_decrypt(cipher: &str, key: usize) -> String {\n    let mut indices: Vec<_> = zigzag(key).zip(1..).take(cipher.len()).collect();\n    indices.sort();\n\n    let mut cipher_text: Vec<_> = cipher\n        .chars()\n        .zip(indices)\n        .map(|(c, (_, i))| (i, c))\n        .collect();\n\n    cipher_text.sort();\n    return cipher_text.iter().map(|(_, c)| c).collect();\n}\n\nfn zigzag(n: usize) -> impl Iterator<Item = usize> {\n    (0..n - 1).chain((1..n).rev()).cycle()\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    #[test]\n    fn rails_basic() {\n        assert_eq!(rail_fence_encrypt(\"attack at once\", 2), \"atc toctaka ne\");\n        assert_eq!(rail_fence_decrypt(\"atc toctaka ne\", 2), \"attack at once\");\n\n        assert_eq!(rail_fence_encrypt(\"rust is cool\", 3), \"r cuti olsso\");\n        assert_eq!(rail_fence_decrypt(\"r cuti olsso\", 3), \"rust is cool\");\n    }\n}\n"
  },
  {
    "path": "src/ciphers/rot13.rs",
    "content": "pub fn rot13(text: &str) -> String {\n    let to_enc = text.to_uppercase();\n    to_enc\n        .chars()\n        .map(|c| match c {\n            'A'..='M' => ((c as u8) + 13) as char,\n            'N'..='Z' => ((c as u8) - 13) as char,\n            _ => c,\n        })\n        .collect()\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_single_letter() {\n        assert_eq!(\"N\", rot13(\"A\"));\n    }\n\n    #[test]\n    fn test_bunch_of_letters() {\n        assert_eq!(\"NOP\", rot13(\"ABC\"));\n    }\n\n    #[test]\n    fn test_non_ascii() {\n        assert_eq!(\"😀NO\", rot13(\"😀AB\"));\n    }\n\n    #[test]\n    fn test_twice() {\n        assert_eq!(\"ABCD\", rot13(&rot13(\"ABCD\")));\n    }\n}\n"
  },
  {
    "path": "src/ciphers/rsa_cipher.rs",
    "content": "//! RSA Cipher Implementation\n//!\n//! This module provides a basic implementation of the RSA (Rivest-Shamir-Adleman) encryption algorithm.\n//! RSA is an asymmetric cryptographic algorithm that uses a pair of keys: public and private.\n//!\n//! # Warning\n//!\n//! This is an educational implementation and should NOT be used for production cryptography.\n//! Use established cryptographic libraries like `ring` or `rust-crypto` for real-world applications.\n//!\n//! # Examples\n//!\n//! ```\n//! use the_algorithms_rust::ciphers::{generate_keypair, encrypt, decrypt};\n//!\n//! let (public_key, private_key) = generate_keypair(61, 53);\n//! let message = 65;\n//! let encrypted = encrypt(message, &public_key);\n//! let decrypted = decrypt(encrypted, &private_key);\n//! assert_eq!(message, decrypted);\n//! ```\n\n/// Represents an RSA public key containing (n, e)\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub struct PublicKey {\n    pub n: u64,\n    pub e: u64,\n}\n\n/// Represents an RSA private key containing (n, d)\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub struct PrivateKey {\n    pub n: u64,\n    pub d: u64,\n}\n\n/// Computes the greatest common divisor using Euclid's algorithm\n///\n/// # Arguments\n///\n/// * `a` - First number\n/// * `b` - Second number\n///\n/// # Returns\n///\n/// The GCD of `a` and `b`\nfn gcd(mut a: u64, mut b: u64) -> u64 {\n    while b != 0 {\n        let temp = b;\n        b = a % b;\n        a = temp;\n    }\n    a\n}\n\n/// Computes the modular multiplicative inverse using the Extended Euclidean Algorithm\n///\n/// Finds `x` such that `(a * x) % m == 1`\n///\n/// # Arguments\n///\n/// * `a` - The number to find the inverse of\n/// * `m` - The modulus\n///\n/// # Returns\n///\n/// The modular multiplicative inverse of `a` modulo `m`, or `None` if it doesn't exist\nfn mod_inverse(a: i64, m: i64) -> Option<u64> {\n    let (mut old_r, mut r) = (a, m);\n    let (mut old_s, mut s) = (1_i64, 0_i64);\n\n    while r != 0 {\n        let quotient = old_r / r;\n        (old_r, r) = (r, old_r - quotient * r);\n        (old_s, s) = (s, old_s - quotient * s);\n    }\n\n    if old_r > 1 {\n        return None; // a is not invertible\n    }\n\n    if old_s < 0 {\n        Some((old_s + m) as u64)\n    } else {\n        Some(old_s as u64)\n    }\n}\n\n/// Performs modular exponentiation: (base^exp) % modulus\n///\n/// Uses the square-and-multiply algorithm for efficiency\n///\n/// # Arguments\n///\n/// * `base` - The base number\n/// * `exp` - The exponent\n/// * `modulus` - The modulus\n///\n/// # Returns\n///\n/// The result of (base^exp) % modulus\nfn mod_pow(mut base: u64, mut exp: u64, modulus: u64) -> u64 {\n    if modulus == 1 {\n        return 0;\n    }\n\n    let mut result = 1;\n    base %= modulus;\n\n    while exp > 0 {\n        if exp % 2 == 1 {\n            result = ((result as u128 * base as u128) % modulus as u128) as u64;\n        }\n        exp >>= 1;\n        base = ((base as u128 * base as u128) % modulus as u128) as u64;\n    }\n\n    result\n}\n\n/// Generates an RSA keypair from two prime numbers\n///\n/// # Arguments\n///\n/// * `p` - First prime number\n/// * `q` - Second prime number (should be different from p)\n///\n/// # Returns\n///\n/// A tuple containing (PublicKey, PrivateKey)\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::ciphers::generate_keypair;\n///\n/// let (public, private) = generate_keypair(61, 53);\n/// // n = p * q\n/// assert_eq!(public.n, 3233);\n/// assert_eq!(private.n, 3233);\n/// // Both keys share the same n\n/// assert_eq!(public.n, private.n);\n/// ```\n///\n/// # Panics\n///\n/// Panics if the modular inverse cannot be computed\npub fn generate_keypair(p: u64, q: u64) -> (PublicKey, PrivateKey) {\n    let n = p * q;\n    let phi = (p - 1) * (q - 1);\n\n    // Choose e such that 1 < e < phi and gcd(e, phi) = 1\n    let mut e = 2;\n    while e < phi {\n        if gcd(e, phi) == 1 {\n            break;\n        }\n        e += 1;\n    }\n\n    // Compute d, the modular multiplicative inverse of e mod phi\n    let d = mod_inverse(e as i64, phi as i64).expect(\"Failed to compute modular inverse\");\n\n    let public_key = PublicKey { n, e };\n    let private_key = PrivateKey { n, d };\n\n    (public_key, private_key)\n}\n\n/// Encrypts a message using the RSA public key\n///\n/// # Arguments\n///\n/// * `message` - The plaintext message (must be less than n)\n/// * `public_key` - The public key to use for encryption\n///\n/// # Returns\n///\n/// The encrypted ciphertext\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::ciphers::{generate_keypair, encrypt, decrypt};\n///\n/// let (public_key, private_key) = generate_keypair(61, 53);\n/// let message = 65;\n/// let ciphertext = encrypt(message, &public_key);\n/// let decrypted = decrypt(ciphertext, &private_key);\n/// assert_eq!(decrypted, message);\n/// ```\npub fn encrypt(message: u64, public_key: &PublicKey) -> u64 {\n    mod_pow(message, public_key.e, public_key.n)\n}\n\n/// Decrypts a ciphertext using the RSA private key\n///\n/// # Arguments\n///\n/// * `ciphertext` - The encrypted message\n/// * `private_key` - The private key to use for decryption\n///\n/// # Returns\n///\n/// The decrypted plaintext message\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::ciphers::{generate_keypair, encrypt, decrypt};\n///\n/// let (public_key, private_key) = generate_keypair(61, 53);\n/// let message = 65;\n/// let ciphertext = encrypt(message, &public_key);\n/// let plaintext = decrypt(ciphertext, &private_key);\n/// assert_eq!(plaintext, message);\n/// ```\npub fn decrypt(ciphertext: u64, private_key: &PrivateKey) -> u64 {\n    mod_pow(ciphertext, private_key.d, private_key.n)\n}\n\n/// Encrypts a text message by converting each character to its ASCII value\n///\n/// # Arguments\n///\n/// * `message` - The plaintext string\n/// * `public_key` - The public key to use for encryption\n///\n/// # Returns\n///\n/// A vector of encrypted values, one for each character\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::ciphers::{generate_keypair, encrypt_text, decrypt_text};\n///\n/// let (public, private) = generate_keypair(61, 53);\n/// let encrypted = encrypt_text(\"HI\", &public);\n/// let decrypted = decrypt_text(&encrypted, &private);\n/// assert_eq!(decrypted, \"HI\");\n/// ```\npub fn encrypt_text(message: &str, public_key: &PublicKey) -> Vec<u64> {\n    message\n        .chars()\n        .map(|c| encrypt(c as u64, public_key))\n        .collect()\n}\n\n/// Decrypts a vector of encrypted values back to text\n///\n/// # Arguments\n///\n/// * `ciphertext` - The vector of encrypted character values\n/// * `private_key` - The private key to use for decryption\n///\n/// # Returns\n///\n/// The decrypted string\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::ciphers::{generate_keypair, encrypt_text, decrypt_text};\n///\n/// let (public, private) = generate_keypair(61, 53);\n/// let encrypted = encrypt_text(\"HELLO\", &public);\n/// let decrypted = decrypt_text(&encrypted, &private);\n/// assert_eq!(decrypted, \"HELLO\");\n/// ```\npub fn decrypt_text(ciphertext: &[u64], private_key: &PrivateKey) -> String {\n    ciphertext\n        .iter()\n        .map(|&c| {\n            let decrypted = decrypt(c, private_key);\n            char::from_u32(decrypted as u32).unwrap_or('?')\n        })\n        .collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_gcd() {\n        assert_eq!(gcd(48, 18), 6);\n        assert_eq!(gcd(17, 13), 1);\n        assert_eq!(gcd(100, 50), 50);\n        assert_eq!(gcd(7, 7), 7);\n    }\n\n    #[test]\n    fn test_mod_inverse() {\n        assert_eq!(mod_inverse(17, 3120), Some(2753));\n        assert_eq!(mod_inverse(7, 40), Some(23));\n        assert!(mod_inverse(4, 8).is_none()); // No inverse exists\n    }\n\n    #[test]\n    fn test_mod_pow() {\n        assert_eq!(mod_pow(4, 13, 497), 445);\n        assert_eq!(mod_pow(2, 10, 1000), 24);\n        assert_eq!(mod_pow(3, 5, 7), 5);\n    }\n\n    #[test]\n    fn test_generate_keypair() {\n        let (public, private) = generate_keypair(61, 53);\n\n        // n should be p * q\n        assert_eq!(public.n, 3233);\n        assert_eq!(private.n, 3233);\n\n        // e should be coprime with phi\n        let phi = (61 - 1) * (53 - 1);\n        assert_eq!(gcd(public.e, phi), 1);\n\n        // Verify that (e * d) % phi == 1\n        assert_eq!((public.e * private.d) % phi, 1);\n    }\n\n    #[test]\n    fn test_encrypt_decrypt_number() {\n        let (public, private) = generate_keypair(61, 53);\n        let message = 65;\n\n        let encrypted = encrypt(message, &public);\n        // Encrypted value will vary based on e, so we just check it's different\n        assert_ne!(encrypted, message);\n\n        let decrypted = decrypt(encrypted, &private);\n        assert_eq!(decrypted, message);\n    }\n\n    #[test]\n    fn test_encrypt_decrypt_various_numbers() {\n        let (public, private) = generate_keypair(61, 53);\n\n        for message in [1, 42, 100, 255, 1000, 3000] {\n            let encrypted = encrypt(message, &public);\n            let decrypted = decrypt(encrypted, &private);\n            assert_eq!(decrypted, message, \"Failed for message: {message}\");\n        }\n    }\n\n    #[test]\n    fn test_encrypt_decrypt_text() {\n        let (public, private) = generate_keypair(61, 53);\n\n        let message = \"HI\";\n        let encrypted = encrypt_text(message, &public);\n        let decrypted = decrypt_text(&encrypted, &private);\n\n        assert_eq!(decrypted, message);\n    }\n\n    #[test]\n    fn test_encrypt_decrypt_longer_text() {\n        let (public, private) = generate_keypair(61, 53);\n\n        let message = \"HELLO\";\n        let encrypted = encrypt_text(message, &public);\n        let decrypted = decrypt_text(&encrypted, &private);\n\n        assert_eq!(decrypted, message);\n    }\n\n    #[test]\n    fn test_different_primes() {\n        let (public, private) = generate_keypair(17, 19);\n\n        let message = 42;\n        let encrypted = encrypt(message, &public);\n        let decrypted = decrypt(encrypted, &private);\n\n        assert_eq!(decrypted, message);\n    }\n\n    #[test]\n    fn test_encrypt_decrypt_alphabet() {\n        let (public, private) = generate_keypair(61, 53);\n\n        let message = \"ABC\";\n        let encrypted = encrypt_text(message, &public);\n        let decrypted = decrypt_text(&encrypted, &private);\n\n        assert_eq!(decrypted, message);\n    }\n\n    #[test]\n    fn test_key_properties() {\n        let (public, private) = generate_keypair(61, 53);\n\n        // Both keys should have the same n\n        assert_eq!(public.n, private.n);\n\n        // e and d should be different\n        assert_ne!(public.e, private.d);\n\n        // Verify that (e * d) % phi == 1\n        let phi = (61 - 1) * (53 - 1);\n        assert_eq!((public.e * private.d) % phi, 1);\n    }\n}\n"
  },
  {
    "path": "src/ciphers/salsa.rs",
    "content": "macro_rules! quarter_round {\n    ($v1:expr,$v2:expr,$v3:expr,$v4:expr) => {\n        $v2 ^= ($v1.wrapping_add($v4).rotate_left(7));\n        $v3 ^= ($v2.wrapping_add($v1).rotate_left(9));\n        $v4 ^= ($v3.wrapping_add($v2).rotate_left(13));\n        $v1 ^= ($v4.wrapping_add($v3).rotate_left(18));\n    };\n}\n\n/// This is a `Salsa20` implementation based on <https://en.wikipedia.org/wiki/Salsa20>\\\n/// `Salsa20` is a stream cipher developed by Daniel J. Bernstein.\\\n/// To use it, the `salsa20` function should be called with appropriate parameters and the\n/// output of the function should be XORed with plain text.\n///\n/// `salsa20` function takes as input an array of 16 32-bit integers (512 bits)\n/// of which 128 bits is the constant 'expand 32-byte k', 256 bits is the key,\n/// and 128 bits are nonce and counter. It is up to the user to determine how\n/// many bits each of nonce and counter take, but a default of 64 bits each\n/// seems to be a sane choice.\n///\n/// The 16 input numbers can be thought of as the elements of a 4x4 matrix like\n/// the one below, on which we do the main operations of the cipher.\n///\n/// ```text\n/// +----+----+----+----+\n/// | 00 | 01 | 02 | 03 |\n/// +----+----+----+----+\n/// | 04 | 05 | 06 | 07 |\n/// +----+----+----+----+\n/// | 08 | 09 | 10 | 11 |\n/// +----+----+----+----+\n/// | 12 | 13 | 14 | 15 |\n/// +----+----+----+----+\n/// ```\n///\n/// As per the diagram below, `input[0, 5, 10, 15]` are the constants mentioned\n/// above, `input[1, 2, 3, 4, 11, 12, 13, 14]` is filled with the key, and\n/// `input[6, 7, 8, 9]` should be filled with nonce and counter values. The output\n/// of the function is stored in `output` variable and can be XORed with the\n/// plain text to produce the cipher text.\n///\n/// ```text\n/// +------+------+------+------+\n/// |      |      |      |      |\n/// | C[0] | key1 | key2 | key3 |\n/// |      |      |      |      |\n/// +------+------+------+------+\n/// |      |      |      |      |\n/// | key4 | C[1] | no1  | no2  |\n/// |      |      |      |      |\n/// +------+------+------+------+\n/// |      |      |      |      |\n/// | ctr1 | ctr2 | C[2] | key5 |\n/// |      |      |      |      |\n/// +------+------+------+------+\n/// |      |      |      |      |\n/// | key6 | key7 | key8 | C[3] |\n/// |      |      |      |      |\n/// +------+------+------+------+\n/// ```\npub fn salsa20(input: &[u32; 16], output: &mut [u32; 16]) {\n    output.copy_from_slice(&input[..]);\n    for _ in 0..10 {\n        // Odd round\n        quarter_round!(output[0], output[4], output[8], output[12]); // column 1\n        quarter_round!(output[5], output[9], output[13], output[1]); // column 2\n        quarter_round!(output[10], output[14], output[2], output[6]); // column 3\n        quarter_round!(output[15], output[3], output[7], output[11]); // column 4\n\n        // Even round\n        quarter_round!(output[0], output[1], output[2], output[3]); // row 1\n        quarter_round!(output[5], output[6], output[7], output[4]); // row 2\n        quarter_round!(output[10], output[11], output[8], output[9]); // row 3\n        quarter_round!(output[15], output[12], output[13], output[14]); // row 4\n    }\n    for (a, &b) in output.iter_mut().zip(input.iter()) {\n        *a = a.wrapping_add(b);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::fmt::Write;\n\n    const C: [u32; 4] = [0x65787061, 0x6e642033, 0x322d6279, 0x7465206b];\n\n    fn output_hex(inp: &[u32; 16]) -> String {\n        let mut res = String::new();\n        res.reserve(512 / 4);\n        for &x in inp {\n            write!(&mut res, \"{x:08x}\").unwrap();\n        }\n        res\n    }\n    #[test]\n    // test vector 1\n    fn basic_tv1() {\n        let mut inp = [0u32; 16];\n        let mut out = [0u32; 16];\n        inp[0] = C[0];\n        inp[1] = 0x01020304; // 1, 2, 3, 4\n        inp[2] = 0x05060708; // 5, 6, 7, 8, ...\n        inp[3] = 0x090a0b0c;\n        inp[4] = 0x0d0e0f10;\n        inp[5] = C[1];\n        inp[6] = 0x65666768; // 101, 102, 103, 104\n        inp[7] = 0x696a6b6c; // 105, 106, 107, 108, ...\n        inp[8] = 0x6d6e6f70;\n        inp[9] = 0x71727374;\n        inp[10] = C[2];\n        inp[11] = 0xc9cacbcc; // 201, 202, 203, 204\n        inp[12] = 0xcdcecfd0; // 205, 206, 207, 208, ...\n        inp[13] = 0xd1d2d3d4;\n        inp[14] = 0xd5d6d7d8;\n        inp[15] = C[3];\n        salsa20(&inp, &mut out);\n        // Checked with wikipedia implementation, does not agree with\n        // \"https://cr.yp.to/snuffle/spec.pdf\"\n        assert_eq!(\n            output_hex(&out),\n            concat!(\n                \"de1d6f8d91dbf69d0db4b70c8b4320d236694432896d98b05aa7b76d5738ca13\",\n                \"04e5a170c8e479af1542ed2f30f26ba57da20203cfe955c66f4cc7a06dd34359\"\n            )\n        );\n    }\n}\n"
  },
  {
    "path": "src/ciphers/sha256.rs",
    "content": "/*!\n * SHA-2 256 bit implementation\n * This implementation is based on RFC6234\n * Keep in mind that the amount of data (in bits) processed should always be an\n * integer multiple of 8\n */\n\n// The constants are tested to make sure they are correct\npub const H0: [u32; 8] = [\n    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\n];\n\npub const K: [u32; 64] = [\n    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n];\n\n// The following functions are implemented according to page 10 of RFC6234\n#[inline]\nfn ch(x: u32, y: u32, z: u32) -> u32 {\n    (x & y) ^ ((!x) & z)\n}\n\n#[inline]\nfn maj(x: u32, y: u32, z: u32) -> u32 {\n    (x & y) ^ (x & z) ^ (y & z)\n}\n\n#[inline]\nfn bsig0(x: u32) -> u32 {\n    x.rotate_right(2) ^ x.rotate_right(13) ^ x.rotate_right(22)\n}\n\n#[inline]\nfn bsig1(x: u32) -> u32 {\n    x.rotate_right(6) ^ x.rotate_right(11) ^ x.rotate_right(25)\n}\n\n#[inline]\nfn ssig0(x: u32) -> u32 {\n    x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3)\n}\n\n#[inline]\nfn ssig1(x: u32) -> u32 {\n    x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10)\n}\n\npub struct SHA256 {\n    /// The current block to be processed, 512 bits long\n    buffer: [u32; 16],\n    /// Length (bits) of the message, should always be a multiple of 8\n    length: u64,\n    /// The current hash value. Note: this value is invalid unless `finalize`\n    /// is called\n    pub h: [u32; 8],\n    /// Message schedule\n    w: [u32; 64],\n    pub finalized: bool,\n    // Temporary values:\n    round: [u32; 8],\n}\n\nfn process_block(h: &mut [u32; 8], w: &mut [u32; 64], round: &mut [u32; 8], buf: &[u32; 16]) {\n    // Prepare the message schedule:\n    w[..buf.len()].copy_from_slice(&buf[..]);\n    for i in buf.len()..w.len() {\n        w[i] = ssig1(w[i - 2])\n            .wrapping_add(w[i - 7])\n            .wrapping_add(ssig0(w[i - 15]))\n            .wrapping_add(w[i - 16]);\n    }\n    round.copy_from_slice(h);\n    for i in 0..w.len() {\n        let t1 = round[7]\n            .wrapping_add(bsig1(round[4]))\n            .wrapping_add(ch(round[4], round[5], round[6]))\n            .wrapping_add(K[i])\n            .wrapping_add(w[i]);\n        let t2 = bsig0(round[0]).wrapping_add(maj(round[0], round[1], round[2]));\n        round[7] = round[6];\n        round[6] = round[5];\n        round[5] = round[4];\n        round[4] = round[3].wrapping_add(t1);\n        round[3] = round[2];\n        round[2] = round[1];\n        round[1] = round[0];\n        round[0] = t1.wrapping_add(t2);\n    }\n    for i in 0..h.len() {\n        h[i] = h[i].wrapping_add(round[i]);\n    }\n}\n\nimpl SHA256 {\n    pub fn new_default() -> Self {\n        SHA256 {\n            buffer: [0u32; 16],\n            length: 0,\n            h: H0,\n            w: [0u32; 64],\n            round: [0u32; 8],\n            finalized: false,\n        }\n    }\n    /// Note: buffer should be empty before calling this!\n    pub fn process_block(&mut self, buf: &[u32; 16]) {\n        process_block(&mut self.h, &mut self.w, &mut self.round, buf);\n        self.length += 512;\n    }\n\n    pub fn update(&mut self, data: &[u8]) {\n        if data.is_empty() {\n            return;\n        }\n        let offset = (((32 - (self.length & 31)) & 31) >> 3) as usize;\n        let mut buf_ind = ((self.length & 511) >> 5) as usize;\n        for (i, &byte) in data.iter().enumerate().take(offset) {\n            self.buffer[buf_ind] ^= (byte as u32) << ((offset - i - 1) << 3);\n        }\n        self.length += (data.len() as u64) << 3;\n        if offset > data.len() {\n            return;\n        }\n        if offset > 0 {\n            buf_ind += 1;\n        }\n        if data.len() > 3 {\n            for i in (offset..(data.len() - 3)).step_by(4) {\n                if buf_ind & 16 == 16 {\n                    process_block(&mut self.h, &mut self.w, &mut self.round, &self.buffer);\n                    buf_ind = 0;\n                }\n                self.buffer[buf_ind] = ((data[i] as u32) << 24)\n                    ^ ((data[i + 1] as u32) << 16)\n                    ^ ((data[i + 2] as u32) << 8)\n                    ^ data[i + 3] as u32;\n                buf_ind += 1;\n            }\n        }\n        if buf_ind & 16 == 16 {\n            process_block(&mut self.h, &mut self.w, &mut self.round, &self.buffer);\n            buf_ind = 0;\n        }\n        self.buffer[buf_ind] = 0;\n        let rem_ind = offset + ((data.len() - offset) & !0b11);\n        for (i, &byte) in data[rem_ind..].iter().enumerate() {\n            self.buffer[buf_ind] ^= (byte as u32) << ((3 - i) << 3);\n        }\n    }\n\n    pub fn get_hash(&mut self) -> [u8; 32] {\n        // we should first add a `1` bit to the end of the buffer, then we will\n        // add enough 0s so that the length becomes (512k + 448). After that we\n        // will append the binary representation of length to the data\n        if !self.finalized {\n            self.finalized = true;\n            let clen = (self.length + 8) & 511;\n            let num_0 = match clen.cmp(&448) {\n                std::cmp::Ordering::Greater => (448 + 512 - clen) >> 3,\n                _ => (448 - clen) >> 3,\n            };\n            let mut padding: Vec<u8> = vec![0_u8; (num_0 + 9) as usize];\n            let len = padding.len();\n            padding[0] = 0x80;\n            padding[len - 8] = (self.length >> 56) as u8;\n            padding[len - 7] = (self.length >> 48) as u8;\n            padding[len - 6] = (self.length >> 40) as u8;\n            padding[len - 5] = (self.length >> 32) as u8;\n            padding[len - 4] = (self.length >> 24) as u8;\n            padding[len - 3] = (self.length >> 16) as u8;\n            padding[len - 2] = (self.length >> 8) as u8;\n            padding[len - 1] = self.length as u8;\n            self.update(&padding);\n        }\n        assert_eq!(self.length & 511, 0);\n        let mut result = [0u8; 32];\n        for i in (0..32).step_by(4) {\n            result[i] = (self.h[i >> 2] >> 24) as u8;\n            result[i + 1] = (self.h[i >> 2] >> 16) as u8;\n            result[i + 2] = (self.h[i >> 2] >> 8) as u8;\n            result[i + 3] = self.h[i >> 2] as u8;\n        }\n        result\n    }\n}\n\nimpl super::Hasher<32> for SHA256 {\n    fn new_default() -> Self {\n        SHA256::new_default()\n    }\n\n    fn update(&mut self, data: &[u8]) {\n        self.update(data);\n    }\n\n    fn get_hash(&mut self) -> [u8; 32] {\n        self.get_hash()\n    }\n}\n\n#[cfg(test)]\npub mod tests {\n    use super::*;\n    use crate::math::LinearSieve;\n    use std::fmt::Write;\n\n    // Let's keep this utility function\n    pub fn get_hash_string(hash: &[u8; 32]) -> String {\n        let mut result = String::new();\n        result.reserve(64);\n        for &ch in hash {\n            write!(&mut result, \"{ch:02x}\").unwrap();\n        }\n        result\n    }\n\n    #[test]\n    fn test_constants() {\n        let mut ls = LinearSieve::new();\n        ls.prepare(311).unwrap();\n        assert_eq!(64, ls.primes.len());\n        assert_eq!(311, ls.primes[63]);\n\n        let float_len = 52;\n        let constant_len = 32;\n        for (pos, &k) in K.iter().enumerate() {\n            let a: f64 = ls.primes[pos] as f64;\n            let bits = a.cbrt().to_bits();\n            let exp = bits >> float_len; // The sign bit is already 0\n                                         //(exp - 1023) can be bigger than 0, we must include more bits.\n            let k_ref = ((bits & ((1_u64 << float_len) - 1))\n                >> (float_len - constant_len + 1023 - exp)) as u32;\n            assert_eq!(k, k_ref);\n        }\n\n        for (pos, &h) in H0.iter().enumerate() {\n            let a: f64 = ls.primes[pos] as f64;\n            let bits = a.sqrt().to_bits();\n            let exp = bits >> float_len;\n            let h_ref = ((bits & ((1_u64 << float_len) - 1))\n                >> (float_len - constant_len + 1023 - exp)) as u32;\n            assert_eq!(h, h_ref);\n        }\n    }\n\n    // To test the hashes, you can use the following command on linux:\n    // echo -n 'STRING' | sha256sum\n    // the `-n` is because by default, echo adds a `\\n` to its output\n\n    #[test]\n    fn empty() {\n        let mut res = SHA256::new_default();\n        assert_eq!(\n            res.get_hash(),\n            [\n                0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f,\n                0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,\n                0x78, 0x52, 0xb8, 0x55\n            ]\n        );\n    }\n\n    #[test]\n    fn ascii() {\n        let mut res = SHA256::new_default();\n        res.update(b\"The quick brown fox jumps over the lazy dog\");\n        assert_eq!(\n            res.get_hash(),\n            [\n                0xD7, 0xA8, 0xFB, 0xB3, 0x07, 0xD7, 0x80, 0x94, 0x69, 0xCA, 0x9A, 0xBC, 0xB0, 0x08,\n                0x2E, 0x4F, 0x8D, 0x56, 0x51, 0xE4, 0x6D, 0x3C, 0xDB, 0x76, 0x2D, 0x02, 0xD0, 0xBF,\n                0x37, 0xC9, 0xE5, 0x92\n            ]\n        )\n    }\n\n    #[test]\n    fn ascii_avalanche() {\n        let mut res = SHA256::new_default();\n        res.update(b\"The quick brown fox jumps over the lazy dog.\");\n        assert_eq!(\n            res.get_hash(),\n            [\n                0xEF, 0x53, 0x7F, 0x25, 0xC8, 0x95, 0xBF, 0xA7, 0x82, 0x52, 0x65, 0x29, 0xA9, 0xB6,\n                0x3D, 0x97, 0xAA, 0x63, 0x15, 0x64, 0xD5, 0xD7, 0x89, 0xC2, 0xB7, 0x65, 0x44, 0x8C,\n                0x86, 0x35, 0xFB, 0x6C\n            ]\n        );\n        // Test if finalization is not repeated twice\n        assert_eq!(\n            res.get_hash(),\n            [\n                0xEF, 0x53, 0x7F, 0x25, 0xC8, 0x95, 0xBF, 0xA7, 0x82, 0x52, 0x65, 0x29, 0xA9, 0xB6,\n                0x3D, 0x97, 0xAA, 0x63, 0x15, 0x64, 0xD5, 0xD7, 0x89, 0xC2, 0xB7, 0x65, 0x44, 0x8C,\n                0x86, 0x35, 0xFB, 0x6C\n            ]\n        )\n    }\n    #[test]\n    fn long_ascii() {\n        let mut res = SHA256::new_default();\n        let val = b\"The quick brown fox jumps over the lazy dog.\";\n        for _ in 0..1000 {\n            res.update(val);\n        }\n        let hash = res.get_hash();\n        assert_eq!(\n            &get_hash_string(&hash),\n            \"c264fca077807d391df72fadf39dd63be21f1823f65ca530c9637760eabfc18c\"\n        );\n        let mut res = SHA256::new_default();\n        let val = b\"a\";\n        for _ in 0..999 {\n            res.update(val);\n        }\n        let hash = res.get_hash();\n        assert_eq!(\n            &get_hash_string(&hash),\n            \"d9fe27f3d807a7c46467325f7189495e82b099ce2e14c5b16cc76697fa909f81\"\n        )\n    }\n    #[test]\n    fn short_ascii() {\n        let mut res = SHA256::new_default();\n        let val = b\"a\";\n        res.update(val);\n        let hash = res.get_hash();\n        assert_eq!(\n            &get_hash_string(&hash),\n            \"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/ciphers/sha3.rs",
    "content": "/// Size of the state array in bits\nconst B: usize = 1600;\n\nconst W: usize = B / 25;\nconst L: usize = W.ilog2() as usize;\n\nconst U8BITS: usize = u8::BITS as usize;\n\n// Macro for looping through the whole state array\nmacro_rules! iterate {\n    ( $x:ident, $y:ident, $z:ident => $b:block ) => {\n        for $y in 0..5 {\n            for $x in 0..5 {\n                for $z in 0..W {\n                    $b\n                }\n            }\n        }\n    };\n}\n\n/// A function that produces a padding string such that the length of the padding + the length of\n/// the string to be padded (2nd parameter) is divisible by the 1st parameter\ntype PadFn = fn(isize, isize) -> Vec<bool>;\ntype SpongeFn = fn(&[bool]) -> [bool; B];\n\ntype State = [[[bool; W]; 5]; 5];\n\nfn state_new() -> State {\n    [[[false; W]; 5]; 5]\n}\n\nfn state_fill(dest: &mut State, bits: &[bool]) {\n    let mut i = 0usize;\n\n    iterate!(x, y, z => {\n        if i >= bits.len() { return; }\n        dest[x][y][z] = bits[i];\n        i += 1;\n    });\n}\n\nfn state_copy(dest: &mut State, src: &State) {\n    iterate!(x, y, z => {\n        dest[x][y][z] = src[x][y][z];\n    });\n}\n\nfn state_dump(state: &State) -> [bool; B] {\n    let mut bits = [false; B];\n\n    let mut i = 0usize;\n\n    iterate!(x, y, z => {\n        bits[i] = state[x][y][z];\n        i += 1;\n    });\n\n    bits\n}\n\n/// XORs the state with the parities of two columns in the state array\nfn theta(state: &mut State) {\n    let mut c = [[false; W]; 5];\n    let mut d = [[false; W]; 5];\n\n    // Assign values of C[x,z]\n    for x in 0..5 {\n        for z in 0..W {\n            c[x][z] = state[x][0][z];\n\n            for y in 1..5 {\n                c[x][z] ^= state[x][y][z];\n            }\n        }\n    }\n\n    // Assign values of D[x,z]\n    for x in 0..5 {\n        for z in 0..W {\n            let x1 = (x as isize - 1).rem_euclid(5) as usize;\n            let z2 = (z as isize - 1).rem_euclid(W as isize) as usize;\n\n            d[x][z] = c[x1][z] ^ c[(x + 1) % 5][z2];\n        }\n    }\n\n    // Xor values of D[x,z] into our state array\n    iterate!(x, y, z => {\n        state[x][y][z] ^= d[x][z];\n    });\n}\n\n/// Rotates each lane by an offset depending of the x and y indeces\nfn rho(state: &mut State) {\n    let mut new_state = state_new();\n\n    for z in 0..W {\n        new_state[0][0][z] = state[0][0][z];\n    }\n\n    let mut x = 1;\n    let mut y = 0;\n\n    for t in 0..=23isize {\n        for z in 0..W {\n            let z_offset: isize = ((t + 1) * (t + 2)) / 2;\n            let new_z = (z as isize - z_offset).rem_euclid(W as isize) as usize;\n\n            new_state[x][y][z] = state[x][y][new_z];\n        }\n\n        let old_y = y;\n        y = ((2 * x) + (3 * y)) % 5;\n        x = old_y;\n    }\n\n    state_copy(state, &new_state);\n}\n\n/// Rearrange the positions of the lanes of the state array\nfn pi(state: &mut State) {\n    let mut new_state = state_new();\n\n    iterate!(x, y, z => {\n        new_state[x][y][z] = state[(x + (3 * y)) % 5][x][z];\n    });\n\n    state_copy(state, &new_state);\n}\n\nfn chi(state: &mut State) {\n    let mut new_state = state_new();\n\n    iterate!(x, y, z => {\n        new_state[x][y][z] = state[x][y][z] ^ ((state[(x + 1) % 5][y][z] ^ true) & state[(x + 2) % 5][y][z]);\n    });\n\n    state_copy(state, &new_state);\n}\n\n/// Calculates the round constant depending on what the round number is\nfn rc(t: u8) -> bool {\n    let mut b1: u16;\n    let mut b2: u16;\n    let mut r: u16 = 0x80; // tread r as an array of bits\n\n    //if t % 0xFF == 0 { return true; }\n\n    for _i in 0..(t % 255) {\n        b1 = r >> 8;\n        b2 = r & 1;\n        r |= (b1 ^ b2) << 8;\n\n        b1 = (r >> 4) & 1;\n        r &= 0x1EF; // clear r[4]\n        r |= (b1 ^ b2) << 4;\n\n        b1 = (r >> 3) & 1;\n        r &= 0x1F7; // clear r[3]\n        r |= (b1 ^ b2) << 3;\n\n        b1 = (r >> 2) & 1;\n        r &= 0x1FB; // clear r[2]\n        r |= (b1 ^ b2) << 2;\n\n        r >>= 1;\n    }\n\n    (r >> 7) != 0\n}\n\n/// Applies the round constant to the first lane of the state array\nfn iota(state: &mut State, i_r: u8) {\n    let mut rc_arr = [false; W];\n\n    for j in 0..=L {\n        rc_arr[(1 << j) - 1] = rc((j as u8) + (7 * i_r));\n    }\n\n    for (z, bit) in rc_arr.iter().enumerate() {\n        state[0][0][z] ^= *bit;\n    }\n}\n\nfn rnd(state: &mut State, i_r: u8) {\n    theta(state);\n    rho(state);\n    pi(state);\n    chi(state);\n    iota(state, i_r);\n}\n\nfn keccak_f(bits: &[bool]) -> [bool; B] {\n    let n_r = 12 + (2 * L);\n\n    let mut state = state_new();\n    state_fill(&mut state, bits);\n\n    for i_r in 0..n_r {\n        rnd(&mut state, i_r as u8);\n    }\n\n    state_dump(&state)\n}\n\nfn pad101(x: isize, m: isize) -> Vec<bool> {\n    let mut j = -m - 2;\n\n    while j < 0 {\n        j += x;\n    }\n\n    j %= x;\n\n    let mut ret = vec![false; (j as usize) + 2];\n    *ret.first_mut().unwrap() = true;\n    *ret.last_mut().unwrap() = true;\n\n    ret\n}\n\n/// Sponge construction is a method of compression needing 1) a function on fixed-length bit\n/// strings( here we use keccak_f), 2) a padding function (pad10*1), and 3) a rate. The input and\n/// output of this method can be arbitrarily long\nfn sponge(f: SpongeFn, pad: PadFn, r: usize, n: &[bool], d: usize) -> Vec<bool> {\n    let mut p = Vec::from(n);\n    p.append(&mut pad(r as isize, n.len() as isize));\n\n    assert!(r < B);\n\n    let mut s = [false; B];\n    for chunk in p.chunks(r) {\n        for (s_i, c_i) in s.iter_mut().zip(chunk) {\n            *s_i ^= c_i;\n        }\n\n        s = f(&s);\n    }\n\n    let mut z = Vec::<bool>::new();\n    while z.len() < d {\n        z.extend(&s);\n\n        s = f(&s);\n    }\n\n    z.truncate(d);\n    z\n}\n\nfn keccak(c: usize, n: &[bool], d: usize) -> Vec<bool> {\n    sponge(keccak_f, pad101, B - c, n, d)\n}\n\nfn h2b(h: &[u8], n: usize) -> Vec<bool> {\n    let mut bits = Vec::with_capacity(h.len() * U8BITS);\n\n    for byte in h {\n        for i in 0..u8::BITS {\n            let mask: u8 = 1 << i;\n\n            bits.push((byte & mask) != 0);\n        }\n    }\n\n    assert!(bits.len() == h.len() * U8BITS);\n\n    bits.truncate(n);\n    bits\n}\n\nfn b2h(s: &[bool]) -> Vec<u8> {\n    let m = if s.len().is_multiple_of(U8BITS) {\n        s.len() / 8\n    } else {\n        (s.len() / 8) + 1\n    };\n    let mut bytes = vec![0u8; m];\n\n    for (i, bit) in s.iter().enumerate() {\n        let byte_index = i / U8BITS;\n        let mask = (*bit as u8) << (i % U8BITS);\n\n        bytes[byte_index] |= mask;\n    }\n\n    bytes\n}\n/// Macro to implement all sha3 hash functions as they only differ in digest size\nmacro_rules! sha3 {\n    ($name:ident, $n:literal) => {\n        pub fn $name(m: &[u8]) -> [u8; ($n / U8BITS)] {\n            let mut temp = h2b(m, m.len() * U8BITS);\n            temp.append(&mut vec![false, true]);\n\n            temp = keccak($n * 2, &temp, $n);\n\n            let mut ret = [0u8; ($n / U8BITS)];\n\n            let temp = b2h(&temp);\n            assert!(temp.len() == $n / U8BITS);\n\n            for (i, byte) in temp.iter().enumerate() {\n                ret[i] = *byte;\n            }\n\n            ret\n        }\n    };\n}\n\nsha3!(sha3_224, 224);\nsha3!(sha3_256, 256);\nsha3!(sha3_384, 384);\nsha3!(sha3_512, 512);\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! digest_test {\n        ($fname:ident, $hash:ident, $size:literal, $message:expr, $expected:expr) => {\n            #[test]\n            fn $fname() {\n                let digest = $hash(&$message);\n\n                let expected: [u8; $size / U8BITS] = $expected;\n\n                assert_eq!(digest, expected);\n            }\n        };\n    }\n\n    digest_test!(\n        sha3_224_0,\n        sha3_224,\n        224,\n        [0; 0],\n        [\n            0x6b, 0x4e, 0x03, 0x42, 0x36, 0x67, 0xdb, 0xb7, 0x3b, 0x6e, 0x15, 0x45, 0x4f, 0x0e,\n            0xb1, 0xab, 0xd4, 0x59, 0x7f, 0x9a, 0x1b, 0x07, 0x8e, 0x3f, 0x5b, 0x5a, 0x6b, 0xc7,\n        ]\n    );\n\n    digest_test!(\n        sha3_224_8,\n        sha3_224,\n        224,\n        [1u8],\n        [\n            0x48, 0x82, 0x86, 0xd9, 0xd3, 0x27, 0x16, 0xe5, 0x88, 0x1e, 0xa1, 0xee, 0x51, 0xf3,\n            0x6d, 0x36, 0x60, 0xd7, 0x0f, 0x0d, 0xb0, 0x3b, 0x3f, 0x61, 0x2c, 0xe9, 0xed, 0xa4,\n        ]\n    );\n\n    // Done on large input to verify sponge function is working properly\n    digest_test!(\n        sha3_224_2312,\n        sha3_224,\n        224,\n        [\n            0x31, 0xc8, 0x2d, 0x71, 0x78, 0x5b, 0x7c, 0xa6, 0xb6, 0x51, 0xcb, 0x6c, 0x8c, 0x9a,\n            0xd5, 0xe2, 0xac, 0xeb, 0x0b, 0x06, 0x33, 0xc0, 0x88, 0xd3, 0x3a, 0xa2, 0x47, 0xad,\n            0xa7, 0xa5, 0x94, 0xff, 0x49, 0x36, 0xc0, 0x23, 0x25, 0x13, 0x19, 0x82, 0x0a, 0x9b,\n            0x19, 0xfc, 0x6c, 0x48, 0xde, 0x8a, 0x6f, 0x7a, 0xda, 0x21, 0x41, 0x76, 0xcc, 0xda,\n            0xad, 0xae, 0xef, 0x51, 0xed, 0x43, 0x71, 0x4a, 0xc0, 0xc8, 0x26, 0x9b, 0xbd, 0x49,\n            0x7e, 0x46, 0xe7, 0x8b, 0xb5, 0xe5, 0x81, 0x96, 0x49, 0x4b, 0x24, 0x71, 0xb1, 0x68,\n            0x0e, 0x2d, 0x4c, 0x6d, 0xbd, 0x24, 0x98, 0x31, 0xbd, 0x83, 0xa4, 0xd3, 0xbe, 0x06,\n            0xc8, 0xa2, 0xe9, 0x03, 0x93, 0x39, 0x74, 0xaa, 0x05, 0xee, 0x74, 0x8b, 0xfe, 0x6e,\n            0xf3, 0x59, 0xf7, 0xa1, 0x43, 0xed, 0xf0, 0xd4, 0x91, 0x8d, 0xa9, 0x16, 0xbd, 0x6f,\n            0x15, 0xe2, 0x6a, 0x79, 0x0c, 0xff, 0x51, 0x4b, 0x40, 0xa5, 0xda, 0x7f, 0x72, 0xe1,\n            0xed, 0x2f, 0xe6, 0x3a, 0x05, 0xb8, 0x14, 0x95, 0x87, 0xbe, 0xa0, 0x56, 0x53, 0x71,\n            0x8c, 0xc8, 0x98, 0x0e, 0xad, 0xbf, 0xec, 0xa8, 0x5b, 0x7c, 0x9c, 0x28, 0x6d, 0xd0,\n            0x40, 0x93, 0x65, 0x85, 0x93, 0x8b, 0xe7, 0xf9, 0x82, 0x19, 0x70, 0x0c, 0x83, 0xa9,\n            0x44, 0x3c, 0x28, 0x56, 0xa8, 0x0f, 0xf4, 0x68, 0x52, 0xb2, 0x6d, 0x1b, 0x1e, 0xdf,\n            0x72, 0xa3, 0x02, 0x03, 0xcf, 0x6c, 0x44, 0xa1, 0x0f, 0xa6, 0xea, 0xf1, 0x92, 0x01,\n            0x73, 0xce, 0xdf, 0xb5, 0xc4, 0xcf, 0x3a, 0xc6, 0x65, 0xb3, 0x7a, 0x86, 0xed, 0x02,\n            0x15, 0x5b, 0xbb, 0xf1, 0x7d, 0xc2, 0xe7, 0x86, 0xaf, 0x94, 0x78, 0xfe, 0x08, 0x89,\n            0xd8, 0x6c, 0x5b, 0xfa, 0x85, 0xa2, 0x42, 0xeb, 0x08, 0x54, 0xb1, 0x48, 0x2b, 0x7b,\n            0xd1, 0x6f, 0x67, 0xf8, 0x0b, 0xef, 0x9c, 0x7a, 0x62, 0x8f, 0x05, 0xa1, 0x07, 0x93,\n            0x6a, 0x64, 0x27, 0x3a, 0x97, 0xb0, 0x08, 0x8b, 0x0e, 0x51, 0x54, 0x51, 0xf9, 0x16,\n            0xb5, 0x65, 0x62, 0x30, 0xa1, 0x2b, 0xa6, 0xdc, 0x78\n        ],\n        [\n            0xaa, 0xb2, 0x3c, 0x9e, 0x7f, 0xb9, 0xd7, 0xda, 0xce, 0xfd, 0xfd, 0x0b, 0x1a, 0xe8,\n            0x5a, 0xb1, 0x37, 0x4a, 0xbf, 0xf7, 0xc4, 0xe3, 0xf7, 0x55, 0x6e, 0xca, 0xe4, 0x12\n        ]\n    );\n\n    digest_test!(\n        sha3_256_0,\n        sha3_256,\n        256,\n        [0; 0],\n        [\n            0xa7, 0xff, 0xc6, 0xf8, 0xbf, 0x1e, 0xd7, 0x66, 0x51, 0xc1, 0x47, 0x56, 0xa0, 0x61,\n            0xd6, 0x62, 0xf5, 0x80, 0xff, 0x4d, 0xe4, 0x3b, 0x49, 0xfa, 0x82, 0xd8, 0x0a, 0x4b,\n            0x80, 0xf8, 0x43, 0x4a,\n        ]\n    );\n\n    digest_test!(\n        sha3_256_8,\n        sha3_256,\n        256,\n        [0xe9u8],\n        [\n            0xf0, 0xd0, 0x4d, 0xd1, 0xe6, 0xcf, 0xc2, 0x9a, 0x44, 0x60, 0xd5, 0x21, 0x79, 0x68,\n            0x52, 0xf2, 0x5d, 0x9e, 0xf8, 0xd2, 0x8b, 0x44, 0xee, 0x91, 0xff, 0x5b, 0x75, 0x9d,\n            0x72, 0xc1, 0xe6, 0xd6,\n        ]\n    );\n\n    digest_test!(\n        sha3_256_2184,\n        sha3_256,\n        256,\n        [\n            0xb1, 0xca, 0xa3, 0x96, 0x77, 0x1a, 0x09, 0xa1, 0xdb, 0x9b, 0xc2, 0x05, 0x43, 0xe9,\n            0x88, 0xe3, 0x59, 0xd4, 0x7c, 0x2a, 0x61, 0x64, 0x17, 0xbb, 0xca, 0x1b, 0x62, 0xcb,\n            0x02, 0x79, 0x6a, 0x88, 0x8f, 0xc6, 0xee, 0xff, 0x5c, 0x0b, 0x5c, 0x3d, 0x50, 0x62,\n            0xfc, 0xb4, 0x25, 0x6f, 0x6a, 0xe1, 0x78, 0x2f, 0x49, 0x2c, 0x1c, 0xf0, 0x36, 0x10,\n            0xb4, 0xa1, 0xfb, 0x7b, 0x81, 0x4c, 0x05, 0x78, 0x78, 0xe1, 0x19, 0x0b, 0x98, 0x35,\n            0x42, 0x5c, 0x7a, 0x4a, 0x0e, 0x18, 0x2a, 0xd1, 0xf9, 0x15, 0x35, 0xed, 0x2a, 0x35,\n            0x03, 0x3a, 0x5d, 0x8c, 0x67, 0x0e, 0x21, 0xc5, 0x75, 0xff, 0x43, 0xc1, 0x94, 0xa5,\n            0x8a, 0x82, 0xd4, 0xa1, 0xa4, 0x48, 0x81, 0xdd, 0x61, 0xf9, 0xf8, 0x16, 0x1f, 0xc6,\n            0xb9, 0x98, 0x86, 0x0c, 0xbe, 0x49, 0x75, 0x78, 0x0b, 0xe9, 0x3b, 0x6f, 0x87, 0x98,\n            0x0b, 0xad, 0x0a, 0x99, 0xaa, 0x2c, 0xb7, 0x55, 0x6b, 0x47, 0x8c, 0xa3, 0x5d, 0x1f,\n            0x37, 0x46, 0xc3, 0x3e, 0x2b, 0xb7, 0xc4, 0x7a, 0xf4, 0x26, 0x64, 0x1c, 0xc7, 0xbb,\n            0xb3, 0x42, 0x5e, 0x21, 0x44, 0x82, 0x03, 0x45, 0xe1, 0xd0, 0xea, 0x5b, 0x7d, 0xa2,\n            0xc3, 0x23, 0x6a, 0x52, 0x90, 0x6a, 0xcd, 0xc3, 0xb4, 0xd3, 0x4e, 0x47, 0x4d, 0xd7,\n            0x14, 0xc0, 0xc4, 0x0b, 0xf0, 0x06, 0xa3, 0xa1, 0xd8, 0x89, 0xa6, 0x32, 0x98, 0x38,\n            0x14, 0xbb, 0xc4, 0xa1, 0x4f, 0xe5, 0xf1, 0x59, 0xaa, 0x89, 0x24, 0x9e, 0x7c, 0x73,\n            0x8b, 0x3b, 0x73, 0x66, 0x6b, 0xac, 0x2a, 0x61, 0x5a, 0x83, 0xfd, 0x21, 0xae, 0x0a,\n            0x1c, 0xe7, 0x35, 0x2a, 0xde, 0x7b, 0x27, 0x8b, 0x58, 0x71, 0x58, 0xfd, 0x2f, 0xab,\n            0xb2, 0x17, 0xaa, 0x1f, 0xe3, 0x1d, 0x0b, 0xda, 0x53, 0x27, 0x20, 0x45, 0x59, 0x80,\n            0x15, 0xa8, 0xae, 0x4d, 0x8c, 0xec, 0x22, 0x6f, 0xef, 0xa5, 0x8d, 0xaa, 0x05, 0x50,\n            0x09, 0x06, 0xc4, 0xd8, 0x5e, 0x75, 0x67\n        ],\n        [\n            0xcb, 0x56, 0x48, 0xa1, 0xd6, 0x1c, 0x6c, 0x5b, 0xda, 0xcd, 0x96, 0xf8, 0x1c, 0x95,\n            0x91, 0xde, 0xbc, 0x39, 0x50, 0xdc, 0xf6, 0x58, 0x14, 0x5b, 0x8d, 0x99, 0x65, 0x70,\n            0xba, 0x88, 0x1a, 0x05\n        ]\n    );\n\n    digest_test!(\n        sha3_384_0,\n        sha3_384,\n        384,\n        [0; 0],\n        [\n            0x0c, 0x63, 0xa7, 0x5b, 0x84, 0x5e, 0x4f, 0x7d, 0x01, 0x10, 0x7d, 0x85, 0x2e, 0x4c,\n            0x24, 0x85, 0xc5, 0x1a, 0x50, 0xaa, 0xaa, 0x94, 0xfc, 0x61, 0x99, 0x5e, 0x71, 0xbb,\n            0xee, 0x98, 0x3a, 0x2a, 0xc3, 0x71, 0x38, 0x31, 0x26, 0x4a, 0xdb, 0x47, 0xfb, 0x6b,\n            0xd1, 0xe0, 0x58, 0xd5, 0xf0, 0x04,\n        ]\n    );\n\n    digest_test!(\n        sha3_384_8,\n        sha3_384,\n        384,\n        [0x80u8],\n        [\n            0x75, 0x41, 0x38, 0x48, 0x52, 0xe1, 0x0f, 0xf1, 0x0d, 0x5f, 0xb6, 0xa7, 0x21, 0x3a,\n            0x4a, 0x6c, 0x15, 0xcc, 0xc8, 0x6d, 0x8b, 0xc1, 0x06, 0x8a, 0xc0, 0x4f, 0x69, 0x27,\n            0x71, 0x42, 0x94, 0x4f, 0x4e, 0xe5, 0x0d, 0x91, 0xfd, 0xc5, 0x65, 0x53, 0xdb, 0x06,\n            0xb2, 0xf5, 0x03, 0x9c, 0x8a, 0xb7,\n        ]\n    );\n\n    digest_test!(\n        sha3_384_2512,\n        sha3_384,\n        384,\n        [\n            0x03, 0x5a, 0xdc, 0xb6, 0x39, 0xe5, 0xf2, 0x8b, 0xb5, 0xc8, 0x86, 0x58, 0xf4, 0x5c,\n            0x1c, 0xe0, 0xbe, 0x16, 0xe7, 0xda, 0xfe, 0x08, 0x3b, 0x98, 0xd0, 0xab, 0x45, 0xe8,\n            0xdc, 0xdb, 0xfa, 0x38, 0xe3, 0x23, 0x4d, 0xfd, 0x97, 0x3b, 0xa5, 0x55, 0xb0, 0xcf,\n            0x8e, 0xea, 0x3c, 0x82, 0xae, 0x1a, 0x36, 0x33, 0xfc, 0x56, 0x5b, 0x7f, 0x2c, 0xc8,\n            0x39, 0x87, 0x6d, 0x39, 0x89, 0xf3, 0x57, 0x31, 0xbe, 0x37, 0x1f, 0x60, 0xde, 0x14,\n            0x0e, 0x3c, 0x91, 0x62, 0x31, 0xec, 0x78, 0x0e, 0x51, 0x65, 0xbf, 0x5f, 0x25, 0xd3,\n            0xf6, 0x7d, 0xc7, 0x3a, 0x1c, 0x33, 0x65, 0x5d, 0xfd, 0xf4, 0x39, 0xdf, 0xbf, 0x1c,\n            0xbb, 0xa8, 0xb7, 0x79, 0x15, 0x8a, 0x81, 0x0a, 0xd7, 0x24, 0x4f, 0x06, 0xec, 0x07,\n            0x81, 0x20, 0xcd, 0x18, 0x76, 0x0a, 0xf4, 0x36, 0xa2, 0x38, 0x94, 0x1c, 0xe1, 0xe6,\n            0x87, 0x88, 0x0b, 0x5c, 0x87, 0x9d, 0xc9, 0x71, 0xa2, 0x85, 0xa7, 0x4e, 0xe8, 0x5c,\n            0x6a, 0x74, 0x67, 0x49, 0xa3, 0x01, 0x59, 0xee, 0x84, 0x2e, 0x9b, 0x03, 0xf3, 0x1d,\n            0x61, 0x3d, 0xdd, 0xd2, 0x29, 0x75, 0xcd, 0x7f, 0xed, 0x06, 0xbd, 0x04, 0x9d, 0x77,\n            0x2c, 0xb6, 0xcc, 0x5a, 0x70, 0x5f, 0xaa, 0x73, 0x4e, 0x87, 0x32, 0x1d, 0xc8, 0xf2,\n            0xa4, 0xea, 0x36, 0x6a, 0x36, 0x8a, 0x98, 0xbf, 0x06, 0xee, 0x2b, 0x0b, 0x54, 0xac,\n            0x3a, 0x3a, 0xee, 0xa6, 0x37, 0xca, 0xeb, 0xe7, 0x0a, 0xd0, 0x9c, 0xcd, 0xa9, 0x3c,\n            0xc0, 0x6d, 0xe9, 0x5d, 0xf7, 0x33, 0x94, 0xa8, 0x7a, 0xc9, 0xbb, 0xb5, 0x08, 0x3a,\n            0x4d, 0x8a, 0x24, 0x58, 0xe9, 0x1c, 0x7d, 0x5b, 0xf1, 0x13, 0xae, 0xca, 0xe0, 0xce,\n            0x27, 0x9f, 0xdd, 0xa7, 0x6b, 0xa6, 0x90, 0x78, 0x7d, 0x26, 0x34, 0x5e, 0x94, 0xc3,\n            0xed, 0xbc, 0x16, 0xa3, 0x5c, 0x83, 0xc4, 0xd0, 0x71, 0xb1, 0x32, 0xdd, 0x81, 0x18,\n            0x7b, 0xcd, 0x99, 0x61, 0x32, 0x30, 0x11, 0x50, 0x9c, 0x8f, 0x64, 0x4a, 0x1c, 0x0a,\n            0x3f, 0x14, 0xee, 0x40, 0xd7, 0xdd, 0x18, 0x6f, 0x80, 0x7f, 0x9e, 0xdc, 0x7c, 0x02,\n            0xf6, 0x76, 0x10, 0x61, 0xbb, 0xb6, 0xdd, 0x91, 0xa6, 0xc9, 0x6e, 0xc0, 0xb9, 0xf1,\n            0x0e, 0xdb, 0xbd, 0x29, 0xdc, 0x52\n        ],\n        [\n            0x02, 0x53, 0x5d, 0x86, 0xcc, 0x75, 0x18, 0x48, 0x4a, 0x2a, 0x23, 0x8c, 0x92, 0x1b,\n            0x73, 0x9b, 0x17, 0x04, 0xa5, 0x03, 0x70, 0xa2, 0x92, 0x4a, 0xbf, 0x39, 0x95, 0x8c,\n            0x59, 0x76, 0xe6, 0x58, 0xdc, 0x5e, 0x87, 0x44, 0x00, 0x63, 0x11, 0x24, 0x59, 0xbd,\n            0xdb, 0x40, 0x30, 0x8b, 0x1c, 0x70\n        ]\n    );\n\n    digest_test!(\n        sha3_512_0,\n        sha3_512,\n        512,\n        [0u8; 0],\n        [\n            0xa6, 0x9f, 0x73, 0xcc, 0xa2, 0x3a, 0x9a, 0xc5, 0xc8, 0xb5, 0x67, 0xdc, 0x18, 0x5a,\n            0x75, 0x6e, 0x97, 0xc9, 0x82, 0x16, 0x4f, 0xe2, 0x58, 0x59, 0xe0, 0xd1, 0xdc, 0xc1,\n            0x47, 0x5c, 0x80, 0xa6, 0x15, 0xb2, 0x12, 0x3a, 0xf1, 0xf5, 0xf9, 0x4c, 0x11, 0xe3,\n            0xe9, 0x40, 0x2c, 0x3a, 0xc5, 0x58, 0xf5, 0x00, 0x19, 0x9d, 0x95, 0xb6, 0xd3, 0xe3,\n            0x01, 0x75, 0x85, 0x86, 0x28, 0x1d, 0xcd, 0x26,\n        ]\n    );\n\n    digest_test!(\n        sha3_512_8,\n        sha3_512,\n        512,\n        [0xe5u8],\n        [\n            0x15, 0x02, 0x40, 0xba, 0xf9, 0x5f, 0xb3, 0x6f, 0x8c, 0xcb, 0x87, 0xa1, 0x9a, 0x41,\n            0x76, 0x7e, 0x7a, 0xed, 0x95, 0x12, 0x50, 0x75, 0xa2, 0xb2, 0xdb, 0xba, 0x6e, 0x56,\n            0x5e, 0x1c, 0xe8, 0x57, 0x5f, 0x2b, 0x04, 0x2b, 0x62, 0xe2, 0x9a, 0x04, 0xe9, 0x44,\n            0x03, 0x14, 0xa8, 0x21, 0xc6, 0x22, 0x41, 0x82, 0x96, 0x4d, 0x8b, 0x55, 0x7b, 0x16,\n            0xa4, 0x92, 0xb3, 0x80, 0x6f, 0x4c, 0x39, 0xc1\n        ]\n    );\n\n    digest_test!(\n        sha3_512_4080,\n        sha3_512,\n        512,\n        [\n            0x43, 0x02, 0x56, 0x15, 0x52, 0x1d, 0x66, 0xfe, 0x8e, 0xc3, 0xa3, 0xf8, 0xcc, 0xc5,\n            0xab, 0xfa, 0xb8, 0x70, 0xa4, 0x62, 0xc6, 0xb3, 0xd1, 0x39, 0x6b, 0x84, 0x62, 0xb9,\n            0x8c, 0x7f, 0x91, 0x0c, 0x37, 0xd0, 0xea, 0x57, 0x91, 0x54, 0xea, 0xf7, 0x0f, 0xfb,\n            0xcc, 0x0b, 0xe9, 0x71, 0xa0, 0x32, 0xcc, 0xfd, 0x9d, 0x96, 0xd0, 0xa9, 0xb8, 0x29,\n            0xa9, 0xa3, 0x76, 0x2e, 0x21, 0xe3, 0xfe, 0xfc, 0xc6, 0x0e, 0x72, 0xfe, 0xdf, 0x9a,\n            0x7f, 0xff, 0xa5, 0x34, 0x33, 0xa4, 0xb0, 0x5e, 0x0f, 0x3a, 0xb0, 0x5d, 0x5e, 0xb2,\n            0x5d, 0x52, 0xc5, 0xea, 0xb1, 0xa7, 0x1a, 0x2f, 0x54, 0xac, 0x79, 0xff, 0x58, 0x82,\n            0x95, 0x13, 0x26, 0x39, 0x4d, 0x9d, 0xb8, 0x35, 0x80, 0xce, 0x09, 0xd6, 0x21, 0x9b,\n            0xca, 0x58, 0x8e, 0xc1, 0x57, 0xf7, 0x1d, 0x06, 0xe9, 0x57, 0xf8, 0xc2, 0x0d, 0x24,\n            0x2c, 0x9f, 0x55, 0xf5, 0xfc, 0x9d, 0x4d, 0x77, 0x7b, 0x59, 0xb0, 0xc7, 0x5a, 0x8e,\n            0xdc, 0x1f, 0xfe, 0xdc, 0x84, 0xb5, 0xd5, 0xc8, 0xa5, 0xe0, 0xeb, 0x05, 0xbb, 0x7d,\n            0xb8, 0xf2, 0x34, 0x91, 0x3d, 0x63, 0x25, 0x30, 0x4f, 0xa4, 0x3c, 0x9d, 0x32, 0xbb,\n            0xf6, 0xb2, 0x69, 0xee, 0x11, 0x82, 0xcd, 0x85, 0x45, 0x3e, 0xdd, 0xd1, 0x2f, 0x55,\n            0x55, 0x6d, 0x8e, 0xdf, 0x02, 0xc4, 0xb1, 0x3c, 0xd4, 0xd3, 0x30, 0xf8, 0x35, 0x31,\n            0xdb, 0xf2, 0x99, 0x4c, 0xf0, 0xbe, 0x56, 0xf5, 0x91, 0x47, 0xb7, 0x1f, 0x74, 0xb9,\n            0x4b, 0xe3, 0xdd, 0x9e, 0x83, 0xc8, 0xc9, 0x47, 0x7c, 0x42, 0x6c, 0x6d, 0x1a, 0x78,\n            0xde, 0x18, 0x56, 0x4a, 0x12, 0xc0, 0xd9, 0x93, 0x07, 0xb2, 0xc9, 0xab, 0x42, 0xb6,\n            0xe3, 0x31, 0x7b, 0xef, 0xca, 0x07, 0x97, 0x02, 0x9e, 0x9d, 0xd6, 0x7b, 0xd1, 0x73,\n            0x4e, 0x6c, 0x36, 0xd9, 0x98, 0x56, 0x5b, 0xfa, 0xc9, 0x4d, 0x19, 0x18, 0xa3, 0x58,\n            0x69, 0x19, 0x0d, 0x17, 0x79, 0x43, 0xc1, 0xa8, 0x00, 0x44, 0x45, 0xca, 0xce, 0x75,\n            0x1c, 0x43, 0xa7, 0x5f, 0x3d, 0x80, 0x51, 0x7f, 0xc4, 0x7c, 0xec, 0x46, 0xe8, 0xe3,\n            0x82, 0x64, 0x2d, 0x76, 0xdf, 0x46, 0xda, 0xb1, 0xa3, 0xdd, 0xae, 0xab, 0x95, 0xa2,\n            0xcf, 0x3f, 0x3a, 0xd7, 0x03, 0x69, 0xa7, 0x0f, 0x22, 0xf2, 0x93, 0xf0, 0xcc, 0x50,\n            0xb0, 0x38, 0x57, 0xc8, 0x3c, 0xfe, 0x0b, 0xd5, 0xd2, 0x3b, 0x92, 0xcd, 0x87, 0x88,\n            0xaa, 0xc2, 0x32, 0x29, 0x1d, 0xa6, 0x0b, 0x4b, 0xf3, 0xb3, 0x78, 0x8a, 0xe6, 0x0a,\n            0x23, 0xb6, 0x16, 0x9b, 0x50, 0xd7, 0xfe, 0x44, 0x6e, 0x6e, 0xa7, 0x3d, 0xeb, 0xfe,\n            0x1b, 0xb3, 0x4d, 0xcb, 0x1d, 0xb3, 0x7f, 0xe2, 0x17, 0x4a, 0x68, 0x59, 0x54, 0xeb,\n            0xc2, 0xd8, 0x6f, 0x10, 0x2a, 0x59, 0x0c, 0x24, 0x73, 0x2b, 0xc5, 0xa1, 0x40, 0x3d,\n            0x68, 0x76, 0xd2, 0x99, 0x5f, 0xab, 0x1e, 0x2f, 0x6f, 0x47, 0x23, 0xd4, 0xa6, 0x72,\n            0x7a, 0x8a, 0x8e, 0xd7, 0x2f, 0x02, 0xa7, 0x4c, 0xcf, 0x5f, 0x14, 0xb5, 0xc2, 0x3d,\n            0x95, 0x25, 0xdb, 0xf2, 0xb5, 0x47, 0x2e, 0x13, 0x45, 0xfd, 0x22, 0x3b, 0x08, 0x46,\n            0xc7, 0x07, 0xb0, 0x65, 0x69, 0x65, 0x09, 0x40, 0x65, 0x0f, 0x75, 0x06, 0x3b, 0x52,\n            0x98, 0x14, 0xe5, 0x14, 0x54, 0x1a, 0x67, 0x15, 0xf8, 0x79, 0xa8, 0x75, 0xb4, 0xf0,\n            0x80, 0x77, 0x51, 0x78, 0x12, 0x84, 0x1e, 0x6c, 0x5c, 0x73, 0x2e, 0xed, 0x0c, 0x07,\n            0xc0, 0x85, 0x95, 0xb9, 0xff, 0x0a, 0x83, 0xb8, 0xec, 0xc6, 0x0b, 0x2f, 0x98, 0xd4,\n            0xe7, 0xc6, 0x96, 0xcd, 0x61, 0x6b, 0xb0, 0xa5, 0xad, 0x52, 0xd9, 0xcf, 0x7b, 0x3a,\n            0x63, 0xa8, 0xcd, 0xf3, 0x72, 0x12\n        ],\n        [\n            0xe7, 0xba, 0x73, 0x40, 0x7a, 0xa4, 0x56, 0xae, 0xce, 0x21, 0x10, 0x77, 0xd9, 0x20,\n            0x87, 0xd5, 0xcd, 0x28, 0x3e, 0x38, 0x68, 0xd2, 0x84, 0xe0, 0x7e, 0xd1, 0x24, 0xb2,\n            0x7c, 0xbc, 0x66, 0x4a, 0x6a, 0x47, 0x5a, 0x8d, 0x7b, 0x4c, 0xf6, 0xa8, 0xa4, 0x92,\n            0x7e, 0xe0, 0x59, 0xa2, 0x62, 0x6a, 0x4f, 0x98, 0x39, 0x23, 0x36, 0x01, 0x45, 0xb2,\n            0x65, 0xeb, 0xfd, 0x4f, 0x5b, 0x3c, 0x44, 0xfd\n        ]\n    );\n}\n"
  },
  {
    "path": "src/ciphers/tea.rs",
    "content": "use std::num::Wrapping as W;\n\nstruct TeaContext {\n    key0: u64,\n    key1: u64,\n}\n\nimpl TeaContext {\n    pub fn new(key: &[u64; 2]) -> TeaContext {\n        TeaContext {\n            key0: key[0],\n            key1: key[1],\n        }\n    }\n\n    pub fn encrypt_block(&self, block: u64) -> u64 {\n        let (mut b0, mut b1) = divide_u64(block);\n        let (k0, k1) = divide_u64(self.key0);\n        let (k2, k3) = divide_u64(self.key1);\n        let mut sum = W(0u32);\n\n        for _ in 0..32 {\n            sum += W(0x9E3779B9);\n            b0 += ((b1 << 4) + k0) ^ (b1 + sum) ^ ((b1 >> 5) + k1);\n            b1 += ((b0 << 4) + k2) ^ (b0 + sum) ^ ((b0 >> 5) + k3);\n        }\n\n        ((b1.0 as u64) << 32) | b0.0 as u64\n    }\n\n    pub fn decrypt_block(&self, block: u64) -> u64 {\n        let (mut b0, mut b1) = divide_u64(block);\n        let (k0, k1) = divide_u64(self.key0);\n        let (k2, k3) = divide_u64(self.key1);\n        let mut sum = W(0xC6EF3720u32);\n\n        for _ in 0..32 {\n            b1 -= ((b0 << 4) + k2) ^ (b0 + sum) ^ ((b0 >> 5) + k3);\n            b0 -= ((b1 << 4) + k0) ^ (b1 + sum) ^ ((b1 >> 5) + k1);\n            sum -= W(0x9E3779B9);\n        }\n\n        ((b1.0 as u64) << 32) | b0.0 as u64\n    }\n}\n\n#[inline]\nfn divide_u64(n: u64) -> (W<u32>, W<u32>) {\n    (W(n as u32), W((n >> 32) as u32))\n}\n\npub fn tea_encrypt(plain: &[u8], key: &[u8]) -> Vec<u8> {\n    let tea = TeaContext::new(&[to_block(&key[..8]), to_block(&key[8..16])]);\n    let mut result: Vec<u8> = Vec::new();\n\n    for i in (0..plain.len()).step_by(8) {\n        let block = to_block(&plain[i..i + 8]);\n        result.extend(from_block(tea.encrypt_block(block)).iter());\n    }\n\n    result\n}\n\npub fn tea_decrypt(cipher: &[u8], key: &[u8]) -> Vec<u8> {\n    let tea = TeaContext::new(&[to_block(&key[..8]), to_block(&key[8..16])]);\n    let mut result: Vec<u8> = Vec::new();\n\n    for i in (0..cipher.len()).step_by(8) {\n        let block = to_block(&cipher[i..i + 8]);\n        result.extend(from_block(tea.decrypt_block(block)).iter());\n    }\n\n    result\n}\n\n#[inline]\nfn to_block(data: &[u8]) -> u64 {\n    data[0] as u64\n        | (data[1] as u64) << 8\n        | (data[2] as u64) << 16\n        | (data[3] as u64) << 24\n        | (data[4] as u64) << 32\n        | (data[5] as u64) << 40\n        | (data[6] as u64) << 48\n        | (data[7] as u64) << 56\n}\n\nfn from_block(block: u64) -> [u8; 8] {\n    [\n        block as u8,\n        (block >> 8) as u8,\n        (block >> 16) as u8,\n        (block >> 24) as u8,\n        (block >> 32) as u8,\n        (block >> 40) as u8,\n        (block >> 48) as u8,\n        (block >> 56) as u8,\n    ]\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_block_convert() {\n        assert_eq!(\n            to_block(&[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]),\n            0xefcdab8967452301\n        );\n\n        assert_eq!(\n            from_block(0xefcdab8967452301),\n            [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]\n        );\n    }\n\n    #[test]\n    fn test_tea_encrypt() {\n        assert_eq!(\n            tea_encrypt(\n                &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],\n                &[\n                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n                    0x00, 0x00, 0x00\n                ]\n            ),\n            [0x0A, 0x3A, 0xEA, 0x41, 0x40, 0xA9, 0xBA, 0x94]\n        );\n    }\n\n    #[test]\n    fn test_tea_encdec() {\n        let plain = &[0x1b, 0xcc, 0xd4, 0x31, 0xa0, 0xf6, 0x8a, 0x55];\n        let key = &[\n            0x20, 0x45, 0x08, 0x10, 0xb0, 0x23, 0xe2, 0x17, 0xc3, 0x81, 0xd6, 0xf2, 0xee, 0x00,\n            0xa4, 0x8a,\n        ];\n        let cipher = tea_encrypt(plain, key);\n\n        assert_eq!(tea_decrypt(&cipher[..], key), plain);\n    }\n}\n"
  },
  {
    "path": "src/ciphers/theoretical_rot13.rs",
    "content": "// in theory rot-13 only affects the lowercase characters in a cipher\npub fn theoretical_rot13(text: &str) -> String {\n    let mut pos: u8 = 0;\n    let mut npos: u8 = 0;\n    text.to_owned()\n        .chars()\n        .map(|mut c| {\n            if c.is_ascii_lowercase() {\n                // ((c as u8) + 13) as char\n                pos = c as u8 - b'a';\n                npos = (pos + 13) % 26;\n                c = (npos + b'a') as char;\n                c\n            } else {\n                c\n            }\n        })\n        .collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_single_letter() {\n        assert_eq!(\"n\", theoretical_rot13(\"a\"));\n    }\n    #[test]\n    fn test_bunch_of_letters() {\n        assert_eq!(\"nop op\", theoretical_rot13(\"abc bc\"));\n    }\n\n    #[test]\n    fn test_non_ascii() {\n        assert_eq!(\"😀ab\", theoretical_rot13(\"😀no\"));\n    }\n\n    #[test]\n    fn test_twice() {\n        assert_eq!(\"abcd\", theoretical_rot13(&theoretical_rot13(\"abcd\")));\n    }\n}\n"
  },
  {
    "path": "src/ciphers/transposition.rs",
    "content": "//! Transposition Cipher\n//!\n//! The Transposition Cipher is a method of encryption by which a message is shifted\n//! according to a regular system, so that the ciphertext is a rearrangement of the\n//! original message. The most commonly referred to Transposition Cipher is the\n//! COLUMNAR TRANSPOSITION cipher, which is demonstrated below.\n\nuse std::ops::RangeInclusive;\n\n/// Encrypts or decrypts a message, using multiple keys. The\n/// encryption is based on the columnar transposition method.\npub fn transposition(decrypt_mode: bool, msg: &str, key: &str) -> String {\n    let key_uppercase = key.to_uppercase();\n    let mut cipher_msg: String = msg.to_string();\n\n    let keys: Vec<&str> = if decrypt_mode {\n        key_uppercase.split_whitespace().rev().collect()\n    } else {\n        key_uppercase.split_whitespace().collect()\n    };\n\n    for cipher_key in keys.iter() {\n        let mut key_order: Vec<usize> = Vec::new();\n\n        // Removes any non-alphabet characters from 'msg'\n        cipher_msg = cipher_msg\n            .to_uppercase()\n            .chars()\n            .filter(|&c| c.is_ascii_alphabetic())\n            .collect();\n\n        // Determines the sequence of the columns, as dictated by the\n        // alphabetical order of the keyword's letters\n        let mut key_ascii: Vec<(usize, u8)> =\n            cipher_key.bytes().enumerate().collect::<Vec<(usize, u8)>>();\n\n        key_ascii.sort_by_key(|&(_, key)| key);\n\n        for (counter, (_, key)) in key_ascii.iter_mut().enumerate() {\n            *key = counter as u8;\n        }\n\n        key_ascii.sort_by_key(|&(index, _)| index);\n\n        for (_, key) in key_ascii {\n            key_order.push(key.into());\n        }\n\n        // Determines whether to encrypt or decrypt the message,\n        // and returns the result\n        cipher_msg = if decrypt_mode {\n            decrypt(cipher_msg, key_order)\n        } else {\n            encrypt(cipher_msg, key_order)\n        };\n    }\n\n    cipher_msg\n}\n\n/// Performs the columnar transposition encryption\nfn encrypt(mut msg: String, key_order: Vec<usize>) -> String {\n    let mut encrypted_msg: String = String::from(\"\");\n    let mut encrypted_vec: Vec<String> = Vec::new();\n\n    let msg_len = msg.len();\n    let key_len: usize = key_order.len();\n\n    let mut msg_index: usize = msg_len;\n    let mut key_index: usize = key_len;\n\n    // Loop each column, pushing it to a Vec<T>\n    while !msg.is_empty() {\n        let mut chars: String = String::from(\"\");\n        let mut index: usize = 0;\n        key_index -= 1;\n\n        // Loop every nth character, determined by key length, to create a column\n        while index < msg_index {\n            let ch = msg.remove(index);\n            chars.push(ch);\n\n            index += key_index;\n            msg_index -= 1;\n        }\n\n        encrypted_vec.push(chars);\n    }\n\n    // Concatenate the columns into a string, determined by the\n    // alphabetical order of the keyword's characters\n    let mut indexed_vec: Vec<(usize, &String)> = Vec::new();\n    let mut indexed_msg: String = String::from(\"\");\n\n    for (counter, key_index) in key_order.into_iter().enumerate() {\n        indexed_vec.push((key_index, &encrypted_vec[counter]));\n    }\n\n    indexed_vec.sort();\n\n    for (_, column) in indexed_vec {\n        indexed_msg.push_str(column);\n    }\n\n    // Split the message by a space every nth character, determined by\n    // 'message length divided by keyword length' to the next highest integer.\n    let msg_div: usize = (msg_len as f32 / key_len as f32).ceil() as usize;\n    let mut counter: usize = 0;\n\n    indexed_msg.chars().for_each(|c| {\n        encrypted_msg.push(c);\n        counter += 1;\n        if counter == msg_div {\n            encrypted_msg.push(' ');\n            counter = 0;\n        }\n    });\n\n    encrypted_msg.trim_end().to_string()\n}\n\n/// Performs the columnar transposition decryption\nfn decrypt(mut msg: String, key_order: Vec<usize>) -> String {\n    let mut decrypted_msg: String = String::from(\"\");\n    let mut decrypted_vec: Vec<String> = Vec::new();\n    let mut indexed_vec: Vec<(usize, String)> = Vec::new();\n\n    let msg_len = msg.len();\n    let key_len: usize = key_order.len();\n\n    // Split the message into columns, determined by 'message length divided by keyword length'.\n    // Some columns are larger by '+1', where the prior calculation leaves a remainder.\n    let split_size: usize = (msg_len as f64 / key_len as f64) as usize;\n    let msg_mod: usize = msg_len % key_len;\n    let mut counter: usize = msg_mod;\n\n    let mut key_split: Vec<usize> = key_order.clone();\n    let (split_large, split_small) = key_split.split_at_mut(msg_mod);\n\n    split_large.sort_unstable();\n    split_small.sort_unstable();\n\n    split_large.iter_mut().rev().for_each(|key_index| {\n        counter -= 1;\n        let range: RangeInclusive<usize> =\n            ((*key_index * split_size) + counter)..=(((*key_index + 1) * split_size) + counter);\n\n        let slice: String = msg[range.clone()].to_string();\n        indexed_vec.push((*key_index, slice));\n\n        msg.replace_range(range, \"\");\n    });\n\n    for key_index in split_small.iter_mut() {\n        let (slice, rest_of_msg) = msg.split_at(split_size);\n        indexed_vec.push((*key_index, (slice.to_string())));\n        msg = rest_of_msg.to_string();\n    }\n\n    indexed_vec.sort();\n\n    for key in key_order {\n        if let Some((_, column)) = indexed_vec.iter().find(|(key_index, _)| key_index == &key) {\n            decrypted_vec.push(column.clone());\n        }\n    }\n\n    // Concatenate the columns into a string, determined by the\n    // alphabetical order of the keyword's characters\n    for _ in 0..split_size {\n        decrypted_vec.iter_mut().for_each(|column| {\n            decrypted_msg.push(column.remove(0));\n        })\n    }\n\n    if !decrypted_vec.is_empty() {\n        decrypted_vec.into_iter().for_each(|chars| {\n            decrypted_msg.push_str(&chars);\n        })\n    }\n\n    decrypted_msg\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn encryption() {\n        assert_eq!(\n            transposition(\n                false,\n                \"The quick brown fox jumps over the lazy dog\",\n                \"Archive\",\n            ),\n            \"TKOOL ERJEZ CFSEG QOURY UWMTD HBXVA INPHO\"\n        );\n\n        assert_eq!(\n            transposition(\n                false,\n                \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,/;'[]{}:|_+=-`~() \",\n                \"Tenacious\"\n            ),\n            \"DMVENW ENWFOX BKTCLU FOXGPY CLUDMV GPYHQZ IRAJSA JSBKTH QZIR\"\n        );\n\n        assert_eq!(\n            transposition(false, \"WE ARE DISCOVERED. FLEE AT ONCE.\", \"ZEBRAS\"),\n            \"EVLNA CDTES EAROF ODEEC WIREE\"\n        );\n    }\n\n    #[test]\n    fn decryption() {\n        assert_eq!(\n            transposition(true, \"TKOOL ERJEZ CFSEG QOURY UWMTD HBXVA INPHO\", \"Archive\"),\n            \"THEQUICKBROWNFOXJUMPSOVERTHELAZYDOG\"\n        );\n\n        assert_eq!(\n            transposition(\n                true,\n                \"DMVENW ENWFOX BKTCLU FOXGPY CLUDMV GPYHQZ IRAJSA JSBKTH QZIR\",\n                \"Tenacious\"\n            ),\n            \"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n        );\n\n        assert_eq!(\n            transposition(true, \"EVLNA CDTES EAROF ODEEC WIREE\", \"ZEBRAS\"),\n            \"WEAREDISCOVEREDFLEEATONCE\"\n        );\n    }\n\n    #[test]\n    fn double_encryption() {\n        assert_eq!(\n            transposition(\n                false,\n                \"The quick brown fox jumps over the lazy dog\",\n                \"Archive Snow\"\n            ),\n            \"KEZEUWHAH ORCGRMBIO TLESOUDVP OJFQYTXN\"\n        );\n\n        assert_eq!(\n            transposition(\n                false,\n                \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,/;'[]{}:|_+=-`~() \",\n                \"Tenacious Drink\"\n            ),\n            \"DWOCXLGZSKI VNBUPDYRJHN FTOCVQJBZEW KFYMHASQMEX LGUPIATR\"\n        );\n\n        assert_eq!(\n            transposition(false, \"WE ARE DISCOVERED. FLEE AT ONCE.\", \"ZEBRAS STRIPE\"),\n            \"CAEEN SOIAE DRLEF WEDRE EVTOC\"\n        );\n    }\n\n    #[test]\n    fn double_decryption() {\n        assert_eq!(\n            transposition(\n                true,\n                \"KEZEUWHAH ORCGRMBIO TLESOUDVP OJFQYTXN\",\n                \"Archive Snow\"\n            ),\n            \"THEQUICKBROWNFOXJUMPSOVERTHELAZYDOG\"\n        );\n\n        assert_eq!(\n            transposition(\n                true,\n                \"DWOCXLGZSKI VNBUPDYRJHN FTOCVQJBZEW KFYMHASQMEX LGUPIATR\",\n                \"Tenacious Drink\",\n            ),\n            \"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n        );\n\n        assert_eq!(\n            transposition(true, \"CAEEN SOIAE DRLEF WEDRE EVTOC\", \"ZEBRAS STRIPE\"),\n            \"WEAREDISCOVEREDFLEEATONCE\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/ciphers/trifid.rs",
    "content": "//! The Trifid cipher uses a table to fractionate each plaintext letter into a trigram,\n//! mixes the constituents of the trigrams, and then applies the table in reverse to turn\n//! these mixed trigrams into ciphertext letters.\n//!\n//! [Wikipedia reference](https://en.wikipedia.org/wiki/Trifid_cipher)\n\nuse std::collections::HashMap;\n\ntype CharToNum = HashMap<char, String>;\ntype NumToChar = HashMap<String, char>;\ntype PrepareResult = Result<(String, String, CharToNum, NumToChar), String>;\n\nconst TRIGRAM_VALUES: [&str; 27] = [\n    \"111\", \"112\", \"113\", \"121\", \"122\", \"123\", \"131\", \"132\", \"133\", \"211\", \"212\", \"213\", \"221\",\n    \"222\", \"223\", \"231\", \"232\", \"233\", \"311\", \"312\", \"313\", \"321\", \"322\", \"323\", \"331\", \"332\",\n    \"333\",\n];\n\n/// Encrypts a message using the Trifid cipher.\n///\n/// # Arguments\n///\n/// * `message` - The message to encrypt\n/// * `alphabet` - The characters to be used for the cipher (must be 27 characters)\n/// * `period` - The number of characters in a group whilst encrypting\npub fn trifid_encrypt(message: &str, alphabet: &str, period: usize) -> Result<String, String> {\n    let (message, _alphabet, char_to_num, num_to_char) = prepare(message, alphabet)?;\n\n    let mut encrypted_numeric = String::new();\n    let chars: Vec<char> = message.chars().collect();\n\n    for chunk in chars.chunks(period) {\n        let chunk_str: String = chunk.iter().collect();\n        encrypted_numeric.push_str(&encrypt_part(&chunk_str, &char_to_num));\n    }\n\n    let mut encrypted = String::new();\n    let numeric_chars: Vec<char> = encrypted_numeric.chars().collect();\n\n    for chunk in numeric_chars.chunks(3) {\n        let trigram: String = chunk.iter().collect();\n        if let Some(ch) = num_to_char.get(&trigram) {\n            encrypted.push(*ch);\n        }\n    }\n\n    Ok(encrypted)\n}\n\n/// Decrypts a Trifid cipher encrypted message.\n///\n/// # Arguments\n///\n/// * `message` - The message to decrypt\n/// * `alphabet` - The characters used for the cipher (must be 27 characters)\n/// * `period` - The number of characters used in grouping when it was encrypted\npub fn trifid_decrypt(message: &str, alphabet: &str, period: usize) -> Result<String, String> {\n    let (message, _alphabet, char_to_num, num_to_char) = prepare(message, alphabet)?;\n\n    let mut decrypted_numeric = Vec::new();\n    let chars: Vec<char> = message.chars().collect();\n\n    for chunk in chars.chunks(period) {\n        let chunk_str: String = chunk.iter().collect();\n        let (a, b, c) = decrypt_part(&chunk_str, &char_to_num);\n\n        for i in 0..a.len() {\n            let trigram = format!(\n                \"{}{}{}\",\n                a.chars().nth(i).unwrap(),\n                b.chars().nth(i).unwrap(),\n                c.chars().nth(i).unwrap()\n            );\n            decrypted_numeric.push(trigram);\n        }\n    }\n\n    let mut decrypted = String::new();\n    for trigram in decrypted_numeric {\n        if let Some(ch) = num_to_char.get(&trigram) {\n            decrypted.push(*ch);\n        }\n    }\n\n    Ok(decrypted)\n}\n\n/// Arranges the trigram value of each letter of message_part vertically and joins\n/// them horizontally.\nfn encrypt_part(message_part: &str, char_to_num: &CharToNum) -> String {\n    let mut one = String::new();\n    let mut two = String::new();\n    let mut three = String::new();\n\n    for ch in message_part.chars() {\n        if let Some(trigram) = char_to_num.get(&ch) {\n            let chars: Vec<char> = trigram.chars().collect();\n            one.push(chars[0]);\n            two.push(chars[1]);\n            three.push(chars[2]);\n        }\n    }\n\n    format!(\"{one}{two}{three}\")\n}\n\n/// Converts each letter of the input string into their respective trigram values,\n/// joins them and splits them into three equal groups of strings which are returned.\nfn decrypt_part(message_part: &str, char_to_num: &CharToNum) -> (String, String, String) {\n    let mut this_part = String::new();\n\n    for ch in message_part.chars() {\n        if let Some(trigram) = char_to_num.get(&ch) {\n            this_part.push_str(trigram);\n        }\n    }\n\n    let part_len = message_part.len();\n\n    if part_len == 0 {\n        return (String::new(), String::new(), String::new());\n    }\n\n    let chars: Vec<char> = this_part.chars().collect();\n\n    let mut result = Vec::new();\n    for chunk in chars.chunks(part_len) {\n        result.push(chunk.iter().collect::<String>());\n    }\n\n    // Ensure we have exactly 3 parts, pad with empty strings if necessary\n    while result.len() < 3 {\n        result.push(String::new());\n    }\n\n    (result[0].clone(), result[1].clone(), result[2].clone())\n}\n\n/// Prepares the message and alphabet for encryption/decryption.\n/// Validates inputs and creates the character-to-number and number-to-character mappings.\nfn prepare(message: &str, alphabet: &str) -> PrepareResult {\n    // Remove spaces and convert to uppercase\n    let alphabet: String = alphabet.chars().filter(|c| !c.is_whitespace()).collect();\n    let alphabet = alphabet.to_uppercase();\n    let message: String = message.chars().filter(|c| !c.is_whitespace()).collect();\n    let message = message.to_uppercase();\n\n    // Validate alphabet length\n    if alphabet.len() != 27 {\n        return Err(\"Length of alphabet has to be 27.\".to_string());\n    }\n\n    // Validate that all message characters are in the alphabet\n    for ch in message.chars() {\n        if !alphabet.contains(ch) {\n            return Err(\"Each message character has to be included in alphabet!\".to_string());\n        }\n    }\n\n    // Create character-to-number mapping\n    let mut char_to_num = HashMap::new();\n    let mut num_to_char = HashMap::new();\n\n    for (i, ch) in alphabet.chars().enumerate() {\n        let trigram = TRIGRAM_VALUES[i].to_string();\n        char_to_num.insert(ch, trigram.clone());\n        num_to_char.insert(trigram, ch);\n    }\n\n    Ok((message, alphabet, char_to_num, num_to_char))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    const DEFAULT_ALPHABET: &str = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ.\";\n\n    #[test]\n    fn test_encrypt_basic() {\n        let result = trifid_encrypt(\"I am a boy\", DEFAULT_ALPHABET, 5);\n        assert_eq!(result, Ok(\"BCDGBQY\".to_string()));\n    }\n\n    #[test]\n    fn test_encrypt_empty() {\n        let result = trifid_encrypt(\" \", DEFAULT_ALPHABET, 5);\n        assert_eq!(result, Ok(\"\".to_string()));\n    }\n\n    #[test]\n    fn test_encrypt_custom_alphabet() {\n        let result = trifid_encrypt(\n            \"aide toi le c iel ta id era\",\n            \"FELIXMARDSTBCGHJKNOPQUVWYZ+\",\n            5,\n        );\n        assert_eq!(result, Ok(\"FMJFVOISSUFTFPUFEQQC\".to_string()));\n    }\n\n    #[test]\n    fn test_decrypt_basic() {\n        let result = trifid_decrypt(\"BCDGBQY\", DEFAULT_ALPHABET, 5);\n        assert_eq!(result, Ok(\"IAMABOY\".to_string()));\n    }\n\n    #[test]\n    fn test_decrypt_custom_alphabet() {\n        let result = trifid_decrypt(\"FMJFVOISSUFTFPUFEQQC\", \"FELIXMARDSTBCGHJKNOPQUVWYZ+\", 5);\n        assert_eq!(result, Ok(\"AIDETOILECIELTAIDERA\".to_string()));\n    }\n\n    #[test]\n    fn test_encrypt_decrypt_roundtrip() {\n        let msg = \"DEFEND THE EAST WALL OF THE CASTLE.\";\n        let alphabet = \"EPSDUCVWYM.ZLKXNBTFGORIJHAQ\";\n        let encrypted = trifid_encrypt(msg, alphabet, 5).unwrap();\n        let decrypted = trifid_decrypt(&encrypted, alphabet, 5).unwrap();\n        assert_eq!(decrypted, msg.replace(' ', \"\"));\n    }\n\n    #[test]\n    fn test_invalid_alphabet_length() {\n        let result = trifid_encrypt(\"test\", \"ABCDEFGHIJKLMNOPQRSTUVW\", 5);\n        assert!(result.is_err());\n        assert_eq!(result.unwrap_err(), \"Length of alphabet has to be 27.\");\n    }\n\n    #[test]\n    fn test_invalid_character_in_message() {\n        let result = trifid_encrypt(\"am i a boy?\", \"ABCDEFGHIJKLMNOPQRSTUVWXYZ+\", 5);\n        assert!(result.is_err());\n        assert_eq!(\n            result.unwrap_err(),\n            \"Each message character has to be included in alphabet!\"\n        );\n    }\n\n    #[test]\n    fn test_encrypt_part() {\n        let mut char_to_num = HashMap::new();\n        char_to_num.insert('A', \"111\".to_string());\n        char_to_num.insert('S', \"311\".to_string());\n        char_to_num.insert('K', \"212\".to_string());\n\n        let result = encrypt_part(\"ASK\", &char_to_num);\n        assert_eq!(result, \"132111112\");\n    }\n\n    #[test]\n    fn test_decrypt_part() {\n        let mut char_to_num = HashMap::new();\n        for (i, ch) in DEFAULT_ALPHABET.chars().enumerate() {\n            char_to_num.insert(ch, TRIGRAM_VALUES[i].to_string());\n        }\n\n        let (a, b, c) = decrypt_part(\"ABCDE\", &char_to_num);\n        assert_eq!(a, \"11111\");\n        assert_eq!(b, \"21131\");\n        assert_eq!(c, \"21122\");\n    }\n\n    #[test]\n    fn test_decrypt_part_single_char() {\n        let mut char_to_num = HashMap::new();\n        char_to_num.insert('A', \"111\".to_string());\n\n        let (a, b, c) = decrypt_part(\"A\", &char_to_num);\n        assert_eq!(a, \"1\");\n        assert_eq!(b, \"1\");\n        assert_eq!(c, \"1\");\n    }\n\n    #[test]\n    fn test_decrypt_part_empty() {\n        let char_to_num = HashMap::new();\n        let (a, b, c) = decrypt_part(\"\", &char_to_num);\n        assert_eq!(a, \"\");\n        assert_eq!(b, \"\");\n        assert_eq!(c, \"\");\n    }\n\n    #[test]\n    fn test_decrypt_part_with_unmapped_chars() {\n        let mut char_to_num = HashMap::new();\n        char_to_num.insert('A', \"111\".to_string());\n        // 'B' and 'C' are not in the mapping, so this_part will only contain A's trigram\n        // With message_part length of 3, chunks will be size 3, giving us one chunk \"111\"\n        // The padding logic will add two empty strings\n        let (a, b, c) = decrypt_part(\"ABC\", &char_to_num);\n        assert_eq!(a, \"111\");\n        assert_eq!(b, \"\");\n        assert_eq!(c, \"\");\n    }\n}\n"
  },
  {
    "path": "src/ciphers/vernam.rs",
    "content": "//! Vernam Cipher\n//!\n//! The Vernam cipher is a symmetric stream cipher where plaintext is combined\n//! with a random or pseudorandom stream of data (the key) of the same length.\n//! This implementation uses the alphabet A-Z with modular arithmetic.\n//!\n//! # Algorithm\n//!\n//! For encryption: C = (P + K) mod 26\n//! For decryption: P = (C - K) mod 26\n//!\n//! Where P is plaintext, K is key, and C is ciphertext (all converted to 0-25 range)\n\n/// Encrypts a plaintext string using the Vernam cipher.\n///\n/// The function converts all input to uppercase and works only with letters A-Z.\n/// The key is repeated cyclically if it's shorter than the plaintext.\n///\n/// # Arguments\n///\n/// * `plaintext` - The text to encrypt (will be converted to uppercase)\n/// * `key` - The encryption key (will be converted to uppercase, must not be empty)\n///\n/// # Returns\n///\n/// The encrypted ciphertext as an uppercase string\n///\n/// # Panics\n///\n/// Panics if the key is empty\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::ciphers::vernam_encrypt;\n///\n/// let ciphertext = vernam_encrypt(\"HELLO\", \"KEY\");\n/// assert_eq!(ciphertext, \"RIJVS\");\n/// ```\npub fn vernam_encrypt(plaintext: &str, key: &str) -> String {\n    assert!(!key.is_empty(), \"Key cannot be empty\");\n\n    let plaintext = plaintext.to_uppercase();\n    let key = key.to_uppercase();\n\n    let plaintext_bytes: Vec<u8> = plaintext\n        .chars()\n        .filter(|c| c.is_ascii_alphabetic())\n        .map(|c| (c as u8) - b'A')\n        .collect();\n\n    let key_bytes: Vec<u8> = key\n        .chars()\n        .filter(|c| c.is_ascii_alphabetic())\n        .map(|c| (c as u8) - b'A')\n        .collect();\n\n    assert!(\n        !key_bytes.is_empty(),\n        \"Key must contain at least one letter\"\n    );\n\n    plaintext_bytes\n        .iter()\n        .enumerate()\n        .map(|(i, &p)| {\n            let k = key_bytes[i % key_bytes.len()];\n            let encrypted = (p + k) % 26;\n            (encrypted + b'A') as char\n        })\n        .collect()\n}\n\n/// Decrypts a ciphertext string using the Vernam cipher.\n///\n/// The function converts all input to uppercase and works only with letters A-Z.\n/// The key is repeated cyclically if it's shorter than the ciphertext.\n///\n/// # Arguments\n///\n/// * `ciphertext` - The text to decrypt (will be converted to uppercase)\n/// * `key` - The decryption key (will be converted to uppercase, must not be empty)\n///\n/// # Returns\n///\n/// The decrypted plaintext as an uppercase string\n///\n/// # Panics\n///\n/// Panics if the key is empty\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::ciphers::vernam_decrypt;\n///\n/// let plaintext = vernam_decrypt(\"RIJVS\", \"KEY\");\n/// assert_eq!(plaintext, \"HELLO\");\n/// ```\npub fn vernam_decrypt(ciphertext: &str, key: &str) -> String {\n    assert!(!key.is_empty(), \"Key cannot be empty\");\n\n    let ciphertext = ciphertext.to_uppercase();\n    let key = key.to_uppercase();\n\n    let ciphertext_bytes: Vec<u8> = ciphertext\n        .chars()\n        .filter(|c| c.is_ascii_alphabetic())\n        .map(|c| (c as u8) - b'A')\n        .collect();\n\n    let key_bytes: Vec<u8> = key\n        .chars()\n        .filter(|c| c.is_ascii_alphabetic())\n        .map(|c| (c as u8) - b'A')\n        .collect();\n\n    assert!(\n        !key_bytes.is_empty(),\n        \"Key must contain at least one letter\"\n    );\n\n    ciphertext_bytes\n        .iter()\n        .enumerate()\n        .map(|(i, &c)| {\n            let k = key_bytes[i % key_bytes.len()];\n            // Add 26 before modulo to handle negative numbers properly\n            let decrypted = (c + 26 - k) % 26;\n            (decrypted + b'A') as char\n        })\n        .collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_encrypt_basic() {\n        assert_eq!(vernam_encrypt(\"HELLO\", \"KEY\"), \"RIJVS\");\n    }\n\n    #[test]\n    fn test_decrypt_basic() {\n        assert_eq!(vernam_decrypt(\"RIJVS\", \"KEY\"), \"HELLO\");\n    }\n\n    #[test]\n    fn test_encrypt_decrypt_roundtrip() {\n        let plaintext = \"HELLO\";\n        let key = \"KEY\";\n        let encrypted = vernam_encrypt(plaintext, key);\n        let decrypted = vernam_decrypt(&encrypted, key);\n        assert_eq!(decrypted, plaintext);\n    }\n\n    #[test]\n    fn test_encrypt_decrypt_long_text() {\n        let plaintext = \"THEQUICKBROWNFOXJUMPSOVERTHELAZYDOG\";\n        let key = \"SECRET\";\n        let encrypted = vernam_encrypt(plaintext, key);\n        let decrypted = vernam_decrypt(&encrypted, key);\n        assert_eq!(decrypted, plaintext);\n    }\n\n    #[test]\n    fn test_lowercase_input() {\n        // Should convert to uppercase\n        assert_eq!(vernam_encrypt(\"hello\", \"key\"), \"RIJVS\");\n        assert_eq!(vernam_decrypt(\"rijvs\", \"key\"), \"HELLO\");\n    }\n\n    #[test]\n    fn test_mixed_case_input() {\n        assert_eq!(vernam_encrypt(\"HeLLo\", \"KeY\"), \"RIJVS\");\n        assert_eq!(vernam_decrypt(\"RiJvS\", \"kEy\"), \"HELLO\");\n    }\n\n    #[test]\n    fn test_single_character() {\n        assert_eq!(vernam_encrypt(\"A\", \"B\"), \"B\");\n        assert_eq!(vernam_decrypt(\"B\", \"B\"), \"A\");\n    }\n\n    #[test]\n    fn test_key_wrapping() {\n        // Key shorter than plaintext, should wrap around\n        let encrypted = vernam_encrypt(\"AAAA\", \"BC\");\n        assert_eq!(encrypted, \"BCBC\");\n        let decrypted = vernam_decrypt(&encrypted, \"BC\");\n        assert_eq!(decrypted, \"AAAA\");\n    }\n\n    #[test]\n    fn test_alphabet_boundary() {\n        // Test wrapping at alphabet boundaries\n        assert_eq!(vernam_encrypt(\"Z\", \"B\"), \"A\"); // 25 + 1 = 26 -> 0\n        assert_eq!(vernam_decrypt(\"A\", \"B\"), \"Z\"); // 0 - 1 = -1 -> 25\n    }\n\n    #[test]\n    fn test_same_key_as_plaintext() {\n        let text = \"HELLO\";\n        let encrypted = vernam_encrypt(text, text);\n        assert_eq!(encrypted, \"OIWWC\");\n    }\n\n    #[test]\n    fn test_with_spaces_and_numbers() {\n        // Non-alphabetic characters should be filtered out\n        let encrypted = vernam_encrypt(\"HELLO 123 WORLD\", \"KEY\");\n        let expected = vernam_encrypt(\"HELLOWORLD\", \"KEY\");\n        assert_eq!(encrypted, expected);\n    }\n\n    #[test]\n    #[should_panic(expected = \"Key cannot be empty\")]\n    fn test_empty_key_encrypt() {\n        vernam_encrypt(\"HELLO\", \"\");\n    }\n\n    #[test]\n    #[should_panic(expected = \"Key cannot be empty\")]\n    fn test_empty_key_decrypt() {\n        vernam_decrypt(\"HELLO\", \"\");\n    }\n\n    #[test]\n    #[should_panic(expected = \"Key must contain at least one letter\")]\n    fn test_key_with_only_numbers() {\n        vernam_encrypt(\"HELLO\", \"12345\");\n    }\n\n    #[test]\n    fn test_empty_plaintext() {\n        assert_eq!(vernam_encrypt(\"\", \"KEY\"), \"\");\n    }\n\n    #[test]\n    fn test_plaintext_with_only_numbers() {\n        assert_eq!(vernam_encrypt(\"12345\", \"KEY\"), \"\");\n    }\n}\n"
  },
  {
    "path": "src/ciphers/vigenere.rs",
    "content": "//! Vigenère Cipher\n//!\n//! # Algorithm\n//!\n//! Rotate each ascii character by the offset of the corresponding key character.\n//! When we reach the last key character, we start over from the first one.\n//! This implementation does not rotate unicode characters.\n\n/// Vigenère cipher to rotate plain_text text by key and return an owned String.\npub fn vigenere(plain_text: &str, key: &str) -> String {\n    // Remove all unicode and non-ascii characters from key\n    let key: String = key.chars().filter(|&c| c.is_ascii_alphabetic()).collect();\n    let key = key.to_ascii_lowercase();\n\n    let key_len = key.len();\n    if key_len == 0 {\n        return String::from(plain_text);\n    }\n\n    let mut index = 0;\n\n    plain_text\n        .chars()\n        .map(|c| {\n            if c.is_ascii_alphabetic() {\n                let first = if c.is_ascii_lowercase() { b'a' } else { b'A' };\n                let shift = key.as_bytes()[index % key_len] - b'a';\n                index += 1;\n                // modulo the distance to keep character range\n                (first + (c as u8 + shift - first) % 26) as char\n            } else {\n                c\n            }\n        })\n        .collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn empty() {\n        assert_eq!(vigenere(\"\", \"test\"), \"\");\n    }\n\n    #[test]\n    fn vigenere_base() {\n        assert_eq!(\n            vigenere(\"LoremIpsumDolorSitAmet\", \"base\"),\n            \"MojinIhwvmVsmojWjtSqft\"\n        );\n    }\n\n    #[test]\n    fn vigenere_with_spaces() {\n        assert_eq!(\n            vigenere(\n                \"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\",\n                \"spaces\"\n            ),\n            \"Ddrgq ahhuo hgddr uml sbev, ggfheexwljr chahxsemfy tlkx.\"\n        );\n    }\n\n    #[test]\n    fn vigenere_unicode_and_numbers() {\n        assert_eq!(\n            vigenere(\"1 Lorem ⏳ ipsum dolor sit amet Ѡ\", \"unicode\"),\n            \"1 Fbzga ⏳ ltmhu fcosl fqv opin Ѡ\"\n        );\n    }\n\n    #[test]\n    fn vigenere_unicode_key() {\n        assert_eq!(\n            vigenere(\"Lorem ipsum dolor sit amet\", \"😉 key!\"),\n            \"Vspoq gzwsw hmvsp cmr kqcd\"\n        );\n    }\n\n    #[test]\n    fn vigenere_empty_key() {\n        assert_eq!(vigenere(\"Lorem ipsum\", \"\"), \"Lorem ipsum\");\n    }\n}\n"
  },
  {
    "path": "src/ciphers/xor.rs",
    "content": "pub fn xor_bytes(text: &[u8], key: u8) -> Vec<u8> {\n    text.iter().map(|c| c ^ key).collect()\n}\n\npub fn xor(text: &str, key: u8) -> Vec<u8> {\n    xor_bytes(text.as_bytes(), key)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_simple() {\n        let test_string = \"test string\";\n        let ciphered_text = xor(test_string, 32);\n        assert_eq!(test_string.as_bytes(), xor_bytes(&ciphered_text, 32));\n    }\n\n    #[test]\n    fn test_every_alphabet_with_space() {\n        let test_string = \"The quick brown fox jumps over the lazy dog\";\n        let ciphered_text = xor(test_string, 64);\n        assert_eq!(test_string.as_bytes(), xor_bytes(&ciphered_text, 64));\n    }\n\n    #[test]\n    fn test_multi_byte() {\n        let test_string = \"日本語\";\n        let key = 42;\n        let ciphered_text = xor(test_string, key);\n        assert_eq!(test_string.as_bytes(), xor_bytes(&ciphered_text, key));\n    }\n\n    #[test]\n    fn test_zero_byte() {\n        let test_string = \"The quick brown fox jumps over the lazy dog\";\n        let key = b' ';\n        let ciphered_text = xor(test_string, key);\n        assert_eq!(test_string.as_bytes(), xor_bytes(&ciphered_text, key));\n    }\n\n    #[test]\n    fn test_invalid_byte() {\n        let test_string = \"The quick brown fox jumps over the lazy dog\";\n        let key = !0;\n        let ciphered_text = xor(test_string, key);\n        assert_eq!(test_string.as_bytes(), xor_bytes(&ciphered_text, key));\n    }\n}\n"
  },
  {
    "path": "src/compression/burrows_wheeler_transform.rs",
    "content": "//! Burrows-Wheeler Transform\n//!\n//! The Burrows-Wheeler transform (BWT, also called block-sorting compression)\n//! rearranges a character string into runs of similar characters. This is useful\n//! for compression, since it tends to be easy to compress a string that has runs\n//! of repeated characters by techniques such as move-to-front transform and\n//! run-length encoding. More importantly, the transformation is reversible,\n//! without needing to store any additional data except the position of the first\n//! original character. The BWT is thus a \"free\" method of improving the efficiency\n//! of text compression algorithms, costing only some extra computation.\n//!\n//! More info: <https://en.wikipedia.org/wiki/Burrows%E2%80%93Wheeler_transform>\n\n/// Result of the Burrows-Wheeler transform containing the transformed string\n/// and the index of the original string in the sorted rotations.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct BwtResult {\n    /// The BWT-transformed string\n    pub bwt_string: String,\n    /// The index of the original string in the sorted rotations (0-based)\n    pub idx_original_string: usize,\n}\n\n/// Generates all rotations of a string.\n///\n/// # Arguments\n///\n/// * `s` - The string to rotate\n///\n/// # Returns\n///\n/// A vector containing all rotations of the input string\n///\n/// # Examples\n///\n/// ```\n/// # use the_algorithms_rust::compression::all_rotations;\n/// let rotations = all_rotations(\"^BANANA|\");\n/// assert_eq!(rotations.len(), 8);\n/// assert_eq!(rotations[0], \"^BANANA|\");\n/// assert_eq!(rotations[1], \"BANANA|^\");\n/// ```\npub fn all_rotations(s: &str) -> Vec<String> {\n    (0..s.len())\n        .map(|i| format!(\"{}{}\", &s[i..], &s[..i]))\n        .collect()\n}\n\n/// Performs the Burrows-Wheeler transform on a string.\n///\n/// # Arguments\n///\n/// * `s` - The string to transform (must not be empty)\n///\n/// # Returns\n///\n/// A `BwtResult` containing the transformed string and the index of the original string\n///\n/// # Panics\n///\n/// Panics if the input string is empty\n///\n/// # Examples\n///\n/// ```\n/// # use the_algorithms_rust::compression::bwt_transform;\n/// let result = bwt_transform(\"^BANANA\");\n/// assert_eq!(result.bwt_string, \"BNN^AAA\");\n/// assert_eq!(result.idx_original_string, 6);\n///\n/// let result = bwt_transform(\"panamabanana\");\n/// assert_eq!(result.bwt_string, \"mnpbnnaaaaaa\");\n/// assert_eq!(result.idx_original_string, 11);\n/// ```\npub fn bwt_transform(s: &str) -> BwtResult {\n    assert!(!s.is_empty(), \"Input string must not be empty\");\n\n    let mut rotations = all_rotations(s);\n    rotations.sort();\n\n    // Find the index of the original string in sorted rotations\n    let idx_original_string = rotations\n        .iter()\n        .position(|r| r == s)\n        .expect(\"Original string must be in rotations\");\n\n    // Build BWT string from last character of each rotation\n    let bwt_string: String = rotations\n        .iter()\n        .map(|r| r.chars().last().unwrap())\n        .collect();\n\n    BwtResult {\n        bwt_string,\n        idx_original_string,\n    }\n}\n\n/// Reverses the Burrows-Wheeler transform to recover the original string.\n///\n/// # Arguments\n///\n/// * `bwt_string` - The BWT-transformed string\n/// * `idx_original_string` - The 0-based index of the original string in sorted rotations\n///\n/// # Returns\n///\n/// The original string before BWT transformation\n///\n/// # Panics\n///\n/// * If `bwt_string` is empty\n/// * If `idx_original_string` is out of bounds (>= length of `bwt_string`)\n///\n/// # Examples\n///\n/// ```\n/// # use the_algorithms_rust::compression::reverse_bwt;\n/// assert_eq!(reverse_bwt(\"BNN^AAA\", 6), \"^BANANA\");\n/// assert_eq!(reverse_bwt(\"aaaadss_c__aa\", 3), \"a_asa_da_casa\");\n/// assert_eq!(reverse_bwt(\"mnpbnnaaaaaa\", 11), \"panamabanana\");\n/// ```\npub fn reverse_bwt(bwt_string: &str, idx_original_string: usize) -> String {\n    assert!(!bwt_string.is_empty(), \"BWT string must not be empty\");\n    assert!(\n        idx_original_string < bwt_string.len(),\n        \"Index must be less than BWT string length\"\n    );\n\n    let len = bwt_string.len();\n    let bwt_chars: Vec<char> = bwt_string.chars().collect();\n    let mut ordered_rotations: Vec<String> = vec![String::new(); len];\n\n    // Iteratively prepend characters and sort to reconstruct rotations\n    for _ in 0..len {\n        for i in 0..len {\n            ordered_rotations[i] = format!(\"{}{}\", bwt_chars[i], ordered_rotations[i]);\n        }\n        ordered_rotations.sort();\n    }\n\n    ordered_rotations[idx_original_string].clone()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_all_rotations_banana() {\n        let rotations = all_rotations(\"^BANANA|\");\n        assert_eq!(rotations.len(), 8);\n        assert_eq!(\n            rotations,\n            vec![\n                \"^BANANA|\", \"BANANA|^\", \"ANANA|^B\", \"NANA|^BA\", \"ANA|^BAN\", \"NA|^BANA\", \"A|^BANAN\",\n                \"|^BANANA\"\n            ]\n        );\n    }\n\n    #[test]\n    fn test_all_rotations_casa() {\n        let rotations = all_rotations(\"a_asa_da_casa\");\n        assert_eq!(rotations.len(), 13);\n        assert_eq!(rotations[0], \"a_asa_da_casa\");\n        assert_eq!(rotations[1], \"_asa_da_casaa\");\n        assert_eq!(rotations[12], \"aa_asa_da_cas\");\n    }\n\n    #[test]\n    fn test_all_rotations_panama() {\n        let rotations = all_rotations(\"panamabanana\");\n        assert_eq!(rotations.len(), 12);\n        assert_eq!(rotations[0], \"panamabanana\");\n        assert_eq!(rotations[11], \"apanamabanan\");\n    }\n\n    #[test]\n    fn test_bwt_transform_banana() {\n        let result = bwt_transform(\"^BANANA\");\n        assert_eq!(result.bwt_string, \"BNN^AAA\");\n        assert_eq!(result.idx_original_string, 6);\n    }\n\n    #[test]\n    fn test_bwt_transform_casa() {\n        let result = bwt_transform(\"a_asa_da_casa\");\n        assert_eq!(result.bwt_string, \"aaaadss_c__aa\");\n        assert_eq!(result.idx_original_string, 3);\n    }\n\n    #[test]\n    fn test_bwt_transform_panama() {\n        let result = bwt_transform(\"panamabanana\");\n        assert_eq!(result.bwt_string, \"mnpbnnaaaaaa\");\n        assert_eq!(result.idx_original_string, 11);\n    }\n\n    #[test]\n    #[should_panic(expected = \"Input string must not be empty\")]\n    fn test_bwt_transform_empty() {\n        bwt_transform(\"\");\n    }\n\n    #[test]\n    fn test_reverse_bwt_banana() {\n        let original = reverse_bwt(\"BNN^AAA\", 6);\n        assert_eq!(original, \"^BANANA\");\n    }\n\n    #[test]\n    fn test_reverse_bwt_casa() {\n        let original = reverse_bwt(\"aaaadss_c__aa\", 3);\n        assert_eq!(original, \"a_asa_da_casa\");\n    }\n\n    #[test]\n    fn test_reverse_bwt_panama() {\n        let original = reverse_bwt(\"mnpbnnaaaaaa\", 11);\n        assert_eq!(original, \"panamabanana\");\n    }\n\n    #[test]\n    #[should_panic(expected = \"BWT string must not be empty\")]\n    fn test_reverse_bwt_empty_string() {\n        reverse_bwt(\"\", 0);\n    }\n\n    #[test]\n    #[should_panic(expected = \"Index must be less than BWT string length\")]\n    fn test_reverse_bwt_index_too_high() {\n        reverse_bwt(\"mnpbnnaaaaaa\", 12);\n    }\n\n    #[test]\n    fn test_bwt_roundtrip() {\n        // Test that transform -> reverse gives back original string\n        let test_strings = vec![\n            \"^BANANA\",\n            \"a_asa_da_casa\",\n            \"panamabanana\",\n            \"ABRACADABRA\",\n            \"SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES\",\n        ];\n\n        for s in test_strings {\n            let result = bwt_transform(s);\n            let recovered = reverse_bwt(&result.bwt_string, result.idx_original_string);\n            assert_eq!(recovered, s, \"Roundtrip failed for '{s}'\");\n        }\n    }\n\n    #[test]\n    fn test_single_character() {\n        let result = bwt_transform(\"A\");\n        assert_eq!(result.bwt_string, \"A\");\n        assert_eq!(result.idx_original_string, 0);\n\n        let recovered = reverse_bwt(&result.bwt_string, result.idx_original_string);\n        assert_eq!(recovered, \"A\");\n    }\n\n    #[test]\n    fn test_repeated_characters() {\n        let result = bwt_transform(\"AAAA\");\n        assert_eq!(result.bwt_string, \"AAAA\");\n\n        let recovered = reverse_bwt(&result.bwt_string, result.idx_original_string);\n        assert_eq!(recovered, \"AAAA\");\n    }\n}\n"
  },
  {
    "path": "src/compression/huffman_encoding.rs",
    "content": "//! Huffman Encoding implementation\n//!\n//! Huffman coding is a lossless data compression algorithm that assigns variable-length codes\n//! to characters based on their frequency of occurrence. Characters that occur more frequently\n//! are assigned shorter codes, while less frequent characters get longer codes.\n//!\n//! # Algorithm Overview\n//!\n//! 1. Count the frequency of each character in the input\n//! 2. Build a min-heap (priority queue) of nodes based on frequency\n//! 3. Build the Huffman tree by repeatedly:\n//!    - Remove two nodes with minimum frequency\n//!    - Create a parent node with combined frequency\n//!    - Insert the parent back into the heap\n//! 4. Traverse the tree to assign binary codes to each character\n//! 5. Encode the input using the generated codes\n//!\n//! # Time Complexity\n//!\n//! - Building frequency map: O(n) where n is input length\n//! - Building Huffman tree: O(m log m) where m is number of unique characters\n//! - Encoding: O(n)\n//!\n//! # Usage\n//!\n//! As a library:\n//! ```no_run\n//! use the_algorithms_rust::compression::huffman_encode;\n//!\n//! let text = \"hello world\";\n//! let (encoded, codes) = huffman_encode(text);\n//! println!(\"Original: {}\", text);\n//! println!(\"Encoded: {}\", encoded);\n//! ```\n//!\n//! As a command-line tool:\n//! ```bash\n//! rustc huffman_encoding.rs -o huffman\n//! ./huffman input.txt\n//! ```\n\nuse std::cmp::Ordering;\nuse std::collections::{BinaryHeap, HashMap};\nuse std::fs;\n\n#[cfg(not(test))]\nuse std::env;\n\n/// Represents a node in the Huffman tree\n#[derive(Debug, Eq, PartialEq)]\nenum HuffmanNode {\n    /// Leaf node containing a character and its frequency\n    Leaf { character: char, frequency: usize },\n    /// Internal node with combined frequency and left/right children\n    Internal {\n        frequency: usize,\n        left: Box<HuffmanNode>,\n        right: Box<HuffmanNode>,\n    },\n}\n\nimpl HuffmanNode {\n    /// Returns the frequency of this node\n    fn frequency(&self) -> usize {\n        match self {\n            HuffmanNode::Leaf { frequency, .. } | HuffmanNode::Internal { frequency, .. } => {\n                *frequency\n            }\n        }\n    }\n\n    /// Creates a new leaf node\n    fn new_leaf(character: char, frequency: usize) -> Self {\n        HuffmanNode::Leaf {\n            character,\n            frequency,\n        }\n    }\n\n    /// Creates a new internal node from two children\n    fn new_internal(left: HuffmanNode, right: HuffmanNode) -> Self {\n        let frequency = left.frequency() + right.frequency();\n        HuffmanNode::Internal {\n            frequency,\n            left: Box::new(left),\n            right: Box::new(right),\n        }\n    }\n}\n\n/// Wrapper for HuffmanNode to implement Ord for BinaryHeap (min-heap)\n#[derive(Eq, PartialEq)]\nstruct HeapNode(HuffmanNode);\n\nimpl Ord for HeapNode {\n    fn cmp(&self, other: &Self) -> Ordering {\n        // Reverse ordering for min-heap\n        other.0.frequency().cmp(&self.0.frequency())\n    }\n}\n\nimpl PartialOrd for HeapNode {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\n/// Counts the frequency of each character in the input string\n///\n/// # Arguments\n///\n/// * `text` - The input string to analyze\n///\n/// # Returns\n///\n/// A HashMap mapping each character to its frequency count\nfn build_frequency_map(text: &str) -> HashMap<char, usize> {\n    let mut frequencies = HashMap::new();\n    for ch in text.chars() {\n        *frequencies.entry(ch).or_insert(0) += 1;\n    }\n    frequencies\n}\n\n/// Builds the Huffman tree from a frequency map\n///\n/// # Arguments\n///\n/// * `frequencies` - HashMap of character frequencies\n///\n/// # Returns\n///\n/// The root node of the Huffman tree, or None if input is empty\nfn build_huffman_tree(frequencies: HashMap<char, usize>) -> Option<HuffmanNode> {\n    if frequencies.is_empty() {\n        return None;\n    }\n\n    let mut heap: BinaryHeap<HeapNode> = frequencies\n        .into_iter()\n        .map(|(ch, freq)| HeapNode(HuffmanNode::new_leaf(ch, freq)))\n        .collect();\n\n    // Special case: only one unique character\n    if heap.len() == 1 {\n        return heap.pop().map(|node| node.0);\n    }\n\n    // Build the tree by combining nodes\n    while heap.len() > 1 {\n        let left = heap.pop().unwrap().0;\n        let right = heap.pop().unwrap().0;\n        let parent = HuffmanNode::new_internal(left, right);\n        heap.push(HeapNode(parent));\n    }\n\n    heap.pop().map(|node| node.0)\n}\n\n/// Traverses the Huffman tree to generate binary codes for each character\n///\n/// # Arguments\n///\n/// * `node` - The current node being traversed\n/// * `code` - The current binary code string\n/// * `codes` - HashMap to store the generated codes\nfn generate_codes(node: &HuffmanNode, code: String, codes: &mut HashMap<char, String>) {\n    match node {\n        HuffmanNode::Leaf { character, .. } => {\n            // Use \"0\" for single character case\n            codes.insert(\n                *character,\n                if code.is_empty() {\n                    \"0\".to_string()\n                } else {\n                    code\n                },\n            );\n        }\n        HuffmanNode::Internal { left, right, .. } => {\n            generate_codes(left, format!(\"{code}0\"), codes);\n            generate_codes(right, format!(\"{code}1\"), codes);\n        }\n    }\n}\n\n/// Encodes text using Huffman coding\n///\n/// # Arguments\n///\n/// * `text` - The input string to encode\n///\n/// # Returns\n///\n/// A tuple containing:\n/// - The encoded binary string\n/// - A HashMap of character to binary code mappings\n///\n/// # Examples\n///\n/// ```\n/// # use std::collections::HashMap;\n/// # use the_algorithms_rust::compression::huffman_encode;\n/// let (encoded, codes) = huffman_encode(\"hello\");\n/// assert!(!encoded.is_empty());\n/// assert!(codes.contains_key(&'h'));\n/// ```\npub fn huffman_encode(text: &str) -> (String, HashMap<char, String>) {\n    if text.is_empty() {\n        return (String::new(), HashMap::new());\n    }\n\n    let frequencies = build_frequency_map(text);\n    let tree = build_huffman_tree(frequencies).expect(\"Failed to build Huffman tree\");\n\n    let mut codes = HashMap::new();\n    generate_codes(&tree, String::new(), &mut codes);\n\n    let encoded: String = text.chars().map(|ch| codes[&ch].as_str()).collect();\n\n    (encoded, codes)\n}\n\n/// Decodes a Huffman-encoded string\n///\n/// # Arguments\n///\n/// * `encoded` - The binary string to decode\n/// * `codes` - HashMap of character to binary code mappings\n///\n/// # Returns\n///\n/// The decoded original string\n///\n/// # Examples\n///\n/// ```\n/// # use std::collections::HashMap;\n/// # use the_algorithms_rust::compression::{huffman_encode, huffman_decode};\n/// let text = \"hello world\";\n/// let (encoded, codes) = huffman_encode(text);\n/// let decoded = huffman_decode(&encoded, &codes);\n/// assert_eq!(text, decoded);\n/// ```\npub fn huffman_decode(encoded: &str, codes: &HashMap<char, String>) -> String {\n    if encoded.is_empty() {\n        return String::new();\n    }\n\n    // Reverse the code map for decoding\n    let reverse_codes: HashMap<&str, char> = codes\n        .iter()\n        .map(|(ch, code)| (code.as_str(), *ch))\n        .collect();\n\n    let mut decoded = String::new();\n    let mut current_code = String::new();\n\n    for bit in encoded.chars() {\n        current_code.push(bit);\n        if let Some(&character) = reverse_codes.get(current_code.as_str()) {\n            decoded.push(character);\n            current_code.clear();\n        }\n    }\n\n    decoded\n}\n\n/// Demonstrates Huffman encoding by processing a file and displaying detailed results\n///\n/// This function reads a file, encodes it using Huffman coding, and displays:\n/// - Character code mappings\n/// - Compression statistics\n/// - Encoded output (with smart truncation for large files)\n/// - Decoding verification\n///\n/// # Arguments\n///\n/// * `file_path` - Path to the file to encode\n///\n/// # Returns\n///\n/// Result indicating success or IO error\n///\n/// # Examples\n///\n/// ```ignore\n/// // Note: This function is not re-exported in the public API\n/// // Access it via: the_algorithms_rust::compression::huffman_encoding::demonstrate_huffman_from_file\n/// use std::fs::File;\n/// use std::io::Write;\n///\n/// // Create a test file\n/// let mut file = File::create(\"test.txt\").unwrap();\n/// file.write_all(b\"hello world\").unwrap();\n///\n/// // Demonstrate Huffman encoding\n/// // In your code, use the full path or import from huffman_encoding module\n/// demonstrate_huffman_from_file(\"test.txt\").unwrap();\n/// ```\n#[allow(dead_code)]\npub fn demonstrate_huffman_from_file(file_path: &str) -> std::io::Result<()> {\n    // Read the file contents\n    let text = fs::read_to_string(file_path)?;\n\n    if text.is_empty() {\n        println!(\"File is empty!\");\n        return Ok(());\n    }\n\n    // Encode using Huffman coding\n    let (encoded, codes) = huffman_encode(&text);\n\n    // Display the results\n    println!(\"Huffman Coding of {file_path}: \");\n    println!();\n\n    // Show the code table\n    println!(\"Character Codes:\");\n    println!(\"{:-<40}\", \"\");\n    let mut sorted_codes: Vec<_> = codes.iter().collect();\n    sorted_codes.sort_by_key(|(ch, _)| *ch);\n\n    for (ch, code) in sorted_codes {\n        let display_char = if ch.is_whitespace() {\n            format!(\"'{}' (space/whitespace)\", ch.escape_default())\n        } else {\n            format!(\"'{ch}'\")\n        };\n        println!(\"{display_char:20} -> {code}\");\n    }\n    println!(\"{:-<40}\", \"\");\n    println!();\n\n    // Show encoding statistics\n    let original_bits = text.len() * 8; // Assuming 8-bit characters\n    let compressed_bits = encoded.len();\n    let compression_ratio = if original_bits > 0 {\n        (1.0 - (compressed_bits as f64 / original_bits as f64)) * 100.0\n    } else {\n        0.0\n    };\n\n    println!(\"Statistics:\");\n    println!(\n        \"  Original size:    {} characters ({} bits)\",\n        text.len(),\n        original_bits\n    );\n    println!(\"  Encoded size:     {compressed_bits} bits\");\n    println!(\"  Compression:      {compression_ratio:.2}%\");\n    println!();\n\n    // Show the encoded output (limited to avoid overwhelming the terminal)\n    println!(\"Encoded output:\");\n    if encoded.len() <= 500 {\n        // Split into chunks of 50 for readability\n        for (i, chunk) in encoded.as_bytes().chunks(50).enumerate() {\n            print!(\"{:4}: \", i * 50);\n            for &byte in chunk {\n                print!(\"{}\", byte as char);\n            }\n            println!();\n        }\n    } else {\n        // Show first and last portions for very long outputs\n        println!(\"  (showing first and last 200 bits)\");\n        print!(\"  Start: \");\n        for &byte in &encoded.as_bytes()[..200] {\n            print!(\"{}\", byte as char);\n        }\n        println!();\n        print!(\"  End:   \");\n        for &byte in &encoded.as_bytes()[encoded.len() - 200..] {\n            print!(\"{}\", byte as char);\n        }\n        println!();\n    }\n    println!();\n\n    // Verify decoding\n    let decoded = huffman_decode(&encoded, &codes);\n    if decoded == text {\n        println!(\"✓ Decoding verification: SUCCESS\");\n    } else {\n        println!(\"✗ Decoding verification: FAILED\");\n    }\n\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_empty_string() {\n        let (encoded, codes) = huffman_encode(\"\");\n        assert_eq!(encoded, \"\");\n        assert!(codes.is_empty());\n    }\n\n    #[test]\n    fn test_single_character() {\n        let (encoded, codes) = huffman_encode(\"aaaa\");\n        assert_eq!(encoded, \"0000\");\n        assert_eq!(codes.get(&'a'), Some(&\"0\".to_string()));\n    }\n\n    #[test]\n    fn test_simple_string() {\n        let text = \"hello\";\n        let (encoded, codes) = huffman_encode(text);\n\n        // Verify all characters have codes\n        for ch in text.chars() {\n            assert!(codes.contains_key(&ch), \"Missing code for '{ch}'\");\n        }\n\n        // Verify decoding returns original text\n        let decoded = huffman_decode(&encoded, &codes);\n        assert_eq!(decoded, text);\n    }\n\n    #[test]\n    fn test_encode_decode_roundtrip() {\n        let test_cases = vec![\n            \"a\",\n            \"ab\",\n            \"hello world\",\n            \"the quick brown fox jumps over the lazy dog\",\n            \"aaaaabbbbbcccccdddddeeeeefffffggggghhhhhiiiii\",\n        ];\n\n        for text in test_cases {\n            let (encoded, codes) = huffman_encode(text);\n            let decoded = huffman_decode(&encoded, &codes);\n            assert_eq!(decoded, text, \"Failed roundtrip for: '{text}'\");\n        }\n    }\n\n    #[test]\n    fn test_frequency_based_encoding() {\n        // In \"aaabbc\", 'a' should have shorter code than 'b' or 'c'\n        let (_, codes) = huffman_encode(\"aaabbc\");\n        let a_len = codes[&'a'].len();\n        let b_len = codes[&'b'].len();\n        let c_len = codes[&'c'].len();\n\n        // 'a' appears most frequently, so should have shortest or equal code\n        assert!(a_len <= b_len);\n        assert!(a_len <= c_len);\n    }\n\n    #[test]\n    fn test_compression_ratio() {\n        let text = \"aaaaaaaaaa\"; // 10 'a's\n        let (encoded, _) = huffman_encode(text);\n\n        // Original: 10 chars * 8 bits = 80 bits (in UTF-8)\n        // Huffman: 10 * 1 bit = 10 bits (single character gets code \"0\")\n        assert_eq!(encoded.len(), 10);\n        assert!(encoded.chars().all(|c| c == '0'));\n    }\n\n    #[test]\n    fn test_all_unique_characters() {\n        let text = \"abcdefg\";\n        let (encoded, codes) = huffman_encode(text);\n\n        // All characters should have codes\n        assert_eq!(codes.len(), 7);\n\n        // Verify roundtrip\n        let decoded = huffman_decode(&encoded, &codes);\n        assert_eq!(decoded, text);\n    }\n\n    #[test]\n    fn test_build_frequency_map() {\n        let frequencies = build_frequency_map(\"hello\");\n        assert_eq!(frequencies.get(&'h'), Some(&1));\n        assert_eq!(frequencies.get(&'e'), Some(&1));\n        assert_eq!(frequencies.get(&'l'), Some(&2));\n        assert_eq!(frequencies.get(&'o'), Some(&1));\n    }\n\n    #[test]\n    fn test_unicode_characters() {\n        let text = \"Hello, 世界! 🌍\";\n        let (encoded, codes) = huffman_encode(text);\n        let decoded = huffman_decode(&encoded, &codes);\n        assert_eq!(decoded, text);\n    }\n\n    #[test]\n    fn test_demonstrate_huffman_from_file() {\n        use std::fs::File;\n        use std::io::Write;\n\n        // Create a temporary test file\n        let test_file = \"/tmp/huffman_test.txt\";\n        let test_content = \"The quick brown fox jumps over the lazy dog\";\n\n        {\n            let mut file = File::create(test_file).unwrap();\n            file.write_all(test_content.as_bytes()).unwrap();\n        }\n\n        // Test the demonstrate function\n        let result = demonstrate_huffman_from_file(test_file);\n        assert!(result.is_ok());\n    }\n\n    #[test]\n    fn test_demonstrate_empty_file() {\n        use std::fs::File;\n\n        // Create an empty test file\n        let test_file = \"/tmp/huffman_empty.txt\";\n        File::create(test_file).unwrap();\n\n        // Test with empty file\n        let result = demonstrate_huffman_from_file(test_file);\n        assert!(result.is_ok());\n    }\n}\n\n/// Main function for command-line usage\n///\n/// Allows this file to be compiled as a standalone binary:\n/// ```bash\n/// rustc huffman_encoding.rs -o huffman\n/// ./huffman input.txt\n/// ```\n#[cfg(not(test))]\n#[allow(dead_code)]\nfn main() {\n    let args: Vec<String> = env::args().collect();\n\n    if args.len() < 2 {\n        eprintln!(\"Huffman Encoding - Lossless Data Compression\");\n        eprintln!();\n        eprintln!(\"Usage: {} <file_path>\", args[0]);\n        eprintln!();\n        eprintln!(\"Example:\");\n        eprintln!(\"  {} sample.txt\", args[0]);\n        eprintln!();\n        eprintln!(\"This will encode the file and display:\");\n        eprintln!(\"  - Character code mappings\");\n        eprintln!(\"  - Compression statistics\");\n        eprintln!(\"  - Encoded binary output\");\n        eprintln!(\"  - Verification of successful decoding\");\n        std::process::exit(1);\n    }\n\n    let file_path = &args[1];\n\n    match demonstrate_huffman_from_file(file_path) {\n        Ok(()) => {}\n        Err(e) => {\n            eprintln!(\"Error processing file '{file_path}': {e}\");\n            std::process::exit(1);\n        }\n    }\n}\n"
  },
  {
    "path": "src/compression/lz77.rs",
    "content": "//! LZ77 Compression Algorithm\n//!\n//! LZ77 is a lossless data compression algorithm published by Abraham Lempel and Jacob Ziv in 1977.\n//! Also known as LZ1 or sliding-window compression, it forms the basis for many variations\n//! including LZW, LZSS, LZMA and others.\n//!\n//! # Algorithm Overview\n//!\n//! It uses a \"sliding window\" method where the window contains:\n//! - Search buffer: previously seen data that can be referenced\n//! - Look-ahead buffer: data currently being encoded\n//!\n//! LZ77 encodes data using triplets (tokens) composed of:\n//! - **Offset**: distance from the current position to the start of a match in the search buffer\n//! - **Length**: number of characters that match\n//! - **Indicator**: the next character to be encoded\n//!\n//! # Examples\n//!\n//! ```\n//! use the_algorithms_rust::compression::LZ77Compressor;\n//!\n//! let compressor = LZ77Compressor::new(13, 6);\n//! let text = \"ababcbababaa\";\n//! let compressed = compressor.compress(text);\n//! let decompressed = compressor.decompress(&compressed);\n//! assert_eq!(text, decompressed);\n//! ```\n//!\n//! # References\n//!\n//! - [Wikipedia: LZ77 and LZ78](https://en.wikipedia.org/wiki/LZ77_and_LZ78)\n\nuse std::fmt;\n\n/// Represents a compression token (triplet) used in LZ77 compression.\n///\n/// A token consists of:\n/// - `offset`: distance to the start of the match in the search buffer\n/// - `length`: number of matching characters\n/// - `indicator`: the next character to be encoded\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Token {\n    pub offset: usize,\n    pub length: usize,\n    pub indicator: char,\n}\n\nimpl Token {\n    /// Creates a new Token.\n    pub fn new(offset: usize, length: usize, indicator: char) -> Self {\n        Self {\n            offset,\n            length,\n            indicator,\n        }\n    }\n}\n\nimpl fmt::Display for Token {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"({}, {}, {})\", self.offset, self.length, self.indicator)\n    }\n}\n\n/// LZ77 Compressor with configurable window and lookahead buffer sizes.\n#[derive(Debug, Clone)]\npub struct LZ77Compressor {\n    search_buffer_size: usize,\n}\n\nimpl LZ77Compressor {\n    /// Creates a new LZ77Compressor with the specified parameters.\n    ///\n    /// # Arguments\n    ///\n    /// * `window_size` - Total size of the sliding window\n    /// * `lookahead_buffer_size` - Size of the lookahead buffer\n    ///\n    /// # Panics\n    ///\n    /// Panics if `lookahead_buffer_size` is greater than or equal to `window_size`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use the_algorithms_rust::compression::LZ77Compressor;\n    ///\n    /// let compressor = LZ77Compressor::new(13, 6);\n    /// ```\n    pub fn new(window_size: usize, lookahead_buffer_size: usize) -> Self {\n        assert!(\n            lookahead_buffer_size < window_size,\n            \"lookahead_buffer_size must be less than window_size\"\n        );\n\n        Self {\n            search_buffer_size: window_size - lookahead_buffer_size,\n        }\n    }\n\n    /// Compresses the given text using the LZ77 algorithm.\n    ///\n    /// # Arguments\n    ///\n    /// * `text` - The string to be compressed\n    ///\n    /// # Returns\n    ///\n    /// A vector of `Token`s representing the compressed data\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use the_algorithms_rust::compression::LZ77Compressor;\n    ///\n    /// let compressor = LZ77Compressor::new(13, 6);\n    /// let compressed = compressor.compress(\"ababcbababaa\");\n    /// assert_eq!(compressed.len(), 5);\n    /// ```\n    pub fn compress(&self, text: &str) -> Vec<Token> {\n        let mut output = Vec::new();\n        let mut search_buffer = String::new();\n        let mut remaining_text = text.to_string();\n\n        while !remaining_text.is_empty() {\n            // Find the next encoding token\n            let token = self.find_encoding_token(&remaining_text, &search_buffer);\n\n            // Update the search buffer with the newly processed characters\n            let chars_to_add = token.length + 1;\n            let new_chars: String = remaining_text.chars().take(chars_to_add).collect();\n            search_buffer.push_str(&new_chars);\n\n            // Trim search buffer if it exceeds the maximum size\n            if search_buffer.len() > self.search_buffer_size {\n                let trim_amount = search_buffer.len() - self.search_buffer_size;\n                search_buffer = search_buffer.chars().skip(trim_amount).collect();\n            }\n\n            // Remove processed characters from remaining text\n            remaining_text = remaining_text.chars().skip(chars_to_add).collect();\n\n            // Add token to output\n            output.push(token);\n        }\n\n        output\n    }\n\n    /// Decompresses a list of tokens back into the original text.\n    ///\n    /// # Arguments\n    ///\n    /// * `tokens` - A slice of `Token`s representing compressed data\n    ///\n    /// # Returns\n    ///\n    /// The decompressed string\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use the_algorithms_rust::compression::{LZ77Compressor, Token};\n    ///\n    /// let compressor = LZ77Compressor::new(13, 6);\n    /// let tokens = vec![\n    ///     Token::new(0, 0, 'a'),\n    ///     Token::new(0, 0, 'b'),\n    ///     Token::new(2, 2, 'c'),\n    ///     Token::new(4, 3, 'a'),\n    ///     Token::new(2, 2, 'a'),\n    /// ];\n    /// let decompressed = compressor.decompress(&tokens);\n    /// assert_eq!(decompressed, \"ababcbababaa\");\n    /// ```\n    pub fn decompress(&self, tokens: &[Token]) -> String {\n        let mut output = String::new();\n\n        for token in tokens {\n            // Copy characters from the existing output based on offset and length\n            for _ in 0..token.length {\n                let index = output.len() - token.offset;\n                let ch = output.chars().nth(index).unwrap();\n                output.push(ch);\n            }\n            // Add the indicator character\n            output.push(token.indicator);\n        }\n\n        output\n    }\n\n    /// Finds the encoding token for the current position in the text.\n    ///\n    /// This method searches the search buffer for the longest match with the\n    /// beginning of the text and returns the corresponding token.\n    fn find_encoding_token(&self, text: &str, search_buffer: &str) -> Token {\n        if text.is_empty() {\n            panic!(\"Cannot encode empty text\");\n        }\n\n        let mut length = 0;\n        let mut offset = 0;\n\n        if search_buffer.is_empty() {\n            return Token::new(offset, length, text.chars().next().unwrap());\n        }\n\n        let search_chars: Vec<char> = search_buffer.chars().collect();\n        let text_chars: Vec<char> = text.chars().collect();\n\n        // We must keep at least one character for the indicator\n        let max_match_length = text_chars.len() - 1;\n\n        // Search for matches in the search buffer\n        for (i, &ch) in search_chars.iter().enumerate() {\n            let found_offset = search_chars.len() - i;\n\n            if ch == text_chars[0] {\n                let found_length = Self::match_length_from_index(&text_chars, &search_chars, 0, i);\n\n                // Limit match length to ensure we have an indicator character\n                let found_length = found_length.min(max_match_length);\n\n                // Update if we found a longer match (or same length with smaller offset)\n                if found_length >= length {\n                    offset = found_offset;\n                    length = found_length;\n                }\n            }\n        }\n\n        Token::new(offset, length, text_chars[length])\n    }\n\n    /// Calculates the length of the longest match between text and window\n    /// starting from the given indices.\n    ///\n    /// This is a helper function that recursively finds matching characters.\n    fn match_length_from_index(\n        text: &[char],\n        window: &[char],\n        text_index: usize,\n        window_index: usize,\n    ) -> usize {\n        // Base cases\n        if text_index >= text.len() || window_index >= window.len() {\n            return 0;\n        }\n\n        if text[text_index] != window[window_index] {\n            return 0;\n        }\n\n        // Recursive case: characters match, continue checking\n        let mut extended_window = window.to_vec();\n        extended_window.push(text[text_index]);\n\n        1 + Self::match_length_from_index(text, &extended_window, text_index + 1, window_index + 1)\n    }\n}\n\nimpl Default for LZ77Compressor {\n    /// Creates a default LZ77Compressor with window_size=13 and lookahead_buffer_size=6.\n    fn default() -> Self {\n        Self::new(13, 6)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_token_display() {\n        let token = Token::new(1, 2, 'c');\n        assert_eq!(token.to_string(), \"(1, 2, c)\");\n    }\n\n    #[test]\n    fn test_compress_ababcbababaa() {\n        let compressor = LZ77Compressor::new(13, 6);\n        let compressed = compressor.compress(\"ababcbababaa\");\n\n        let expected = vec![\n            Token::new(0, 0, 'a'),\n            Token::new(0, 0, 'b'),\n            Token::new(2, 2, 'c'),\n            Token::new(4, 3, 'a'),\n            Token::new(2, 2, 'a'),\n        ];\n\n        assert_eq!(compressed, expected);\n    }\n\n    #[test]\n    fn test_compress_aacaacabcabaaac() {\n        let compressor = LZ77Compressor::new(13, 6);\n        let compressed = compressor.compress(\"aacaacabcabaaac\");\n\n        let expected = vec![\n            Token::new(0, 0, 'a'),\n            Token::new(1, 1, 'c'),\n            Token::new(3, 4, 'b'),\n            Token::new(3, 3, 'a'),\n            Token::new(1, 2, 'c'),\n        ];\n\n        assert_eq!(compressed, expected);\n    }\n\n    #[test]\n    fn test_decompress_cabracadabrarrarrad() {\n        let compressor = LZ77Compressor::new(13, 6);\n        let tokens = vec![\n            Token::new(0, 0, 'c'),\n            Token::new(0, 0, 'a'),\n            Token::new(0, 0, 'b'),\n            Token::new(0, 0, 'r'),\n            Token::new(3, 1, 'c'),\n            Token::new(2, 1, 'd'),\n            Token::new(7, 4, 'r'),\n            Token::new(3, 5, 'd'),\n        ];\n\n        let decompressed = compressor.decompress(&tokens);\n        assert_eq!(decompressed, \"cabracadabrarrarrad\");\n    }\n\n    #[test]\n    fn test_decompress_ababcbababaa() {\n        let compressor = LZ77Compressor::new(13, 6);\n        let tokens = vec![\n            Token::new(0, 0, 'a'),\n            Token::new(0, 0, 'b'),\n            Token::new(2, 2, 'c'),\n            Token::new(4, 3, 'a'),\n            Token::new(2, 2, 'a'),\n        ];\n\n        let decompressed = compressor.decompress(&tokens);\n        assert_eq!(decompressed, \"ababcbababaa\");\n    }\n\n    #[test]\n    fn test_decompress_aacaacabcabaaac() {\n        let compressor = LZ77Compressor::new(13, 6);\n        let tokens = vec![\n            Token::new(0, 0, 'a'),\n            Token::new(1, 1, 'c'),\n            Token::new(3, 4, 'b'),\n            Token::new(3, 3, 'a'),\n            Token::new(1, 2, 'c'),\n        ];\n\n        let decompressed = compressor.decompress(&tokens);\n        assert_eq!(decompressed, \"aacaacabcabaaac\");\n    }\n\n    #[test]\n    fn test_round_trip_compression() {\n        let compressor = LZ77Compressor::new(13, 6);\n        let texts = vec![\n            \"cabracadabrarrarrad\",\n            \"ababcbababaa\",\n            \"aacaacabcabaaac\",\n            \"hello world\",\n            \"aaaaaaa\",\n            \"abcdefghijk\",\n        ];\n\n        for text in texts {\n            let compressed = compressor.compress(text);\n            let decompressed = compressor.decompress(&compressed);\n            assert_eq!(text, decompressed, \"Round trip failed for text: {text}\");\n        }\n    }\n\n    #[test]\n    fn test_empty_search_buffer() {\n        let compressor = LZ77Compressor::new(13, 6);\n        let token = compressor.find_encoding_token(\"abc\", \"\");\n        assert_eq!(token, Token::new(0, 0, 'a'));\n    }\n\n    #[test]\n    #[should_panic(expected = \"Cannot encode empty text\")]\n    fn test_empty_text_panics() {\n        let compressor = LZ77Compressor::new(13, 6);\n        compressor.find_encoding_token(\"\", \"xyz\");\n    }\n\n    #[test]\n    fn test_default_compressor() {\n        let compressor = LZ77Compressor::default();\n        let text = \"test\";\n        let compressed = compressor.compress(text);\n        let decompressed = compressor.decompress(&compressed);\n        assert_eq!(text, decompressed);\n    }\n\n    #[test]\n    #[should_panic(expected = \"lookahead_buffer_size must be less than window_size\")]\n    fn test_invalid_buffer_sizes() {\n        LZ77Compressor::new(10, 10);\n    }\n\n    #[test]\n    fn test_single_character() {\n        let compressor = LZ77Compressor::new(13, 6);\n        let compressed = compressor.compress(\"a\");\n        assert_eq!(compressed, vec![Token::new(0, 0, 'a')]);\n        let decompressed = compressor.decompress(&compressed);\n        assert_eq!(decompressed, \"a\");\n    }\n\n    #[test]\n    fn test_repeated_pattern() {\n        let compressor = LZ77Compressor::new(13, 6);\n        let text = \"abababab\";\n        let compressed = compressor.compress(text);\n        let decompressed = compressor.decompress(&compressed);\n        assert_eq!(text, decompressed);\n    }\n}\n"
  },
  {
    "path": "src/compression/mod.rs",
    "content": "mod burrows_wheeler_transform;\nmod huffman_encoding;\nmod lz77;\nmod move_to_front;\nmod run_length_encoding;\n\npub use self::burrows_wheeler_transform::{all_rotations, bwt_transform, reverse_bwt, BwtResult};\npub use self::huffman_encoding::{huffman_decode, huffman_encode};\npub use self::lz77::{LZ77Compressor, Token};\npub use self::move_to_front::{move_to_front_decode, move_to_front_encode};\npub use self::run_length_encoding::{run_length_decode, run_length_encode};\n"
  },
  {
    "path": "src/compression/move_to_front.rs",
    "content": "// https://en.wikipedia.org/wiki/Move-to-front_transform\n\nfn blank_char_table() -> Vec<char> {\n    (0..=255).map(|ch| ch as u8 as char).collect()\n}\n\npub fn move_to_front_encode(text: &str) -> Vec<u8> {\n    let mut char_table = blank_char_table();\n    let mut result = Vec::new();\n\n    for ch in text.chars() {\n        if let Some(position) = char_table.iter().position(|&x| x == ch) {\n            result.push(position as u8);\n            char_table.remove(position);\n            char_table.insert(0, ch);\n        }\n    }\n\n    result\n}\n\npub fn move_to_front_decode(encoded: &[u8]) -> String {\n    let mut char_table = blank_char_table();\n    let mut result = String::new();\n\n    for &pos in encoded {\n        let ch = char_table[pos as usize];\n        result.push(ch);\n        char_table.remove(pos as usize);\n        char_table.insert(0, ch);\n    }\n\n    result\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    macro_rules! test_mtf {\n        ($($name:ident: ($text:expr, $encoded:expr),)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    assert_eq!(move_to_front_encode($text), $encoded);\n                    assert_eq!(move_to_front_decode($encoded), $text);\n                }\n            )*\n        }\n    }\n\n    test_mtf! {\n        empty: (\"\", &[]),\n        single_char: (\"@\", &[64]),\n        repeated_chars: (\"aaba\", &[97, 0, 98, 1]),\n        mixed_chars: (\"aZ!\", &[97, 91, 35]),\n        word: (\"banana\", &[98, 98, 110, 1, 1, 1]),\n        special_chars: (\"\\0\\n\\t\", &[0, 10, 10]),\n    }\n}\n"
  },
  {
    "path": "src/compression/run_length_encoding.rs",
    "content": "// https://en.wikipedia.org/wiki/Run-length_encoding\n\npub fn run_length_encode(text: &str) -> Vec<(char, i32)> {\n    let mut count = 1;\n    let mut encoded: Vec<(char, i32)> = vec![];\n\n    for (i, c) in text.chars().enumerate() {\n        if i + 1 < text.len() && c == text.chars().nth(i + 1).unwrap() {\n            count += 1;\n        } else {\n            encoded.push((c, count));\n            count = 1;\n        }\n    }\n\n    encoded\n}\n\npub fn run_length_decode(encoded: &[(char, i32)]) -> String {\n    let res = encoded\n        .iter()\n        .map(|x| (x.0).to_string().repeat(x.1 as usize))\n        .collect::<String>();\n\n    res\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_run_length_decode() {\n        let res = run_length_decode(&[('A', 0)]);\n        assert_eq!(res, \"\");\n        let res = run_length_decode(&[('B', 1)]);\n        assert_eq!(res, \"B\");\n        let res = run_length_decode(&[('A', 5), ('z', 3), ('B', 1)]);\n        assert_eq!(res, \"AAAAAzzzB\");\n    }\n\n    #[test]\n    fn test_run_length_encode() {\n        let res = run_length_encode(\"\");\n        assert_eq!(res, []);\n\n        let res = run_length_encode(\"A\");\n        assert_eq!(res, [('A', 1)]);\n\n        let res = run_length_encode(\"AA\");\n        assert_eq!(res, [('A', 2)]);\n\n        let res = run_length_encode(\"AAAABBBCCDAA\");\n        assert_eq!(res, [('A', 4), ('B', 3), ('C', 2), ('D', 1), ('A', 2)]);\n\n        let res = run_length_encode(\"Rust-Trends\");\n        assert_eq!(\n            res,\n            [\n                ('R', 1),\n                ('u', 1),\n                ('s', 1),\n                ('t', 1),\n                ('-', 1),\n                ('T', 1),\n                ('r', 1),\n                ('e', 1),\n                ('n', 1),\n                ('d', 1),\n                ('s', 1)\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "src/conversions/binary_to_decimal.rs",
    "content": "use num_traits::CheckedAdd;\n\npub fn binary_to_decimal(binary: &str) -> Option<u128> {\n    if binary.len() > 128 {\n        return None;\n    }\n    let mut num = 0;\n    let mut idx_val = 1;\n    for bit in binary.chars().rev() {\n        match bit {\n            '1' => {\n                if let Some(sum) = num.checked_add(&idx_val) {\n                    num = sum;\n                } else {\n                    return None;\n                }\n            }\n            '0' => {}\n            _ => return None,\n        }\n        idx_val <<= 1;\n    }\n    Some(num)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::binary_to_decimal;\n\n    #[test]\n    fn basic_binary_to_decimal() {\n        assert_eq!(binary_to_decimal(\"0000000110\"), Some(6));\n        assert_eq!(binary_to_decimal(\"1000011110\"), Some(542));\n        assert_eq!(binary_to_decimal(\"1111111111\"), Some(1023));\n    }\n    #[test]\n    fn big_binary_to_decimal() {\n        assert_eq!(\n            binary_to_decimal(\"111111111111111111111111\"),\n            Some(16_777_215)\n        );\n        // 32 bits\n        assert_eq!(\n            binary_to_decimal(\"11111111111111111111111111111111\"),\n            Some(4_294_967_295)\n        );\n        // 64 bits\n        assert_eq!(\n            binary_to_decimal(\"1111111111111111111111111111111111111111111111111111111111111111\"),\n            Some(18_446_744_073_709_551_615u128)\n        );\n    }\n    #[test]\n    fn very_big_binary_to_decimal() {\n        // 96 bits\n        assert_eq!(\n            binary_to_decimal(\n                \"1111111111111111111111111111111111111111111111111111111111111111\\\n                11111111111111111111111111111111\"\n            ),\n            Some(79_228_162_514_264_337_593_543_950_335u128)\n        );\n\n        // 128 bits\n        assert_eq!(\n            binary_to_decimal(\n                \"1111111111111111111111111111111111111111111111111111111111111111\\\n                1111111111111111111111111111111111111111111111111111111111111111\"\n            ),\n            Some(340_282_366_920_938_463_463_374_607_431_768_211_455u128)\n        );\n        // 129 bits, should overflow\n        assert!(binary_to_decimal(\n            \"1111111111111111111111111111111111111111111111111111111111111111\\\n                11111111111111111111111111111111111111111111111111111111111111111\"\n        )\n        .is_none());\n        // obviously none\n        assert!(binary_to_decimal(\n            \"1111111111111111111111111111111111111111111111111111111111111111\\\n                1111111111111111111111111111111111111111111111111111111111111\\\n                1111111111111111111111111111111111111111111111111111111111111\\\n                1111111111111111111111111111111111111111111111111111111111111\\\n                1111111111111111111111111111111111111111111111111111111111111\\\n                1111111111111111111111111111111111111111111111111111111111111\\\n                1111111111111111111111111111111111111111111111111111111111111\"\n        )\n        .is_none());\n    }\n}\n"
  },
  {
    "path": "src/conversions/binary_to_hexadecimal.rs",
    "content": "// Author : cyrixninja\n// Binary to Hex Converter : Converts Binary to Hexadecimal\n// Wikipedia References  : 1. https://en.wikipedia.org/wiki/Hexadecimal\n//                         2. https://en.wikipedia.org/wiki/Binary_number\n\nstatic BITS_TO_HEX: &[(u8, &str)] = &[\n    (0b0000, \"0\"),\n    (0b0001, \"1\"),\n    (0b0010, \"2\"),\n    (0b0011, \"3\"),\n    (0b0100, \"4\"),\n    (0b0101, \"5\"),\n    (0b0110, \"6\"),\n    (0b0111, \"7\"),\n    (0b1000, \"8\"),\n    (0b1001, \"9\"),\n    (0b1010, \"a\"),\n    (0b1011, \"b\"),\n    (0b1100, \"c\"),\n    (0b1101, \"d\"),\n    (0b1110, \"e\"),\n    (0b1111, \"f\"),\n];\n\npub fn binary_to_hexadecimal(binary_str: &str) -> String {\n    let binary_str = binary_str.trim();\n\n    if binary_str.is_empty() {\n        return String::from(\"Invalid Input\");\n    }\n\n    let is_negative = binary_str.starts_with('-');\n    let binary_str = if is_negative {\n        &binary_str[1..]\n    } else {\n        binary_str\n    };\n\n    if !binary_str.chars().all(|c| c == '0' || c == '1') {\n        return String::from(\"Invalid Input\");\n    }\n\n    let padded_len = (4 - (binary_str.len() % 4)) % 4;\n    let binary_str = format!(\n        \"{:0width$}\",\n        binary_str,\n        width = binary_str.len() + padded_len\n    );\n\n    // Convert binary to hexadecimal\n    let mut hexadecimal = String::with_capacity(binary_str.len() / 4 + 2);\n    hexadecimal.push_str(\"0x\");\n\n    for chunk in binary_str.as_bytes().chunks(4) {\n        let mut nibble = 0;\n        for (i, &byte) in chunk.iter().enumerate() {\n            nibble |= (byte - b'0') << (3 - i);\n        }\n\n        let hex_char = BITS_TO_HEX\n            .iter()\n            .find(|&&(bits, _)| bits == nibble)\n            .map(|&(_, hex)| hex)\n            .unwrap();\n        hexadecimal.push_str(hex_char);\n    }\n\n    if is_negative {\n        format!(\"-{hexadecimal}\")\n    } else {\n        hexadecimal\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_empty_string() {\n        let input = \"\";\n        let expected = \"Invalid Input\";\n        assert_eq!(binary_to_hexadecimal(input), expected);\n    }\n\n    #[test]\n    fn test_invalid_binary() {\n        let input = \"a\";\n        let expected = \"Invalid Input\";\n        assert_eq!(binary_to_hexadecimal(input), expected);\n    }\n\n    #[test]\n    fn test_binary() {\n        let input = \"00110110\";\n        let expected = \"0x36\";\n        assert_eq!(binary_to_hexadecimal(input), expected);\n    }\n\n    #[test]\n    fn test_padded_binary() {\n        let input = \" 1010   \";\n        let expected = \"0xa\";\n        assert_eq!(binary_to_hexadecimal(input), expected);\n    }\n}\n"
  },
  {
    "path": "src/conversions/binary_to_octal.rs",
    "content": "// Author: NithinU2802\n// Binary to Octal Converter: Converts Binary to Octal\n// Wikipedia References:\n// 1. https://en.wikipedia.org/wiki/Binary_number\n// 2. https://en.wikipedia.org/wiki/Octal\n\npub fn binary_to_octal(binary_str: &str) -> Result<String, &'static str> {\n    // Validate input\n    let binary_str = binary_str.trim();\n    if binary_str.is_empty() {\n        return Err(\"Empty string\");\n    }\n\n    if !binary_str.chars().all(|c| c == '0' || c == '1') {\n        return Err(\"Invalid binary string\");\n    }\n\n    // Pad the binary string with zeros to make its length a multiple of 3\n    let padding_length = (3 - (binary_str.len() % 3)) % 3;\n    let padded_binary = \"0\".repeat(padding_length) + binary_str;\n\n    // Convert every 3 binary digits to one octal digit\n    let mut octal = String::new();\n    for chunk in padded_binary.chars().collect::<Vec<char>>().chunks(3) {\n        let binary_group: String = chunk.iter().collect();\n        let decimal = u8::from_str_radix(&binary_group, 2).map_err(|_| \"Conversion error\")?;\n        octal.push_str(&decimal.to_string());\n    }\n\n    Ok(octal)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_binary_to_octal() {\n        assert_eq!(binary_to_octal(\"1010\"), Ok(\"12\".to_string()));\n        assert_eq!(binary_to_octal(\"1111\"), Ok(\"17\".to_string()));\n        assert_eq!(binary_to_octal(\"11111111\"), Ok(\"377\".to_string()));\n        assert_eq!(binary_to_octal(\"1100100\"), Ok(\"144\".to_string()));\n    }\n\n    #[test]\n    fn test_invalid_input() {\n        assert_eq!(binary_to_octal(\"\"), Err(\"Empty string\"));\n        assert_eq!(binary_to_octal(\"12\"), Err(\"Invalid binary string\"));\n        assert_eq!(binary_to_octal(\"abc\"), Err(\"Invalid binary string\"));\n    }\n}\n"
  },
  {
    "path": "src/conversions/decimal_to_binary.rs",
    "content": "pub fn decimal_to_binary(base_num: u64) -> String {\n    let mut num = base_num;\n    let mut binary_num = String::new();\n    loop {\n        let bit = (num % 2).to_string();\n        binary_num.push_str(&bit);\n        num /= 2;\n        if num == 0 {\n            break;\n        }\n    }\n\n    let bits = binary_num.chars();\n    bits.rev().collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn converting_decimal_to_binary() {\n        assert_eq!(decimal_to_binary(542), \"1000011110\");\n        assert_eq!(decimal_to_binary(92), \"1011100\");\n    }\n}\n"
  },
  {
    "path": "src/conversions/decimal_to_hexadecimal.rs",
    "content": "pub fn decimal_to_hexadecimal(base_num: u64) -> String {\n    let mut num = base_num;\n    let mut hexadecimal_num = String::new();\n\n    loop {\n        let remainder = num % 16;\n        let hex_char = if remainder < 10 {\n            (remainder as u8 + b'0') as char\n        } else {\n            (remainder as u8 - 10 + b'A') as char\n        };\n\n        hexadecimal_num.insert(0, hex_char);\n        num /= 16;\n        if num == 0 {\n            break;\n        }\n    }\n\n    hexadecimal_num\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_zero() {\n        assert_eq!(decimal_to_hexadecimal(0), \"0\");\n    }\n\n    #[test]\n    fn test_single_digit_decimal() {\n        assert_eq!(decimal_to_hexadecimal(9), \"9\");\n    }\n\n    #[test]\n    fn test_single_digit_hexadecimal() {\n        assert_eq!(decimal_to_hexadecimal(12), \"C\");\n    }\n\n    #[test]\n    fn test_multiple_digit_hexadecimal() {\n        assert_eq!(decimal_to_hexadecimal(255), \"FF\");\n    }\n\n    #[test]\n    fn test_big() {\n        assert_eq!(decimal_to_hexadecimal(u64::MAX), \"FFFFFFFFFFFFFFFF\");\n    }\n\n    #[test]\n    fn test_random() {\n        assert_eq!(decimal_to_hexadecimal(123456), \"1E240\");\n    }\n}\n"
  },
  {
    "path": "src/conversions/decimal_to_octal.rs",
    "content": "// Author: NithinU2802\n// Decimal to Octal Converter: Converts Decimal to Octal\n// Wikipedia References:\n// 1. https://en.wikipedia.org/wiki/Decimal\n// 2. https://en.wikipedia.org/wiki/Octal\n\npub fn decimal_to_octal(decimal_num: u64) -> String {\n    if decimal_num == 0 {\n        return \"0\".to_string();\n    }\n\n    let mut num = decimal_num;\n    let mut octal = String::new();\n\n    while num > 0 {\n        let remainder = num % 8;\n        octal.push_str(&remainder.to_string());\n        num /= 8;\n    }\n\n    // Reverse the string to get the correct octal representation\n    octal.chars().rev().collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_decimal_to_octal() {\n        assert_eq!(decimal_to_octal(8), \"10\");\n        assert_eq!(decimal_to_octal(15), \"17\");\n        assert_eq!(decimal_to_octal(255), \"377\");\n        assert_eq!(decimal_to_octal(100), \"144\");\n        assert_eq!(decimal_to_octal(0), \"0\");\n    }\n}\n"
  },
  {
    "path": "src/conversions/energy.rs",
    "content": "//! Convert between different units of energy\n//!\n//! Supports conversions between 70+ energy units using Joule as an intermediary:\n//! - SI units: Joule (J), kilojoule, megajoule, gigajoule\n//! - Power-time units: Watt-hour, kilowatt-hour, megawatt-hour\n//! - Calories: Nutritional, IT (International Table), thermochemical\n//! - Electron volts: eV, keV, MeV\n//! - British Thermal Units: BTU (IT), BTU (th), mega BTU\n//! - Imperial units: foot-pound, pound-force foot, etc.\n//! - Historical and specialized units: therm, ton TNT equivalent, Hartree energy\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum EnergyUnit {\n    // SI units\n    Joule,\n    Kilojoule,\n    Megajoule,\n    Gigajoule,\n    Millijoule,\n    Microjoule,\n    Nanojoule,\n    Attojoule,\n\n    // Power-time units\n    WattSecond,\n    WattHour,\n    KilowattSecond,\n    KilowattHour,\n    MegawattHour,\n    GigawattHour,\n\n    // Mechanical units\n    NewtonMeter,\n    Erg,\n    DyneCentimeter,\n\n    // Calories\n    CalorieNutritional,\n    KilocalorieNutritional,\n    CalorieIT,\n    KilocalorieIT,\n    CalorieTh,\n    KilocalorieTh,\n\n    // Electron volts\n    Electronvolt,\n    Kiloelectronvolt,\n    Megaelectronvolt,\n\n    // British Thermal Units\n    BtuIT,\n    BtuTh,\n    MegaBtuIT,\n\n    // Imperial force-distance units\n    FootPound,\n    PoundForceFoot,\n    PoundForceInch,\n    InchPound,\n    InchOunce,\n    OunceForceInch,\n    PoundalFoot,\n\n    // Horsepower units\n    HorsepowerHour,\n    HorsepowerMetricHour,\n\n    // Metric force units\n    KilogramForceMeter,\n    KilogramForceCentimeter,\n    KilopondMeter,\n    GramForceMeter,\n    GramForceCentimeter,\n\n    // Therm units\n    Therm,\n    ThermEC,\n    ThermUS,\n\n    // Specialized units\n    TonHourRefrigeration,\n    FuelOilEquivalentKiloliter,\n    FuelOilEquivalentBarrel,\n    TonExplosives,\n    Kiloton,\n    Megaton,\n    Gigaton,\n\n    // Atomic units\n    HartreeEnergy,\n    RydbergConstant,\n}\n\nimpl EnergyUnit {\n    fn to_joule(self, value: f64) -> f64 {\n        match self {\n            // SI units\n            EnergyUnit::Joule | EnergyUnit::WattSecond | EnergyUnit::NewtonMeter => value,\n            EnergyUnit::Kilojoule | EnergyUnit::KilowattSecond => value * 1_000.0,\n            EnergyUnit::Megajoule => value * 1_000_000.0,\n            EnergyUnit::Gigajoule => value * 1_000_000_000.0,\n            EnergyUnit::Millijoule => value * 0.001,\n            EnergyUnit::Microjoule => value * 1.0e-6,\n            EnergyUnit::Nanojoule => value * 1.0e-9,\n            EnergyUnit::Attojoule => value * 1.0e-18,\n\n            // Power-time units\n            EnergyUnit::WattHour => value * 3_600.0,\n            EnergyUnit::KilowattHour => value * 3_600_000.0,\n            EnergyUnit::MegawattHour => value * 3_600_000_000.0,\n            EnergyUnit::GigawattHour => value * 3_600_000_000_000.0,\n\n            // Mechanical units\n            EnergyUnit::Erg | EnergyUnit::DyneCentimeter => value * 1.0e-7,\n\n            // Calories\n            EnergyUnit::CalorieNutritional | EnergyUnit::KilocalorieIT => value * 4_186.8,\n            EnergyUnit::KilocalorieNutritional => value * 4_186_800.0,\n            EnergyUnit::CalorieIT => value * 4.1868,\n            EnergyUnit::CalorieTh => value * 4.184,\n            EnergyUnit::KilocalorieTh => value * 4_184.0,\n\n            // Electron volts\n            EnergyUnit::Electronvolt => value * 1.602_176_634e-19,\n            EnergyUnit::Kiloelectronvolt => value * 1.602_176_634e-16,\n            EnergyUnit::Megaelectronvolt => value * 1.602_176_634e-13,\n\n            // British Thermal Units\n            EnergyUnit::BtuIT => value * 1_055.055_852_62,\n            EnergyUnit::BtuTh => value * 1_054.349_999_974_4,\n            EnergyUnit::MegaBtuIT => value * 1_055_055_852.62,\n\n            // Imperial force-distance units\n            EnergyUnit::FootPound | EnergyUnit::PoundForceFoot => value * 1.355_817_948_3,\n            EnergyUnit::PoundForceInch | EnergyUnit::InchPound => value * 0.112_984_829,\n            EnergyUnit::InchOunce | EnergyUnit::OunceForceInch => value * 0.007_061_551_8,\n            EnergyUnit::PoundalFoot => value * 0.042_140_11,\n\n            // Horsepower units\n            EnergyUnit::HorsepowerHour => value * 2_684_519.536_885_6,\n            EnergyUnit::HorsepowerMetricHour => value * 2_647_795.5,\n\n            // Metric force units\n            EnergyUnit::KilogramForceMeter | EnergyUnit::KilopondMeter => value * 9.806_649_999_7,\n            EnergyUnit::KilogramForceCentimeter => value * 0.098_066_5,\n            EnergyUnit::GramForceMeter => value * 0.009_806_65,\n            EnergyUnit::GramForceCentimeter => value * 9.806_65e-5,\n\n            // Therm units\n            EnergyUnit::Therm | EnergyUnit::ThermEC => value * 105_505_600.0,\n            EnergyUnit::ThermUS => value * 105_480_400.0,\n\n            // Specialized units\n            EnergyUnit::TonHourRefrigeration => value * 12_660_670.231_44,\n            EnergyUnit::FuelOilEquivalentKiloliter => value * 40_197_627_984.822,\n            EnergyUnit::FuelOilEquivalentBarrel => value * 6_383_087_908.350_9,\n            EnergyUnit::TonExplosives => value * 4_184_000_000.0,\n            EnergyUnit::Kiloton => value * 4_184_000_000_000.0,\n            EnergyUnit::Megaton => value * 4.184e15,\n            EnergyUnit::Gigaton => value * 4.184e18,\n\n            // Atomic units\n            EnergyUnit::HartreeEnergy => value * 4.359_748_2e-18,\n            EnergyUnit::RydbergConstant => value * 2.179_874_1e-18,\n        }\n    }\n\n    fn joule_to_unit(self, joule: f64) -> f64 {\n        match self {\n            // SI units\n            EnergyUnit::Joule | EnergyUnit::WattSecond | EnergyUnit::NewtonMeter => joule,\n            EnergyUnit::Kilojoule | EnergyUnit::KilowattSecond => joule / 1_000.0,\n            EnergyUnit::Megajoule => joule / 1_000_000.0,\n            EnergyUnit::Gigajoule => joule / 1_000_000_000.0,\n            EnergyUnit::Millijoule => joule / 0.001,\n            EnergyUnit::Microjoule => joule / 1.0e-6,\n            EnergyUnit::Nanojoule => joule / 1.0e-9,\n            EnergyUnit::Attojoule => joule / 1.0e-18,\n\n            // Power-time units\n            EnergyUnit::WattHour => joule / 3_600.0,\n            EnergyUnit::KilowattHour => joule / 3_600_000.0,\n            EnergyUnit::MegawattHour => joule / 3_600_000_000.0,\n            EnergyUnit::GigawattHour => joule / 3_600_000_000_000.0,\n\n            // Mechanical units\n            EnergyUnit::Erg | EnergyUnit::DyneCentimeter => joule / 1.0e-7,\n\n            // Calories\n            EnergyUnit::CalorieNutritional | EnergyUnit::KilocalorieIT => joule / 4_186.8,\n            EnergyUnit::KilocalorieNutritional => joule / 4_186_800.0,\n            EnergyUnit::CalorieIT => joule / 4.1868,\n            EnergyUnit::CalorieTh => joule / 4.184,\n            EnergyUnit::KilocalorieTh => joule / 4_184.0,\n\n            // Electron volts\n            EnergyUnit::Electronvolt => joule / 1.602_176_634e-19,\n            EnergyUnit::Kiloelectronvolt => joule / 1.602_176_634e-16,\n            EnergyUnit::Megaelectronvolt => joule / 1.602_176_634e-13,\n\n            // British Thermal Units\n            EnergyUnit::BtuIT => joule / 1_055.055_852_62,\n            EnergyUnit::BtuTh => joule / 1_054.349_999_974_4,\n            EnergyUnit::MegaBtuIT => joule / 1_055_055_852.62,\n\n            // Imperial force-distance units\n            EnergyUnit::FootPound | EnergyUnit::PoundForceFoot => joule / 1.355_817_948_3,\n            EnergyUnit::PoundForceInch | EnergyUnit::InchPound => joule / 0.112_984_829,\n            EnergyUnit::InchOunce | EnergyUnit::OunceForceInch => joule / 0.007_061_551_8,\n            EnergyUnit::PoundalFoot => joule / 0.042_140_11,\n\n            // Horsepower units\n            EnergyUnit::HorsepowerHour => joule / 2_684_519.536_885_6,\n            EnergyUnit::HorsepowerMetricHour => joule / 2_647_795.5,\n\n            // Metric force units\n            EnergyUnit::KilogramForceMeter | EnergyUnit::KilopondMeter => joule / 9.806_649_999_7,\n            EnergyUnit::KilogramForceCentimeter => joule / 0.098_066_5,\n            EnergyUnit::GramForceMeter => joule / 0.009_806_65,\n            EnergyUnit::GramForceCentimeter => joule / 9.806_65e-5,\n\n            // Therm units\n            EnergyUnit::Therm | EnergyUnit::ThermEC => joule / 105_505_600.0,\n            EnergyUnit::ThermUS => joule / 105_480_400.0,\n\n            // Specialized units\n            EnergyUnit::TonHourRefrigeration => joule / 12_660_670.231_44,\n            EnergyUnit::FuelOilEquivalentKiloliter => joule / 40_197_627_984.822,\n            EnergyUnit::FuelOilEquivalentBarrel => joule / 6_383_087_908.350_9,\n            EnergyUnit::TonExplosives => joule / 4_184_000_000.0,\n            EnergyUnit::Kiloton => joule / 4_184_000_000_000.0,\n            EnergyUnit::Megaton => joule / 4.184e15,\n            EnergyUnit::Gigaton => joule / 4.184e18,\n\n            // Atomic units\n            EnergyUnit::HartreeEnergy => joule / 4.359_748_2e-18,\n            EnergyUnit::RydbergConstant => joule / 2.179_874_1e-18,\n        }\n    }\n}\n\npub fn convert_energy(value: f64, from: EnergyUnit, to: EnergyUnit) -> f64 {\n    let joule = from.to_joule(value);\n    to.joule_to_unit(joule)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    const EPSILON: f64 = 1e-10;\n\n    fn approx_eq(a: f64, b: f64) -> bool {\n        (a - b).abs() < EPSILON\n    }\n\n    #[test]\n    fn test_same_unit_conversion() {\n        let value = 42.0;\n        for unit in [\n            EnergyUnit::Joule,\n            EnergyUnit::Kilojoule,\n            EnergyUnit::KilowattHour,\n            EnergyUnit::CalorieNutritional,\n            EnergyUnit::BtuIT,\n            EnergyUnit::FootPound,\n        ] {\n            assert!(approx_eq(convert_energy(value, unit, unit), value));\n        }\n    }\n\n    #[test]\n    fn test_joule_to_kilojoule() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Joule, EnergyUnit::Kilojoule),\n            0.001\n        ));\n        assert!(approx_eq(\n            convert_energy(1000.0, EnergyUnit::Joule, EnergyUnit::Kilojoule),\n            1.0\n        ));\n    }\n\n    #[test]\n    fn test_joule_to_megajoule() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Joule, EnergyUnit::Megajoule),\n            1e-6\n        ));\n        assert!(approx_eq(\n            convert_energy(1_000_000.0, EnergyUnit::Joule, EnergyUnit::Megajoule),\n            1.0\n        ));\n    }\n\n    #[test]\n    fn test_joule_to_gigajoule() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Joule, EnergyUnit::Gigajoule),\n            1e-9\n        ));\n    }\n\n    #[test]\n    fn test_watt_second() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Joule, EnergyUnit::WattSecond),\n            1.0\n        ));\n    }\n\n    #[test]\n    fn test_watt_hour() {\n        let result = convert_energy(1.0, EnergyUnit::Joule, EnergyUnit::WattHour);\n        assert!((result - 0.000_277_777_777_777_777_8).abs() < 1e-15);\n    }\n\n    #[test]\n    fn test_kilowatt_hour_conversions() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::KilowattHour, EnergyUnit::Joule),\n            3_600_000.0\n        ));\n        assert!(approx_eq(\n            convert_energy(10.0, EnergyUnit::KilowattHour, EnergyUnit::Joule),\n            36_000_000.0\n        ));\n    }\n\n    #[test]\n    fn test_newton_meter() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Joule, EnergyUnit::NewtonMeter),\n            1.0\n        ));\n    }\n\n    #[test]\n    fn test_calorie_nutritional() {\n        let result = convert_energy(1.0, EnergyUnit::Joule, EnergyUnit::CalorieNutritional);\n        assert!((result - 0.000_238_845_896_627_495_9).abs() < 1e-15);\n\n        assert!(approx_eq(\n            convert_energy(\n                1000.0,\n                EnergyUnit::CalorieNutritional,\n                EnergyUnit::KilocalorieNutritional\n            ),\n            1.0\n        ));\n    }\n\n    #[test]\n    fn test_electronvolt() {\n        let result = convert_energy(1.0, EnergyUnit::Joule, EnergyUnit::Electronvolt);\n        assert!((result - 6.241_509_074_460_763e18).abs() < 1e15);\n    }\n\n    #[test]\n    fn test_btu_conversions() {\n        let result = convert_energy(1.0, EnergyUnit::Joule, EnergyUnit::BtuIT);\n        assert!((result - 0.000_947_817_120_313_317_3).abs() < 1e-15);\n\n        let result = convert_energy(1.0, EnergyUnit::BtuIT, EnergyUnit::FootPound);\n        assert!((result - 778.169).abs() < 0.01);\n    }\n\n    #[test]\n    fn test_foot_pound() {\n        let result = convert_energy(1.0, EnergyUnit::Joule, EnergyUnit::FootPound);\n        assert!((result - 0.737_562_149_294_347).abs() < 1e-10);\n    }\n\n    #[test]\n    fn test_round_trip_conversions() {\n        let value = 100.0;\n        let units = [\n            EnergyUnit::Joule,\n            EnergyUnit::Kilojoule,\n            EnergyUnit::KilowattHour,\n            EnergyUnit::CalorieNutritional,\n            EnergyUnit::BtuIT,\n            EnergyUnit::FootPound,\n            EnergyUnit::Electronvolt,\n            EnergyUnit::Erg,\n        ];\n\n        for from_unit in units.iter() {\n            for to_unit in units.iter() {\n                let converted = convert_energy(value, *from_unit, *to_unit);\n                let back = convert_energy(converted, *to_unit, *from_unit);\n                assert!(\n                    approx_eq(back, value),\n                    \"Round trip failed: {from_unit:?} -> {to_unit:?} -> {from_unit:?}: {back} != {value}\"\n                );\n            }\n        }\n    }\n\n    #[test]\n    fn test_megawatt_hour() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::MegawattHour, EnergyUnit::Joule),\n            3_600_000_000.0\n        ));\n    }\n\n    #[test]\n    fn test_horsepower_hour() {\n        let result = convert_energy(1.0, EnergyUnit::HorsepowerHour, EnergyUnit::Joule);\n        assert!((result - 2_684_519.536_885_6).abs() < 0.01);\n    }\n\n    #[test]\n    fn test_therm() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Therm, EnergyUnit::Joule),\n            105_505_600.0\n        ));\n    }\n\n    #[test]\n    fn test_ton_explosives() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::TonExplosives, EnergyUnit::Joule),\n            4_184_000_000.0\n        ));\n    }\n\n    #[test]\n    fn test_kiloton() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Kiloton, EnergyUnit::Joule),\n            4_184_000_000_000.0\n        ));\n    }\n\n    #[test]\n    fn test_erg() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Erg, EnergyUnit::Joule),\n            1.0e-7\n        ));\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Joule, EnergyUnit::Erg),\n            1.0e7\n        ));\n    }\n\n    #[test]\n    fn test_small_si_units() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Millijoule, EnergyUnit::Joule),\n            0.001\n        ));\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Microjoule, EnergyUnit::Joule),\n            1.0e-6\n        ));\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Nanojoule, EnergyUnit::Joule),\n            1.0e-9\n        ));\n    }\n\n    #[test]\n    fn test_calorie_variants() {\n        let it_result = convert_energy(1.0, EnergyUnit::CalorieIT, EnergyUnit::Joule);\n        let th_result = convert_energy(1.0, EnergyUnit::CalorieTh, EnergyUnit::Joule);\n        assert!((it_result - 4.1868).abs() < 1e-10);\n        assert!((th_result - 4.184).abs() < 1e-10);\n    }\n\n    #[test]\n    fn test_food_energy() {\n        // 2000 Calories (nutritional) to kilojoules\n        let result = convert_energy(\n            2000.0,\n            EnergyUnit::CalorieNutritional,\n            EnergyUnit::Kilojoule,\n        );\n        assert!((result - 8373.6).abs() < 0.1);\n    }\n\n    #[test]\n    fn test_electricity_bill() {\n        // 100 kWh to megajoules\n        let result = convert_energy(100.0, EnergyUnit::KilowattHour, EnergyUnit::Megajoule);\n        assert!((result - 360.0).abs() < 0.1);\n    }\n\n    #[test]\n    fn test_zero_value() {\n        assert!(approx_eq(\n            convert_energy(0.0, EnergyUnit::Joule, EnergyUnit::KilowattHour),\n            0.0\n        ));\n    }\n\n    #[test]\n    fn test_negative_value() {\n        assert!(approx_eq(\n            convert_energy(-1000.0, EnergyUnit::Joule, EnergyUnit::Kilojoule),\n            -1.0\n        ));\n    }\n\n    #[test]\n    fn test_large_value() {\n        let result = convert_energy(100.0, EnergyUnit::Gigajoule, EnergyUnit::Joule);\n        assert!(approx_eq(result, 100_000_000_000.0));\n    }\n\n    #[test]\n    fn test_imperial_units() {\n        // Pound-force foot equals foot-pound\n        let value = 50.0;\n        let result1 = convert_energy(value, EnergyUnit::FootPound, EnergyUnit::Joule);\n        let result2 = convert_energy(value, EnergyUnit::PoundForceFoot, EnergyUnit::Joule);\n        assert!(approx_eq(result1, result2));\n    }\n\n    #[test]\n    fn test_electron_volt_variants() {\n        assert!(approx_eq(\n            convert_energy(1.0, EnergyUnit::Kiloelectronvolt, EnergyUnit::Electronvolt),\n            1000.0\n        ));\n        assert!(approx_eq(\n            convert_energy(\n                1.0,\n                EnergyUnit::Megaelectronvolt,\n                EnergyUnit::Kiloelectronvolt\n            ),\n            1000.0\n        ));\n    }\n\n    #[test]\n    fn test_therm_variants() {\n        // Therm and Therm EC should be equal\n        let value = 5.0;\n        let result1 = convert_energy(value, EnergyUnit::Therm, EnergyUnit::Joule);\n        let result2 = convert_energy(value, EnergyUnit::ThermEC, EnergyUnit::Joule);\n        assert!(approx_eq(result1, result2));\n\n        // Therm US should be slightly different\n        let result3 = convert_energy(value, EnergyUnit::ThermUS, EnergyUnit::Joule);\n        assert!((result1 - result3).abs() > 1.0); // They differ\n    }\n\n    #[test]\n    fn test_explosive_yield() {\n        // 1 megaton TNT to gigajoules\n        let result = convert_energy(1.0, EnergyUnit::Megaton, EnergyUnit::Gigajoule);\n        assert!((result - 4_184_000.0).abs() < 1.0);\n    }\n\n    #[test]\n    fn test_atomic_units() {\n        // Hartree energy conversion\n        let result = convert_energy(1.0, EnergyUnit::HartreeEnergy, EnergyUnit::Joule);\n        assert!((result - 4.359_748_2e-18).abs() < 1e-25);\n\n        // Rydberg constant should be half of Hartree\n        let hartree = convert_energy(1.0, EnergyUnit::HartreeEnergy, EnergyUnit::Joule);\n        let rydberg = convert_energy(1.0, EnergyUnit::RydbergConstant, EnergyUnit::Joule);\n        assert!((rydberg * 2.0 - hartree).abs() < 1e-25);\n    }\n}\n"
  },
  {
    "path": "src/conversions/hexadecimal_to_binary.rs",
    "content": "// Author : cyrixninja\n// Hexadecimal to Binary Converter : Converts Hexadecimal to Binary\n// Wikipedia References  : 1. https://en.wikipedia.org/wiki/Hexadecimal\n//                         2. https://en.wikipedia.org/wiki/Binary_number\n// Other References for Testing : https://www.rapidtables.com/convert/number/hex-to-binary.html\n\npub fn hexadecimal_to_binary(hex_str: &str) -> Result<String, String> {\n    let hex_chars = hex_str.chars().collect::<Vec<char>>();\n    let mut binary = String::new();\n\n    for c in hex_chars {\n        let bin_rep = match c {\n            '0' => \"0000\",\n            '1' => \"0001\",\n            '2' => \"0010\",\n            '3' => \"0011\",\n            '4' => \"0100\",\n            '5' => \"0101\",\n            '6' => \"0110\",\n            '7' => \"0111\",\n            '8' => \"1000\",\n            '9' => \"1001\",\n            'a' | 'A' => \"1010\",\n            'b' | 'B' => \"1011\",\n            'c' | 'C' => \"1100\",\n            'd' | 'D' => \"1101\",\n            'e' | 'E' => \"1110\",\n            'f' | 'F' => \"1111\",\n            _ => return Err(\"Invalid\".to_string()),\n        };\n        binary.push_str(bin_rep);\n    }\n\n    Ok(binary)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_empty_string() {\n        let input = \"\";\n        let expected = Ok(\"\".to_string());\n        assert_eq!(hexadecimal_to_binary(input), expected);\n    }\n\n    #[test]\n    fn test_hexadecimal() {\n        let input = \"1a2\";\n        let expected = Ok(\"000110100010\".to_string());\n        assert_eq!(hexadecimal_to_binary(input), expected);\n    }\n    #[test]\n    fn test_hexadecimal2() {\n        let input = \"1b3\";\n        let expected = Ok(\"000110110011\".to_string());\n        assert_eq!(hexadecimal_to_binary(input), expected);\n    }\n\n    #[test]\n    fn test_invalid_hexadecimal() {\n        let input = \"1g3\";\n        let expected = Err(\"Invalid\".to_string());\n        assert_eq!(hexadecimal_to_binary(input), expected);\n    }\n}\n"
  },
  {
    "path": "src/conversions/hexadecimal_to_decimal.rs",
    "content": "pub fn hexadecimal_to_decimal(hexadecimal_str: &str) -> Result<u64, &'static str> {\n    if hexadecimal_str.is_empty() {\n        return Err(\"Empty input\");\n    }\n\n    for hexadecimal_str in hexadecimal_str.chars() {\n        if !hexadecimal_str.is_ascii_hexdigit() {\n            return Err(\"Input was not a hexadecimal number\");\n        }\n    }\n\n    match u64::from_str_radix(hexadecimal_str, 16) {\n        Ok(decimal) => Ok(decimal),\n        Err(_e) => Err(\"Failed to convert octal to hexadecimal\"),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_hexadecimal_to_decimal_empty() {\n        assert_eq!(hexadecimal_to_decimal(\"\"), Err(\"Empty input\"));\n    }\n\n    #[test]\n    fn test_hexadecimal_to_decimal_invalid() {\n        assert_eq!(\n            hexadecimal_to_decimal(\"xyz\"),\n            Err(\"Input was not a hexadecimal number\")\n        );\n        assert_eq!(\n            hexadecimal_to_decimal(\"0xabc\"),\n            Err(\"Input was not a hexadecimal number\")\n        );\n    }\n\n    #[test]\n    fn test_hexadecimal_to_decimal_valid1() {\n        assert_eq!(hexadecimal_to_decimal(\"45\"), Ok(69));\n        assert_eq!(hexadecimal_to_decimal(\"2b3\"), Ok(691));\n        assert_eq!(hexadecimal_to_decimal(\"4d2\"), Ok(1234));\n        assert_eq!(hexadecimal_to_decimal(\"1267a\"), Ok(75386));\n    }\n\n    #[test]\n    fn test_hexadecimal_to_decimal_valid2() {\n        assert_eq!(hexadecimal_to_decimal(\"1a\"), Ok(26));\n        assert_eq!(hexadecimal_to_decimal(\"ff\"), Ok(255));\n        assert_eq!(hexadecimal_to_decimal(\"a1b\"), Ok(2587));\n        assert_eq!(hexadecimal_to_decimal(\"7fffffff\"), Ok(2147483647));\n    }\n\n    #[test]\n    fn test_hexadecimal_to_decimal_valid3() {\n        assert_eq!(hexadecimal_to_decimal(\"0\"), Ok(0));\n        assert_eq!(hexadecimal_to_decimal(\"7f\"), Ok(127));\n        assert_eq!(hexadecimal_to_decimal(\"80000000\"), Ok(2147483648));\n    }\n}\n"
  },
  {
    "path": "src/conversions/hexadecimal_to_octal.rs",
    "content": "// Author: NithinU2802\n// Hexadecimal to Octal Converter: Converts Hexadecimal to Octal\n// Wikipedia References:\n// 1. https://en.wikipedia.org/wiki/Hexadecimal\n// 2. https://en.wikipedia.org/wiki/Octal\n\npub fn hexadecimal_to_octal(hex_str: &str) -> Result<String, &'static str> {\n    let hex_str = hex_str.trim();\n\n    if hex_str.is_empty() {\n        return Err(\"Empty string\");\n    }\n\n    // Validate hexadecimal string\n    if !hex_str.chars().all(|c| c.is_ascii_hexdigit()) {\n        return Err(\"Invalid hexadecimal string\");\n    }\n\n    // Convert hex to decimal first\n    let decimal = u64::from_str_radix(hex_str, 16).map_err(|_| \"Conversion error\")?;\n\n    // Then convert decimal to octal\n    if decimal == 0 {\n        return Ok(\"0\".to_string());\n    }\n\n    let mut num = decimal;\n    let mut octal = String::new();\n\n    while num > 0 {\n        let remainder = num % 8;\n        octal.push_str(&remainder.to_string());\n        num /= 8;\n    }\n\n    // Reverse the string to get the correct octal representation\n    Ok(octal.chars().rev().collect())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_hexadecimal_to_octal() {\n        assert_eq!(hexadecimal_to_octal(\"A\"), Ok(\"12\".to_string()));\n        assert_eq!(hexadecimal_to_octal(\"FF\"), Ok(\"377\".to_string()));\n        assert_eq!(hexadecimal_to_octal(\"64\"), Ok(\"144\".to_string()));\n        assert_eq!(hexadecimal_to_octal(\"0\"), Ok(\"0\".to_string()));\n    }\n\n    #[test]\n    fn test_invalid_input() {\n        assert_eq!(hexadecimal_to_octal(\"\"), Err(\"Empty string\"));\n        assert_eq!(\n            hexadecimal_to_octal(\"GG\"),\n            Err(\"Invalid hexadecimal string\")\n        );\n        assert_eq!(\n            hexadecimal_to_octal(\"XYZ\"),\n            Err(\"Invalid hexadecimal string\")\n        );\n    }\n}\n"
  },
  {
    "path": "src/conversions/ipv4_conversion.rs",
    "content": "/// Module for converting between IPv4 addresses and their decimal representations\n///\n/// This module provides functions to convert IPv4 addresses to decimal integers\n/// and vice versa.\n///\n/// Reference: https://www.geeksforgeeks.org/convert-ip-address-to-integer-and-vice-versa/\nuse std::num::ParseIntError;\n\n/// Errors that can occur during IPv4 address conversion\n#[derive(Debug, PartialEq)]\npub enum Ipv4Error {\n    /// The IPv4 address does not have exactly 4 octets\n    InvalidFormat,\n    /// An octet value is greater than 255\n    InvalidOctet(u32),\n    /// The decimal value is out of valid range\n    InvalidDecimal,\n    /// Failed to parse an octet as a number\n    ParseError,\n}\n\nimpl std::fmt::Display for Ipv4Error {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Ipv4Error::InvalidFormat => write!(f, \"Invalid IPv4 address format\"),\n            Ipv4Error::InvalidOctet(octet) => write!(f, \"Invalid IPv4 octet {octet}\"),\n            Ipv4Error::InvalidDecimal => write!(f, \"Invalid decimal IPv4 address\"),\n            Ipv4Error::ParseError => write!(f, \"Failed to parse octet\"),\n        }\n    }\n}\n\nimpl std::error::Error for Ipv4Error {}\n\nimpl From<ParseIntError> for Ipv4Error {\n    fn from(_: ParseIntError) -> Self {\n        Ipv4Error::ParseError\n    }\n}\n\n/// Convert an IPv4 address to its decimal representation.\n///\n/// The conversion is performed by treating each octet as 8 bits and combining\n/// them into a 32-bit unsigned integer.\n///\n/// # Arguments\n///\n/// * `ipv4_address` - A string slice representing an IPv4 address (e.g., \"192.168.0.1\")\n///\n/// # Returns\n///\n/// * `Ok(u32)` - The decimal representation of the IP address\n/// * `Err(Ipv4Error)` - If the input format is invalid or contains invalid octets\npub fn ipv4_to_decimal(ipv4_address: &str) -> Result<u32, Ipv4Error> {\n    let octets: Vec<&str> = ipv4_address.split('.').collect();\n\n    if octets.len() != 4 {\n        return Err(Ipv4Error::InvalidFormat);\n    }\n\n    let mut decimal_ipv4: u32 = 0;\n\n    for octet_str in octets {\n        let octet: u32 = octet_str.parse()?;\n\n        if octet > 255 {\n            return Err(Ipv4Error::InvalidOctet(octet));\n        }\n\n        decimal_ipv4 = (decimal_ipv4 << 8) + octet;\n    }\n\n    Ok(decimal_ipv4)\n}\n\n/// Alternative implementation to convert an IPv4 address to its decimal representation\n/// using hexadecimal conversion.\n///\n/// This function converts each octet to a two-digit hexadecimal string, concatenates\n/// them, and then parses the result as a hexadecimal number.\n///\n/// # Arguments\n///\n/// * `ipv4_address` - A string slice representing an IPv4 address\n///\n/// # Returns\n///\n/// * `Ok(u32)` - The decimal representation of the IP address\n/// * `Err(Ipv4Error)` - If the input is invalid\npub fn alt_ipv4_to_decimal(ipv4_address: &str) -> Result<u32, Ipv4Error> {\n    let octets: Vec<&str> = ipv4_address.split('.').collect();\n\n    if octets.len() != 4 {\n        return Err(Ipv4Error::InvalidFormat);\n    }\n\n    let hex_string: String = octets\n        .iter()\n        .map(|octet| {\n            let num: u32 = octet.parse().map_err(|_| Ipv4Error::ParseError)?;\n            if num > 255 {\n                return Err(Ipv4Error::InvalidOctet(num));\n            }\n            Ok(format!(\"{num:02x}\"))\n        })\n        .collect::<Result<Vec<String>, Ipv4Error>>()?\n        .join(\"\");\n\n    u32::from_str_radix(&hex_string, 16).map_err(|_| Ipv4Error::ParseError)\n}\n\n/// Convert a decimal representation of an IP address to its IPv4 format.\n///\n/// The conversion extracts each octet by masking the lower 8 bits and right-shifting.\n///\n/// # Arguments\n///\n/// * `decimal_ipv4` - An unsigned 32-bit integer representing the decimal IP address\n///\n/// # Returns\n///\n/// * `Ok(String)` - The IPv4 representation of the decimal IP address\npub fn decimal_to_ipv4(decimal_ipv4: u32) -> Result<String, Ipv4Error> {\n    let mut ip_parts = Vec::new();\n    let mut num = decimal_ipv4;\n\n    for _ in 0..4 {\n        ip_parts.push((num & 255).to_string());\n        num >>= 8;\n    }\n\n    ip_parts.reverse();\n    Ok(ip_parts.join(\".\"))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_ipv4_to_decimal_valid() {\n        assert_eq!(ipv4_to_decimal(\"192.168.0.1\").unwrap(), 3232235521);\n        assert_eq!(ipv4_to_decimal(\"10.0.0.255\").unwrap(), 167772415);\n        assert_eq!(ipv4_to_decimal(\"0.0.0.0\").unwrap(), 0);\n        assert_eq!(ipv4_to_decimal(\"255.255.255.255\").unwrap(), 4294967295);\n        assert_eq!(ipv4_to_decimal(\"8.8.8.8\").unwrap(), 134744072);\n    }\n\n    #[test]\n    fn test_ipv4_to_decimal_invalid_format() {\n        assert_eq!(ipv4_to_decimal(\"10.0.255\"), Err(Ipv4Error::InvalidFormat));\n        assert_eq!(ipv4_to_decimal(\"10.0.0.0.1\"), Err(Ipv4Error::InvalidFormat));\n        assert_eq!(ipv4_to_decimal(\"\"), Err(Ipv4Error::InvalidFormat));\n        assert_eq!(ipv4_to_decimal(\"192.168.0\"), Err(Ipv4Error::InvalidFormat));\n    }\n\n    #[test]\n    fn test_ipv4_to_decimal_invalid_octet() {\n        assert_eq!(\n            ipv4_to_decimal(\"10.0.0.256\"),\n            Err(Ipv4Error::InvalidOctet(256))\n        );\n        assert_eq!(\n            ipv4_to_decimal(\"300.168.0.1\"),\n            Err(Ipv4Error::InvalidOctet(300))\n        );\n        assert_eq!(\n            ipv4_to_decimal(\"192.168.256.1\"),\n            Err(Ipv4Error::InvalidOctet(256))\n        );\n    }\n\n    #[test]\n    fn test_ipv4_to_decimal_parse_error() {\n        assert_eq!(ipv4_to_decimal(\"192.168.0.abc\"), Err(Ipv4Error::ParseError));\n        assert_eq!(ipv4_to_decimal(\"a.b.c.d\"), Err(Ipv4Error::ParseError));\n    }\n\n    #[test]\n    fn test_alt_ipv4_to_decimal_valid() {\n        assert_eq!(alt_ipv4_to_decimal(\"192.168.0.1\").unwrap(), 3232235521);\n        assert_eq!(alt_ipv4_to_decimal(\"10.0.0.255\").unwrap(), 167772415);\n        assert_eq!(alt_ipv4_to_decimal(\"0.0.0.0\").unwrap(), 0);\n        assert_eq!(alt_ipv4_to_decimal(\"255.255.255.255\").unwrap(), 4294967295);\n    }\n\n    #[test]\n    fn test_alt_ipv4_to_decimal_invalid() {\n        assert_eq!(\n            alt_ipv4_to_decimal(\"10.0.255\"),\n            Err(Ipv4Error::InvalidFormat)\n        );\n        assert_eq!(\n            alt_ipv4_to_decimal(\"10.0.0.256\"),\n            Err(Ipv4Error::InvalidOctet(256))\n        );\n    }\n\n    #[test]\n    fn test_decimal_to_ipv4_valid() {\n        assert_eq!(decimal_to_ipv4(3232235521).unwrap(), \"192.168.0.1\");\n        assert_eq!(decimal_to_ipv4(167772415).unwrap(), \"10.0.0.255\");\n        assert_eq!(decimal_to_ipv4(0).unwrap(), \"0.0.0.0\");\n        assert_eq!(decimal_to_ipv4(4294967295).unwrap(), \"255.255.255.255\");\n        assert_eq!(decimal_to_ipv4(134744072).unwrap(), \"8.8.8.8\");\n        assert_eq!(decimal_to_ipv4(2886794752).unwrap(), \"172.16.254.0\");\n    }\n\n    #[test]\n    fn test_round_trip_conversion() {\n        let test_addresses = vec![\n            \"192.168.0.1\",\n            \"10.0.0.255\",\n            \"172.16.254.1\",\n            \"8.8.8.8\",\n            \"255.255.255.255\",\n            \"0.0.0.0\",\n            \"127.0.0.1\",\n            \"1.2.3.4\",\n        ];\n\n        for addr in test_addresses {\n            let decimal = ipv4_to_decimal(addr).unwrap();\n            let result = decimal_to_ipv4(decimal).unwrap();\n            assert_eq!(addr, result, \"Round trip failed for {addr}\");\n        }\n    }\n\n    #[test]\n    fn test_both_methods_agree() {\n        let test_addresses = vec![\n            \"192.168.0.1\",\n            \"10.0.0.255\",\n            \"172.16.254.1\",\n            \"8.8.8.8\",\n            \"255.255.255.255\",\n            \"0.0.0.0\",\n        ];\n\n        for addr in test_addresses {\n            let result1 = ipv4_to_decimal(addr).unwrap();\n            let result2 = alt_ipv4_to_decimal(addr).unwrap();\n            assert_eq!(result1, result2, \"Methods disagree for address: {addr}\");\n        }\n    }\n\n    #[test]\n    fn test_edge_cases() {\n        // All zeros\n        assert_eq!(ipv4_to_decimal(\"0.0.0.0\").unwrap(), 0);\n        assert_eq!(decimal_to_ipv4(0).unwrap(), \"0.0.0.0\");\n\n        // All 255s (max value)\n        assert_eq!(ipv4_to_decimal(\"255.255.255.255\").unwrap(), 4294967295);\n        assert_eq!(decimal_to_ipv4(4294967295).unwrap(), \"255.255.255.255\");\n\n        // Common private ranges\n        assert_eq!(ipv4_to_decimal(\"10.0.0.0\").unwrap(), 167772160);\n        assert_eq!(ipv4_to_decimal(\"172.16.0.0\").unwrap(), 2886729728);\n        assert_eq!(ipv4_to_decimal(\"192.168.0.0\").unwrap(), 3232235520);\n    }\n}\n"
  },
  {
    "path": "src/conversions/length_conversion.rs",
    "content": "/// Author : https://github.com/ali77gh\n/// Conversion of length units.\n///\n/// Available Units:\n/// -> Wikipedia reference: https://en.wikipedia.org/wiki/Millimeter\n/// -> Wikipedia reference: https://en.wikipedia.org/wiki/Centimeter\n/// -> Wikipedia reference: https://en.wikipedia.org/wiki/Meter\n/// -> Wikipedia reference: https://en.wikipedia.org/wiki/Kilometer\n/// -> Wikipedia reference: https://en.wikipedia.org/wiki/Inch\n/// -> Wikipedia reference: https://en.wikipedia.org/wiki/Foot\n/// -> Wikipedia reference: https://en.wikipedia.org/wiki/Yard\n/// -> Wikipedia reference: https://en.wikipedia.org/wiki/Mile\n\n#[derive(Clone, Copy, PartialEq, Eq, Hash)]\npub enum LengthUnit {\n    Millimeter,\n    Centimeter,\n    Meter,\n    Kilometer,\n    Inch,\n    Foot,\n    Yard,\n    Mile,\n}\n\nfn unit_to_meter_multiplier(from: LengthUnit) -> f64 {\n    match from {\n        LengthUnit::Millimeter => 0.001,\n        LengthUnit::Centimeter => 0.01,\n        LengthUnit::Meter => 1.0,\n        LengthUnit::Kilometer => 1000.0,\n        LengthUnit::Inch => 0.0254,\n        LengthUnit::Foot => 0.3048,\n        LengthUnit::Yard => 0.9144,\n        LengthUnit::Mile => 1609.34,\n    }\n}\n\nfn unit_to_meter(input: f64, from: LengthUnit) -> f64 {\n    input * unit_to_meter_multiplier(from)\n}\n\nfn meter_to_unit(input: f64, to: LengthUnit) -> f64 {\n    input / unit_to_meter_multiplier(to)\n}\n\n/// This function will convert a value in unit of [from] to value in unit of [to]\n/// by first converting it to meter and than convert it to destination unit\npub fn length_conversion(input: f64, from: LengthUnit, to: LengthUnit) -> f64 {\n    meter_to_unit(unit_to_meter(input, from), to)\n}\n\n#[cfg(test)]\nmod length_conversion_tests {\n    use std::collections::HashMap;\n\n    use super::LengthUnit::*;\n    use super::*;\n\n    #[test]\n    fn zero_to_zero() {\n        let units = vec![\n            Millimeter, Centimeter, Meter, Kilometer, Inch, Foot, Yard, Mile,\n        ];\n\n        for u1 in units.clone() {\n            for u2 in units.clone() {\n                assert_eq!(length_conversion(0f64, u1, u2), 0f64);\n            }\n        }\n    }\n\n    #[test]\n    fn length_of_one_meter() {\n        let meter_in_different_units = HashMap::from([\n            (Millimeter, 1000f64),\n            (Centimeter, 100f64),\n            (Kilometer, 0.001f64),\n            (Inch, 39.37007874015748f64),\n            (Foot, 3.280839895013123f64),\n            (Yard, 1.0936132983377078f64),\n            (Mile, 0.0006213727366498068f64),\n        ]);\n        for (input_unit, input_value) in &meter_in_different_units {\n            for (target_unit, target_value) in &meter_in_different_units {\n                assert!(\n                    num_traits::abs(\n                        length_conversion(*input_value, *input_unit, *target_unit) - *target_value\n                    ) < 0.0000001\n                );\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/conversions/mod.rs",
    "content": "mod binary_to_decimal;\nmod binary_to_hexadecimal;\nmod binary_to_octal;\nmod decimal_to_binary;\nmod decimal_to_hexadecimal;\nmod decimal_to_octal;\nmod energy;\nmod hexadecimal_to_binary;\nmod hexadecimal_to_decimal;\nmod hexadecimal_to_octal;\nmod ipv4_conversion;\nmod length_conversion;\nmod octal_to_binary;\nmod octal_to_decimal;\nmod octal_to_hexadecimal;\nmod order_of_magnitude_conversion;\nmod pressure;\nmod rectangular_to_polar;\nmod rgb_cmyk_conversion;\nmod rgb_hsv_conversion;\nmod roman_numerals;\nmod speed;\nmod temperature;\nmod time;\nmod volume;\nmod weight;\n\npub use self::binary_to_decimal::binary_to_decimal;\npub use self::binary_to_hexadecimal::binary_to_hexadecimal;\npub use self::binary_to_octal::binary_to_octal;\npub use self::decimal_to_binary::decimal_to_binary;\npub use self::decimal_to_hexadecimal::decimal_to_hexadecimal;\npub use self::decimal_to_octal::decimal_to_octal;\npub use self::energy::{convert_energy, EnergyUnit};\npub use self::hexadecimal_to_binary::hexadecimal_to_binary;\npub use self::hexadecimal_to_decimal::hexadecimal_to_decimal;\npub use self::hexadecimal_to_octal::hexadecimal_to_octal;\npub use self::ipv4_conversion::{alt_ipv4_to_decimal, decimal_to_ipv4, ipv4_to_decimal, Ipv4Error};\npub use self::length_conversion::length_conversion;\npub use self::octal_to_binary::octal_to_binary;\npub use self::octal_to_decimal::octal_to_decimal;\npub use self::octal_to_hexadecimal::octal_to_hexadecimal;\npub use self::order_of_magnitude_conversion::{\n    convert_metric_length, metric_length_conversion, MetricLengthUnit,\n};\npub use self::pressure::{convert_pressure, PressureUnit};\npub use self::rectangular_to_polar::rectangular_to_polar;\npub use self::rgb_cmyk_conversion::rgb_to_cmyk;\npub use self::rgb_hsv_conversion::{hsv_to_rgb, rgb_to_hsv, ColorError, Hsv, Rgb};\npub use self::roman_numerals::{int_to_roman, roman_to_int};\npub use self::speed::{convert_speed, SpeedUnit};\npub use self::temperature::{convert_temperature, TemperatureUnit};\npub use self::time::convert_time;\npub use self::volume::{convert_volume, VolumeUnit};\npub use self::weight::{convert_weight, WeightUnit};\n"
  },
  {
    "path": "src/conversions/octal_to_binary.rs",
    "content": "// Author : cyrixninja\n// Octal to Binary Converter : Converts Octal to Binary\n// Wikipedia References  : 1. https://en.wikipedia.org/wiki/Octal\n//                         2. https://en.wikipedia.org/wiki/Binary_number\n\npub fn octal_to_binary(octal_str: &str) -> Result<String, &'static str> {\n    let octal_str = octal_str.trim();\n\n    if octal_str.is_empty() {\n        return Err(\"Empty\");\n    }\n\n    if !octal_str.chars().all(|c| ('0'..'7').contains(&c)) {\n        return Err(\"Non-octal Value\");\n    }\n\n    // Convert octal to binary\n    let binary = octal_str\n        .chars()\n        .map(|c| match c {\n            '0' => \"000\",\n            '1' => \"001\",\n            '2' => \"010\",\n            '3' => \"011\",\n            '4' => \"100\",\n            '5' => \"101\",\n            '6' => \"110\",\n            '7' => \"111\",\n            _ => unreachable!(),\n        })\n        .collect::<String>();\n\n    Ok(binary)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_empty_string() {\n        let input = \"\";\n        let expected = Err(\"Empty\");\n        assert_eq!(octal_to_binary(input), expected);\n    }\n\n    #[test]\n    fn test_invalid_octal() {\n        let input = \"89\";\n        let expected = Err(\"Non-octal Value\");\n        assert_eq!(octal_to_binary(input), expected);\n    }\n\n    #[test]\n    fn test_valid_octal() {\n        let input = \"123\";\n        let expected = Ok(\"001010011\".to_string());\n        assert_eq!(octal_to_binary(input), expected);\n    }\n}\n"
  },
  {
    "path": "src/conversions/octal_to_decimal.rs",
    "content": "// Author: cyrixninja\n// Octal to Decimal Converter: Converts Octal to Decimal\n// Wikipedia References:\n// 1. https://en.wikipedia.org/wiki/Octal\n// 2. https://en.wikipedia.org/wiki/Decimal\n\npub fn octal_to_decimal(octal_str: &str) -> Result<u64, &'static str> {\n    let octal_str = octal_str.trim();\n\n    if octal_str.is_empty() {\n        return Err(\"Empty\");\n    }\n\n    if !octal_str.chars().all(|c| ('0'..='7').contains(&c)) {\n        return Err(\"Non-octal Value\");\n    }\n\n    // Convert octal to decimal and directly return the Result\n    u64::from_str_radix(octal_str, 8).map_err(|_| \"Conversion error\")\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_empty_string() {\n        let input = \"\";\n        let expected = Err(\"Empty\");\n        assert_eq!(octal_to_decimal(input), expected);\n    }\n\n    #[test]\n    fn test_invalid_octal() {\n        let input = \"89\";\n        let expected = Err(\"Non-octal Value\");\n        assert_eq!(octal_to_decimal(input), expected);\n    }\n\n    #[test]\n    fn test_valid_octal() {\n        let input = \"123\";\n        let expected = Ok(83);\n        assert_eq!(octal_to_decimal(input), expected);\n    }\n\n    #[test]\n    fn test_valid_octal2() {\n        let input = \"1234\";\n        let expected = Ok(668);\n        assert_eq!(octal_to_decimal(input), expected);\n    }\n\n    #[test]\n    fn test_valid_octal3() {\n        let input = \"12345\";\n        let expected = Ok(5349);\n        assert_eq!(octal_to_decimal(input), expected);\n    }\n}\n"
  },
  {
    "path": "src/conversions/octal_to_hexadecimal.rs",
    "content": "// Author: NithinU2802\n// Octal to Hexadecimal Converter: Converts Octal to Hexadecimal\n// Wikipedia References:\n// 1. https://en.wikipedia.org/wiki/Octal\n// 2. https://en.wikipedia.org/wiki/Hexadecimal\n\npub fn octal_to_hexadecimal(octal_str: &str) -> Result<String, &'static str> {\n    let octal_str = octal_str.trim();\n\n    if octal_str.is_empty() {\n        return Err(\"Empty string\");\n    }\n\n    // Validate octal string\n    if !octal_str.chars().all(|c| ('0'..='7').contains(&c)) {\n        return Err(\"Invalid octal string\");\n    }\n\n    // Convert octal to decimal first\n    let decimal = u64::from_str_radix(octal_str, 8).map_err(|_| \"Conversion error\")?;\n\n    // Special case for zero\n    if decimal == 0 {\n        return Ok(\"0\".to_string());\n    }\n\n    // Convert decimal to hexadecimal\n    Ok(format!(\"{decimal:X}\"))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_octal_to_hexadecimal() {\n        assert_eq!(octal_to_hexadecimal(\"12\"), Ok(\"A\".to_string()));\n        assert_eq!(octal_to_hexadecimal(\"377\"), Ok(\"FF\".to_string()));\n        assert_eq!(octal_to_hexadecimal(\"144\"), Ok(\"64\".to_string()));\n        assert_eq!(octal_to_hexadecimal(\"0\"), Ok(\"0\".to_string()));\n    }\n\n    #[test]\n    fn test_invalid_input() {\n        assert_eq!(octal_to_hexadecimal(\"\"), Err(\"Empty string\"));\n        assert_eq!(octal_to_hexadecimal(\"8\"), Err(\"Invalid octal string\"));\n        assert_eq!(octal_to_hexadecimal(\"9\"), Err(\"Invalid octal string\"));\n        assert_eq!(octal_to_hexadecimal(\"ABC\"), Err(\"Invalid octal string\"));\n    }\n}\n"
  },
  {
    "path": "src/conversions/order_of_magnitude_conversion.rs",
    "content": "//! Length Unit Conversion\n//!\n//! This module provides conversion between metric length units ranging from\n//! meters to yottameters (10^24 meters).\n//!\n//! Available units: Meter, Kilometer, Megameter, Gigameter, Terameter,\n//! Petameter, Exameter, Zettameter, Yottameter\n//!\n//! ## Spelling Convention\n//!\n//! This module uses **American spellings** (meter, kilometer, etc.) for all\n//! official API elements including enum variants and documentation, following\n//! standard programming conventions and SI guidelines.\n//!\n//! However, the `FromStr` implementation **accepts both American and British spellings**\n//! for maximum compatibility:\n//! - American: \"meter\", \"kilometer\", \"megameter\", etc.\n//! - British: \"metre\", \"kilometre\", \"megametre\", etc.\n//!\n//! ```\n//! use the_algorithms_rust::conversions::MetricLengthUnit;\n//! use std::str::FromStr;\n//!\n//! // Both spellings work!\n//! let american: MetricLengthUnit = \"megameter\".parse().unwrap();\n//! let british: MetricLengthUnit = \"megametre\".parse().unwrap();\n//! assert_eq!(american, british); // Same enum variant\n//! ```\n//!\n//! # References\n//!\n//! - [Meter - Wikipedia](https://en.wikipedia.org/wiki/Meter)\n//! - [Kilometer - Wikipedia](https://en.wikipedia.org/wiki/Kilometer)\n//! - [Orders of Magnitude (Length) - Wikipedia](https://en.wikipedia.org/wiki/Orders_of_magnitude_(length))\n\nuse std::fmt;\nuse std::str::FromStr;\n\n/// Represents different metric length units.\n///\n/// Each variant corresponds to a specific power of 10 relative to the base unit (meter).\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum MetricLengthUnit {\n    /// Meter (m) - base unit, 10^0 meters\n    Meter,\n    /// Kilometer (km) - 10^3 meters\n    Kilometer,\n    /// Megameter (Mm) - 10^6 meters\n    Megameter,\n    /// Gigameter (Gm) - 10^9 meters\n    Gigameter,\n    /// Terameter (Tm) - 10^12 meters\n    Terameter,\n    /// Petameter (Pm) - 10^15 meters\n    Petameter,\n    /// Exameter (Em) - 10^18 meters\n    Exameter,\n    /// Zettameter (Zm) - 10^21 meters\n    Zettameter,\n    /// Yottameter (Ym) - 10^24 meters\n    Yottameter,\n}\n\nimpl MetricLengthUnit {\n    /// Returns the exponent (power of 10) for this unit relative to meters.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use the_algorithms_rust::conversions::MetricLengthUnit;\n    ///\n    /// assert_eq!(MetricLengthUnit::Meter.exponent(), 0);\n    /// assert_eq!(MetricLengthUnit::Kilometer.exponent(), 3);\n    /// assert_eq!(MetricLengthUnit::Megameter.exponent(), 6);\n    /// ```\n    pub fn exponent(&self) -> i32 {\n        match self {\n            MetricLengthUnit::Meter => 0,\n            MetricLengthUnit::Kilometer => 3,\n            MetricLengthUnit::Megameter => 6,\n            MetricLengthUnit::Gigameter => 9,\n            MetricLengthUnit::Terameter => 12,\n            MetricLengthUnit::Petameter => 15,\n            MetricLengthUnit::Exameter => 18,\n            MetricLengthUnit::Zettameter => 21,\n            MetricLengthUnit::Yottameter => 24,\n        }\n    }\n\n    /// Returns the standard abbreviation for this unit.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use the_algorithms_rust::conversions::MetricLengthUnit;\n    ///\n    /// assert_eq!(MetricLengthUnit::Meter.symbol(), \"m\");\n    /// assert_eq!(MetricLengthUnit::Kilometer.symbol(), \"km\");\n    /// ```\n    pub fn symbol(&self) -> &'static str {\n        match self {\n            MetricLengthUnit::Meter => \"m\",\n            MetricLengthUnit::Kilometer => \"km\",\n            MetricLengthUnit::Megameter => \"Mm\",\n            MetricLengthUnit::Gigameter => \"Gm\",\n            MetricLengthUnit::Terameter => \"Tm\",\n            MetricLengthUnit::Petameter => \"Pm\",\n            MetricLengthUnit::Exameter => \"Em\",\n            MetricLengthUnit::Zettameter => \"Zm\",\n            MetricLengthUnit::Yottameter => \"Ym\",\n        }\n    }\n}\n\nimpl FromStr for MetricLengthUnit {\n    type Err = String;\n\n    /// Parses a unit from a string (case-insensitive, handles plurals).\n    ///\n    /// Accepts both full names (e.g., \"meter\", \"meters\") and symbols (e.g., \"m\", \"km\").\n    /// **Accepts both American and British spellings** (e.g., \"megameter\" and \"megametre\").\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use the_algorithms_rust::conversions::MetricLengthUnit;\n    /// use std::str::FromStr;\n    ///\n    /// // American spellings (official)\n    /// assert_eq!(MetricLengthUnit::from_str(\"meter\").unwrap(), MetricLengthUnit::Meter);\n    /// assert_eq!(MetricLengthUnit::from_str(\"megameter\").unwrap(), MetricLengthUnit::Megameter);\n    ///\n    /// // British spellings (also accepted)\n    /// assert_eq!(MetricLengthUnit::from_str(\"metre\").unwrap(), MetricLengthUnit::Meter);\n    /// assert_eq!(MetricLengthUnit::from_str(\"megametre\").unwrap(), MetricLengthUnit::Megameter);\n    ///\n    /// // Symbols and case-insensitive\n    /// assert_eq!(MetricLengthUnit::from_str(\"km\").unwrap(), MetricLengthUnit::Kilometer);\n    /// assert_eq!(MetricLengthUnit::from_str(\"METERS\").unwrap(), MetricLengthUnit::Meter);\n    /// ```\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        // Sanitize: lowercase and remove trailing 's'\n        let sanitized = s.to_lowercase().trim_end_matches('s').to_string();\n\n        match sanitized.as_str() {\n            \"meter\" | \"metre\" | \"m\" => Ok(MetricLengthUnit::Meter),\n            \"kilometer\" | \"kilometre\" | \"km\" => Ok(MetricLengthUnit::Kilometer),\n            \"megameter\" | \"megametre\" | \"mm\" => Ok(MetricLengthUnit::Megameter),\n            \"gigameter\" | \"gigametre\" | \"gm\" => Ok(MetricLengthUnit::Gigameter),\n            \"terameter\" | \"terametre\" | \"tm\" => Ok(MetricLengthUnit::Terameter),\n            \"petameter\" | \"petametre\" | \"pm\" => Ok(MetricLengthUnit::Petameter),\n            \"exameter\" | \"exametre\" | \"em\" => Ok(MetricLengthUnit::Exameter),\n            \"zettameter\" | \"zettametre\" | \"zm\" => Ok(MetricLengthUnit::Zettameter),\n            \"yottameter\" | \"yottametre\" | \"ym\" => Ok(MetricLengthUnit::Yottameter),\n            _ => Err(format!(\n                \"Invalid unit: '{s}'. Valid units are: m, km, Mm, Gm, Tm, Pm, Em, Zm, Ym\"\n            )),\n        }\n    }\n}\n\nimpl fmt::Display for MetricLengthUnit {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.symbol())\n    }\n}\n\n/// Converts a length value from one unit to another.\n///\n/// # Arguments\n///\n/// * `value` - The numeric value to convert\n/// * `from` - The unit to convert from\n/// * `to` - The unit to convert to\n///\n/// # Returns\n///\n/// The converted value in the target unit\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::conversions::{MetricLengthUnit, convert_metric_length};\n///\n/// let result = convert_metric_length(1.0, MetricLengthUnit::Meter, MetricLengthUnit::Kilometer);\n/// assert_eq!(result, 0.001);\n///\n/// let result = convert_metric_length(1.0, MetricLengthUnit::Kilometer, MetricLengthUnit::Meter);\n/// assert_eq!(result, 1000.0);\n/// ```\npub fn convert_metric_length(value: f64, from: MetricLengthUnit, to: MetricLengthUnit) -> f64 {\n    let from_exp = from.exponent();\n    let to_exp = to.exponent();\n    let exponent = from_exp - to_exp;\n\n    value * 10_f64.powi(exponent)\n}\n\n/// Converts a length value from one unit to another using string unit names.\n///\n/// This function accepts both full unit names and abbreviations, and is case-insensitive.\n/// It also handles plural forms (e.g., \"meters\" and \"meter\" both work).\n///\n/// # Arguments\n///\n/// * `value` - The numeric value to convert\n/// * `from_type` - The unit to convert from (as a string)\n/// * `to_type` - The unit to convert to (as a string)\n///\n/// # Returns\n///\n/// `Ok(f64)` with the converted value, or `Err(String)` if either unit is invalid\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::conversions::metric_length_conversion;\n///\n/// let result = metric_length_conversion(1.0, \"meter\", \"kilometer\").unwrap();\n/// assert_eq!(result, 0.001);\n///\n/// let result = metric_length_conversion(1.0, \"km\", \"m\").unwrap();\n/// assert_eq!(result, 1000.0);\n///\n/// // Case insensitive and handles plurals\n/// let result = metric_length_conversion(5.0, \"METERS\", \"kilometers\").unwrap();\n/// assert_eq!(result, 0.005);\n///\n/// // Invalid unit returns error\n/// assert!(metric_length_conversion(1.0, \"wrongUnit\", \"meter\").is_err());\n/// ```\npub fn metric_length_conversion(value: f64, from_type: &str, to_type: &str) -> Result<f64, String> {\n    let from_unit = MetricLengthUnit::from_str(from_type).map_err(|_| {\n        format!(\n            \"Invalid 'from_type' value: '{from_type}'.\\nConversion abbreviations are: m, km, Mm, Gm, Tm, Pm, Em, Zm, Ym\"\n        )\n    })?;\n\n    let to_unit = MetricLengthUnit::from_str(to_type).map_err(|_| {\n        format!(\n            \"Invalid 'to_type' value: '{to_type}'.\\nConversion abbreviations are: m, km, Mm, Gm, Tm, Pm, Em, Zm, Ym\"\n        )\n    })?;\n\n    Ok(convert_metric_length(value, from_unit, to_unit))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_unit_exponents() {\n        assert_eq!(MetricLengthUnit::Meter.exponent(), 0);\n        assert_eq!(MetricLengthUnit::Kilometer.exponent(), 3);\n        assert_eq!(MetricLengthUnit::Megameter.exponent(), 6);\n        assert_eq!(MetricLengthUnit::Gigameter.exponent(), 9);\n        assert_eq!(MetricLengthUnit::Terameter.exponent(), 12);\n        assert_eq!(MetricLengthUnit::Petameter.exponent(), 15);\n        assert_eq!(MetricLengthUnit::Exameter.exponent(), 18);\n        assert_eq!(MetricLengthUnit::Zettameter.exponent(), 21);\n        assert_eq!(MetricLengthUnit::Yottameter.exponent(), 24);\n    }\n\n    #[test]\n    fn test_unit_symbols() {\n        assert_eq!(MetricLengthUnit::Meter.symbol(), \"m\");\n        assert_eq!(MetricLengthUnit::Kilometer.symbol(), \"km\");\n        assert_eq!(MetricLengthUnit::Megameter.symbol(), \"Mm\");\n        assert_eq!(MetricLengthUnit::Gigameter.symbol(), \"Gm\");\n        assert_eq!(MetricLengthUnit::Terameter.symbol(), \"Tm\");\n        assert_eq!(MetricLengthUnit::Petameter.symbol(), \"Pm\");\n        assert_eq!(MetricLengthUnit::Exameter.symbol(), \"Em\");\n        assert_eq!(MetricLengthUnit::Zettameter.symbol(), \"Zm\");\n        assert_eq!(MetricLengthUnit::Yottameter.symbol(), \"Ym\");\n    }\n\n    #[test]\n    fn test_from_str_full_names() {\n        assert_eq!(\n            MetricLengthUnit::from_str(\"meter\").unwrap(),\n            MetricLengthUnit::Meter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"kilometer\").unwrap(),\n            MetricLengthUnit::Kilometer\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"megameter\").unwrap(),\n            MetricLengthUnit::Megameter\n        );\n    }\n\n    #[test]\n    fn test_from_str_symbols() {\n        assert_eq!(\n            MetricLengthUnit::from_str(\"m\").unwrap(),\n            MetricLengthUnit::Meter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"km\").unwrap(),\n            MetricLengthUnit::Kilometer\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"Mm\").unwrap(),\n            MetricLengthUnit::Megameter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"Gm\").unwrap(),\n            MetricLengthUnit::Gigameter\n        );\n    }\n\n    #[test]\n    fn test_from_str_case_insensitive() {\n        assert_eq!(\n            MetricLengthUnit::from_str(\"METER\").unwrap(),\n            MetricLengthUnit::Meter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"KiLoMeTeR\").unwrap(),\n            MetricLengthUnit::Kilometer\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"KM\").unwrap(),\n            MetricLengthUnit::Kilometer\n        );\n    }\n\n    #[test]\n    fn test_from_str_plurals() {\n        assert_eq!(\n            MetricLengthUnit::from_str(\"meters\").unwrap(),\n            MetricLengthUnit::Meter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"kilometers\").unwrap(),\n            MetricLengthUnit::Kilometer\n        );\n    }\n\n    #[test]\n    fn test_from_str_british_spellings() {\n        // Test that British spellings work (uses 're' instead of 'er')\n        assert_eq!(\n            MetricLengthUnit::from_str(\"metre\").unwrap(),\n            MetricLengthUnit::Meter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"kilometre\").unwrap(),\n            MetricLengthUnit::Kilometer\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"megametre\").unwrap(),\n            MetricLengthUnit::Megameter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"gigametre\").unwrap(),\n            MetricLengthUnit::Gigameter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"terametre\").unwrap(),\n            MetricLengthUnit::Terameter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"petametre\").unwrap(),\n            MetricLengthUnit::Petameter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"exametre\").unwrap(),\n            MetricLengthUnit::Exameter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"zettametre\").unwrap(),\n            MetricLengthUnit::Zettameter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"yottametre\").unwrap(),\n            MetricLengthUnit::Yottameter\n        );\n\n        // British spellings with plurals\n        assert_eq!(\n            MetricLengthUnit::from_str(\"metres\").unwrap(),\n            MetricLengthUnit::Meter\n        );\n        assert_eq!(\n            MetricLengthUnit::from_str(\"kilometres\").unwrap(),\n            MetricLengthUnit::Kilometer\n        );\n    }\n\n    #[test]\n    fn test_from_str_american_and_british_equivalent() {\n        // Verify American and British spellings parse to the same enum variant\n        let american = MetricLengthUnit::from_str(\"megameter\").unwrap();\n        let british = MetricLengthUnit::from_str(\"megametre\").unwrap();\n        assert_eq!(american, british);\n        assert_eq!(american, MetricLengthUnit::Megameter);\n    }\n\n    #[test]\n    fn test_from_str_invalid() {\n        assert!(MetricLengthUnit::from_str(\"wrongUnit\").is_err());\n        assert!(MetricLengthUnit::from_str(\"inch\").is_err());\n        assert!(MetricLengthUnit::from_str(\"\").is_err());\n    }\n\n    #[test]\n    fn test_convert_length_meter_to_kilometer() {\n        let result =\n            convert_metric_length(1.0, MetricLengthUnit::Meter, MetricLengthUnit::Kilometer);\n        assert_eq!(result, 0.001);\n    }\n\n    #[test]\n    fn test_convert_length_meter_to_megameter() {\n        let result =\n            convert_metric_length(1.0, MetricLengthUnit::Meter, MetricLengthUnit::Megameter);\n        assert_eq!(result, 1e-6);\n    }\n\n    #[test]\n    fn test_convert_length_gigameter_to_meter() {\n        let result =\n            convert_metric_length(1.0, MetricLengthUnit::Gigameter, MetricLengthUnit::Meter);\n        assert_eq!(result, 1_000_000_000.0);\n    }\n\n    #[test]\n    fn test_convert_length_gigameter_to_terameter() {\n        let result = convert_metric_length(\n            1.0,\n            MetricLengthUnit::Gigameter,\n            MetricLengthUnit::Terameter,\n        );\n        assert_eq!(result, 0.001);\n    }\n\n    #[test]\n    fn test_convert_length_petameter_to_terameter() {\n        let result = convert_metric_length(\n            1.0,\n            MetricLengthUnit::Petameter,\n            MetricLengthUnit::Terameter,\n        );\n        assert_eq!(result, 1000.0);\n    }\n\n    #[test]\n    fn test_convert_length_petameter_to_exameter() {\n        let result =\n            convert_metric_length(1.0, MetricLengthUnit::Petameter, MetricLengthUnit::Exameter);\n        assert_eq!(result, 0.001);\n    }\n\n    #[test]\n    fn test_convert_length_terameter_to_zettameter() {\n        let result = convert_metric_length(\n            1.0,\n            MetricLengthUnit::Terameter,\n            MetricLengthUnit::Zettameter,\n        );\n        assert_eq!(result, 1e-9);\n    }\n\n    #[test]\n    fn test_convert_length_yottameter_to_zettameter() {\n        let result = convert_metric_length(\n            1.0,\n            MetricLengthUnit::Yottameter,\n            MetricLengthUnit::Zettameter,\n        );\n        assert_eq!(result, 1000.0);\n    }\n\n    #[test]\n    fn test_convert_length_same_unit() {\n        let result = convert_metric_length(\n            42.0,\n            MetricLengthUnit::Kilometer,\n            MetricLengthUnit::Kilometer,\n        );\n        assert_eq!(result, 42.0);\n    }\n\n    #[test]\n    fn test_length_conversion_str_basic() {\n        let result = metric_length_conversion(1.0, \"meter\", \"kilometer\").unwrap();\n        assert_eq!(result, 0.001);\n    }\n\n    #[test]\n    fn test_length_conversion_str_symbols() {\n        let result = metric_length_conversion(1.0, \"m\", \"km\").unwrap();\n        assert_eq!(result, 0.001);\n    }\n\n    #[test]\n    fn test_length_conversion_str_case_insensitive() {\n        let result = metric_length_conversion(1.0, \"METER\", \"KILOMETER\").unwrap();\n        assert_eq!(result, 0.001);\n    }\n\n    #[test]\n    fn test_length_conversion_str_plurals() {\n        let result = metric_length_conversion(5.0, \"meters\", \"kilometers\").unwrap();\n        assert_eq!(result, 0.005);\n    }\n\n    #[test]\n    fn test_length_conversion_str_british_spellings() {\n        // Test that British spellings work in string-based API\n        let result = metric_length_conversion(1.0, \"metre\", \"kilometre\").unwrap();\n        assert_eq!(result, 0.001);\n\n        let result = metric_length_conversion(1000.0, \"kilometre\", \"metre\").unwrap();\n        assert_eq!(result, 1_000_000.0);\n\n        let result = metric_length_conversion(1.0, \"gigametre\", \"megametre\").unwrap();\n        assert_eq!(result, 1000.0);\n\n        // Mix American and British\n        let result = metric_length_conversion(1.0, \"meter\", \"kilometre\").unwrap();\n        assert_eq!(result, 0.001);\n\n        let result = metric_length_conversion(1.0, \"megametre\", \"meter\").unwrap();\n        assert_eq!(result, 1_000_000.0);\n    }\n\n    #[test]\n    fn test_length_conversion_str_invalid_from() {\n        let result = metric_length_conversion(1.0, \"wrongUnit\", \"meter\");\n        assert!(result.is_err());\n        assert!(result.unwrap_err().contains(\"Invalid 'from_type'\"));\n    }\n\n    #[test]\n    fn test_length_conversion_str_invalid_to() {\n        let result = metric_length_conversion(1.0, \"meter\", \"inch\");\n        assert!(result.is_err());\n        assert!(result.unwrap_err().contains(\"Invalid 'to_type'\"));\n    }\n\n    #[test]\n    fn test_length_conversion_str_large_values() {\n        let result = metric_length_conversion(1000.0, \"km\", \"m\").unwrap();\n        assert_eq!(result, 1_000_000.0);\n    }\n\n    #[test]\n    fn test_length_conversion_str_small_values() {\n        let result = metric_length_conversion(0.001, \"m\", \"km\").unwrap();\n        assert_eq!(result, 0.000001);\n    }\n\n    #[test]\n    fn test_all_conversions_reversible() {\n        let units = [\n            MetricLengthUnit::Meter,\n            MetricLengthUnit::Kilometer,\n            MetricLengthUnit::Megameter,\n            MetricLengthUnit::Gigameter,\n            MetricLengthUnit::Terameter,\n        ];\n\n        for &from in &units {\n            for &to in &units {\n                let forward = convert_metric_length(100.0, from, to);\n                let backward = convert_metric_length(forward, to, from);\n                assert!((backward - 100.0).abs() < 1e-9, \"Conversion not reversible\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/conversions/pressure.rs",
    "content": "//! Conversion of pressure units.\n//!\n//! This module provides conversion between various pressure units including:\n//! Pascal (Pa, kPa, MPa, GPa), Bar (bar, mbar), Atmosphere (atm, at, ata),\n//! Torr (Torr, mTorr), PSI (psi, ksi), Barad (Ba), Pièze (pz),\n//! and manometric units (mmHg, cmHg, inHg, mmH2O, cmH2O, inH2O, msw, fsw).\n//!\n//! # References\n//! - [Units of Pressure](https://msestudent.com/what-are-the-units-of-pressure/)\n\nuse std::fmt;\nuse std::str::FromStr;\n\n/// Trait for types that can be converted into a PressureUnit\npub trait IntoPressureUnit {\n    fn into_pressure_unit(self) -> Result<PressureUnit, String>;\n}\n\nimpl IntoPressureUnit for PressureUnit {\n    fn into_pressure_unit(self) -> Result<PressureUnit, String> {\n        Ok(self)\n    }\n}\n\nimpl IntoPressureUnit for &str {\n    fn into_pressure_unit(self) -> Result<PressureUnit, String> {\n        PressureUnit::from_str(self)\n    }\n}\n\nimpl IntoPressureUnit for String {\n    fn into_pressure_unit(self) -> Result<PressureUnit, String> {\n        PressureUnit::from_str(&self)\n    }\n}\n\n/// Supported pressure units\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum PressureUnit {\n    // SI units (Pascal-based)\n    Pascal,\n    Kilopascal,\n    Megapascal,\n    Gigapascal,\n    Hectopascal,\n\n    // Atmosphere units\n    Atmosphere,\n    TechnicalAtmosphere,\n    TotalAtmosphere,\n\n    // Torr units\n    Torr,\n    Millitorr,\n\n    // Bar units\n    Bar,\n    Millibar,\n\n    // Imperial units\n    Psi,\n    Ksi,\n    OunceForcePerSquareInch,\n\n    // Other metric units\n    Barad,\n    Pieze,\n\n    // Manometric units\n    MillimeterMercury,\n    CentimeterMercury,\n    InchMercury,\n    MillimeterWater,\n    CentimeterWater,\n    InchWater,\n    MeterSeawater,\n    FootSeawater,\n}\n\nimpl fmt::Display for PressureUnit {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let s = match self {\n            Self::Pascal => \"Pa\",\n            Self::Kilopascal => \"kPa\",\n            Self::Megapascal => \"MPa\",\n            Self::Gigapascal => \"GPa\",\n            Self::Hectopascal => \"hPa\",\n            Self::Atmosphere => \"atm\",\n            Self::TechnicalAtmosphere => \"at\",\n            Self::TotalAtmosphere => \"ata\",\n            Self::Torr => \"Torr\",\n            Self::Millitorr => \"mTorr\",\n            Self::Bar => \"bar\",\n            Self::Millibar => \"mbar\",\n            Self::Psi => \"psi\",\n            Self::Ksi => \"ksi\",\n            Self::OunceForcePerSquareInch => \"ozf/in²\",\n            Self::Barad => \"Ba\",\n            Self::Pieze => \"pz\",\n            Self::MillimeterMercury => \"mmHg\",\n            Self::CentimeterMercury => \"cmHg\",\n            Self::InchMercury => \"inHg\",\n            Self::MillimeterWater => \"mmH₂O\",\n            Self::CentimeterWater => \"cmH₂O\",\n            Self::InchWater => \"inH₂O\",\n            Self::MeterSeawater => \"msw\",\n            Self::FootSeawater => \"fsw\",\n        };\n        write!(f, \"{s}\")\n    }\n}\n\nimpl PressureUnit {\n    /// Get the conversion factor to convert this unit to pascals\n    fn to_pascal_factor(self) -> f64 {\n        match self {\n            // SI units (Pascal-based)\n            Self::Pascal => 1.0,\n            Self::Kilopascal | Self::Pieze => 1_000.0,\n            Self::Megapascal => 1_000_000.0,\n            Self::Gigapascal => 1_000_000_000.0,\n            Self::Hectopascal | Self::Millibar => 100.0,\n\n            // Atmosphere units\n            Self::Atmosphere | Self::TotalAtmosphere => 101_325.0,\n            Self::TechnicalAtmosphere => 98_070.0,\n\n            // Torr units (1 atm = 760 Torr exactly)\n            Self::Torr | Self::MillimeterMercury => 101_325.0 / 760.0,\n            Self::Millitorr => 101_325.0 / 760_000.0,\n\n            // Bar units\n            Self::Bar => 100_000.0,\n\n            // Imperial units\n            Self::Psi => 6_894.757_293_168,\n            Self::Ksi => 6_894_757.293_168,\n            Self::OunceForcePerSquareInch => 430.922_330_823,\n\n            // Other metric units\n            Self::Barad => 0.1,\n\n            // Manometric units\n            Self::CentimeterMercury => 101_325.0 / 76.0,\n            Self::InchMercury => 3_386.389,\n            Self::MillimeterWater => 9.806_65,\n            Self::CentimeterWater => 98.0665,\n            Self::InchWater => 249.088_908_333,\n            Self::MeterSeawater => 10_000.0,\n            Self::FootSeawater => 3_048.0,\n        }\n    }\n\n    /// Get all supported units as strings\n    pub fn supported_units() -> Vec<&'static str> {\n        vec![\n            \"Pa\", \"kPa\", \"MPa\", \"GPa\", \"hPa\", \"atm\", \"at\", \"ata\", \"Torr\", \"mTorr\", \"bar\", \"mbar\",\n            \"psi\", \"ksi\", \"ozf/in²\", \"Ba\", \"pz\", \"mmHg\", \"cmHg\", \"inHg\", \"mmH₂O\", \"cmH₂O\", \"inH₂O\",\n            \"msw\", \"fsw\",\n        ]\n    }\n}\n\nimpl FromStr for PressureUnit {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let unit = match s.to_lowercase().as_str() {\n            \"pa\" | \"pascal\" => Self::Pascal,\n            \"kpa\" | \"kilopascal\" => Self::Kilopascal,\n            \"mpa\" | \"megapascal\" => Self::Megapascal,\n            \"gpa\" | \"gigapascal\" => Self::Gigapascal,\n            \"hpa\" | \"hectopascal\" => Self::Hectopascal,\n            \"atm\" | \"atmosphere\" => Self::Atmosphere,\n            \"at\" | \"technical_atmosphere\" | \"kgf/cm2\" => Self::TechnicalAtmosphere,\n            \"ata\" | \"total_atmosphere\" => Self::TotalAtmosphere,\n            \"torr\" => Self::Torr,\n            \"mtorr\" | \"millitorr\" => Self::Millitorr,\n            \"bar\" => Self::Bar,\n            \"mbar\" | \"millibar\" => Self::Millibar,\n            \"psi\" | \"lb/in2\" => Self::Psi,\n            \"ksi\" => Self::Ksi,\n            \"ozf/in2\" | \"ounce_force_per_square_inch\" => Self::OunceForcePerSquareInch,\n            \"ba\" | \"barad\" => Self::Barad,\n            \"pz\" | \"pieze\" => Self::Pieze,\n            \"mmhg\" | \"millimeter_mercury\" => Self::MillimeterMercury,\n            \"cmhg\" | \"centimeter_mercury\" => Self::CentimeterMercury,\n            \"inhg\" | \"inch_mercury\" => Self::InchMercury,\n            \"mmh2o\" | \"millimeter_water\" => Self::MillimeterWater,\n            \"cmh2o\" | \"centimeter_water\" => Self::CentimeterWater,\n            \"inh2o\" | \"inch_water\" => Self::InchWater,\n            \"msw\" | \"meter_seawater\" => Self::MeterSeawater,\n            \"fsw\" | \"foot_seawater\" => Self::FootSeawater,\n            _ => return Err(format!(\"Unknown pressure unit: {s}\")),\n        };\n        Ok(unit)\n    }\n}\n\n/// Convert pressure from one unit to another.\n///\n/// This function accepts both `PressureUnit` enums and string identifiers.\n///\n/// # Arguments\n///\n/// * `value` - The numerical value to convert\n/// * `from_unit` - The unit to convert from (can be a `PressureUnit` enum or a string)\n/// * `to_unit` - The unit to convert to (can be a `PressureUnit` enum or a string)\n///\n/// # Returns\n///\n/// The converted value, or an error if the unit is invalid\n///\n/// # Examples\n///\n/// Using enums (type-safe):\n/// ```ignore\n/// let result = convert_pressure(100.0, PressureUnit::Psi, PressureUnit::Kilopascal);\n/// ```\n///\n/// Using strings (convenient):\n/// ```ignore\n/// let result = convert_pressure(100.0, \"psi\", \"kpa\");\n/// ```\npub fn convert_pressure<F, T>(value: f64, from_unit: F, to_unit: T) -> Result<f64, String>\nwhere\n    F: IntoPressureUnit,\n    T: IntoPressureUnit,\n{\n    let from = from_unit.into_pressure_unit().map_err(|_| {\n        format!(\n            \"Invalid 'from_unit' value. Supported values are:\\n{}\",\n            PressureUnit::supported_units().join(\", \")\n        )\n    })?;\n\n    let to = to_unit.into_pressure_unit().map_err(|_| {\n        format!(\n            \"Invalid 'to_unit' value. Supported values are:\\n{}\",\n            PressureUnit::supported_units().join(\", \")\n        )\n    })?;\n\n    // Convert to pascals first, then to target unit\n    let pascals = value * from.to_pascal_factor();\n    Ok(pascals / to.to_pascal_factor())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    const EPSILON: f64 = 1e-3; // Increased tolerance for floating point comparisons\n\n    fn approx_eq(a: f64, b: f64) -> bool {\n        (a - b).abs() < EPSILON\n    }\n\n    #[test]\n    fn test_pressure_conversions() {\n        // Test basic conversions from Python original (using strings)\n        assert!(approx_eq(\n            convert_pressure(4.0, \"atm\", \"pascal\").unwrap(),\n            405_300.0\n        ));\n        assert!(approx_eq(\n            convert_pressure(1.0, \"pascal\", \"psi\").unwrap(),\n            0.000_145_037_738\n        ));\n        assert!(approx_eq(\n            convert_pressure(1.0, \"bar\", \"atm\").unwrap(),\n            0.986_923_266_716\n        ));\n        assert!(approx_eq(\n            convert_pressure(3.0, \"kilopascal\", \"bar\").unwrap(),\n            0.03\n        ));\n        assert!(approx_eq(\n            convert_pressure(2.0, \"megapascal\", \"psi\").unwrap(),\n            290.075_476\n        ));\n        assert!(approx_eq(\n            convert_pressure(4.0, \"psi\", \"torr\").unwrap(),\n            206.859_730\n        ));\n        assert!(approx_eq(\n            convert_pressure(1.0, \"inhg\", \"atm\").unwrap(),\n            0.033_421_052\n        ));\n        assert!(approx_eq(\n            convert_pressure(1.0, \"torr\", \"psi\").unwrap(),\n            0.019_336_775\n        ));\n\n        // Test using enums (type-safe)\n        assert!(approx_eq(\n            convert_pressure(1.0, PressureUnit::Atmosphere, PressureUnit::Pascal).unwrap(),\n            101_325.0\n        ));\n        assert!(approx_eq(\n            convert_pressure(100.0, PressureUnit::Psi, PressureUnit::Kilopascal).unwrap(),\n            689.475_729\n        ));\n\n        // Test mixed usage (enum and string)\n        assert!(approx_eq(\n            convert_pressure(1.0, PressureUnit::Bar, \"atm\").unwrap(),\n            0.986_923_266_716\n        ));\n        assert!(approx_eq(\n            convert_pressure(1.0, \"bar\", PressureUnit::Atmosphere).unwrap(),\n            0.986_923_266_716\n        ));\n\n        // Test invalid units\n        assert!(convert_pressure(4.0, \"wrongUnit\", \"atm\").is_err());\n        assert!(convert_pressure(4.0, \"atm\", \"wrongUnit\").is_err());\n\n        // Test atmospheric pressure conversions\n        assert!(approx_eq(\n            convert_pressure(1.0, \"atm\", \"pascal\").unwrap(),\n            101_325.0\n        ));\n        assert!(approx_eq(\n            convert_pressure(1.0, \"atm\", \"bar\").unwrap(),\n            1.01325\n        ));\n        assert!(approx_eq(\n            convert_pressure(1.0, \"atm\", \"torr\").unwrap(),\n            760.0\n        ));\n        assert!(approx_eq(\n            convert_pressure(1.0, \"atm\", \"psi\").unwrap(),\n            14.695_949\n        ));\n\n        // Test roundtrip conversion\n        let original = 100.0;\n        let converted = convert_pressure(original, \"psi\", \"kpa\").unwrap();\n        let back = convert_pressure(converted, \"kpa\", \"psi\").unwrap();\n        assert!(approx_eq(original, back));\n\n        // Test manometric units\n        assert!(approx_eq(\n            convert_pressure(760.0, \"mmhg\", \"atm\").unwrap(),\n            1.0\n        ));\n        assert!(approx_eq(\n            convert_pressure(1.0, \"mmh2o\", \"pascal\").unwrap(),\n            9.80665\n        ));\n        assert!(approx_eq(\n            convert_pressure(1.0, \"msw\", \"kpa\").unwrap(),\n            10.0\n        ));\n        assert!(approx_eq(\n            convert_pressure(1.0, \"fsw\", \"pascal\").unwrap(),\n            3_048.0\n        ));\n\n        // Test technical atmosphere\n        assert!(approx_eq(\n            convert_pressure(1.0, \"at\", \"atm\").unwrap(),\n            0.967_841_105\n        ));\n\n        // Test ksi conversion\n        assert!(approx_eq(\n            convert_pressure(1.0, \"ksi\", \"psi\").unwrap(),\n            1_000.0\n        ));\n\n        // Test gigapascal conversion\n        assert!(approx_eq(\n            convert_pressure(1.0, \"gpa\", \"mpa\").unwrap(),\n            1_000.0\n        ));\n\n        // Test hectopascal equals millibar\n        let hpa_to_pa = convert_pressure(1.0, \"hpa\", \"pa\").unwrap();\n        let mbar_to_pa = convert_pressure(1.0, \"mbar\", \"pa\").unwrap();\n        assert!(approx_eq(hpa_to_pa, mbar_to_pa));\n\n        // Test barad conversion\n        assert!(approx_eq(convert_pressure(1.0, \"ba\", \"pa\").unwrap(), 0.1));\n\n        // Test pieze conversion\n        assert!(approx_eq(convert_pressure(1.0, \"pz\", \"kpa\").unwrap(), 1.0));\n    }\n\n    #[test]\n    fn test_additional_coverage() {\n        // Test String (owned) conversion\n        let unit_string = String::from(\"kPa\");\n        assert_eq!(\n            unit_string.into_pressure_unit().unwrap(),\n            PressureUnit::Kilopascal\n        );\n\n        let invalid_string = String::from(\"invalid\");\n        assert!(invalid_string.into_pressure_unit().is_err());\n\n        // Test Display implementation for all units\n        assert_eq!(format!(\"{}\", PressureUnit::Pascal), \"Pa\");\n        assert_eq!(format!(\"{}\", PressureUnit::Kilopascal), \"kPa\");\n        assert_eq!(format!(\"{}\", PressureUnit::Megapascal), \"MPa\");\n        assert_eq!(format!(\"{}\", PressureUnit::Gigapascal), \"GPa\");\n        assert_eq!(format!(\"{}\", PressureUnit::Hectopascal), \"hPa\");\n        assert_eq!(format!(\"{}\", PressureUnit::Atmosphere), \"atm\");\n        assert_eq!(format!(\"{}\", PressureUnit::TechnicalAtmosphere), \"at\");\n        assert_eq!(format!(\"{}\", PressureUnit::TotalAtmosphere), \"ata\");\n        assert_eq!(format!(\"{}\", PressureUnit::Torr), \"Torr\");\n        assert_eq!(format!(\"{}\", PressureUnit::Millitorr), \"mTorr\");\n        assert_eq!(format!(\"{}\", PressureUnit::Bar), \"bar\");\n        assert_eq!(format!(\"{}\", PressureUnit::Millibar), \"mbar\");\n        assert_eq!(format!(\"{}\", PressureUnit::Psi), \"psi\");\n        assert_eq!(format!(\"{}\", PressureUnit::Ksi), \"ksi\");\n        assert_eq!(\n            format!(\"{}\", PressureUnit::OunceForcePerSquareInch),\n            \"ozf/in²\"\n        );\n        assert_eq!(format!(\"{}\", PressureUnit::Barad), \"Ba\");\n        assert_eq!(format!(\"{}\", PressureUnit::Pieze), \"pz\");\n        assert_eq!(format!(\"{}\", PressureUnit::MillimeterMercury), \"mmHg\");\n        assert_eq!(format!(\"{}\", PressureUnit::CentimeterMercury), \"cmHg\");\n        assert_eq!(format!(\"{}\", PressureUnit::InchMercury), \"inHg\");\n        assert_eq!(format!(\"{}\", PressureUnit::MillimeterWater), \"mmH₂O\");\n        assert_eq!(format!(\"{}\", PressureUnit::CentimeterWater), \"cmH₂O\");\n        assert_eq!(format!(\"{}\", PressureUnit::InchWater), \"inH₂O\");\n        assert_eq!(format!(\"{}\", PressureUnit::MeterSeawater), \"msw\");\n        assert_eq!(format!(\"{}\", PressureUnit::FootSeawater), \"fsw\");\n\n        // Test Millitorr conversion factor\n        assert!(approx_eq(\n            convert_pressure(1.0, \"mtorr\", \"pa\").unwrap(),\n            101_325.0 / 760_000.0\n        ));\n        assert!(approx_eq(\n            convert_pressure(1000.0, \"mtorr\", \"torr\").unwrap(),\n            1.0\n        ));\n\n        // Test OunceForcePerSquareInch conversion factor\n        assert!(approx_eq(\n            convert_pressure(1.0, \"ozf/in2\", \"pa\").unwrap(),\n            430.922_330_823\n        ));\n        assert!(approx_eq(\n            convert_pressure(16.0, \"ozf/in2\", \"psi\").unwrap(),\n            1.0\n        ));\n\n        // Test CentimeterMercury conversion factor\n        assert!(approx_eq(\n            convert_pressure(1.0, \"cmhg\", \"pa\").unwrap(),\n            101_325.0 / 76.0\n        ));\n        assert!(approx_eq(\n            convert_pressure(76.0, \"cmhg\", \"atm\").unwrap(),\n            1.0\n        ));\n\n        // Test CentimeterWater conversion factor\n        assert!(approx_eq(\n            convert_pressure(1.0, \"cmh2o\", \"pa\").unwrap(),\n            98.0665\n        ));\n\n        // Test InchWater conversion factor\n        assert!(approx_eq(\n            convert_pressure(1.0, \"inh2o\", \"pa\").unwrap(),\n            249.088_908_333\n        ));\n    }\n}\n"
  },
  {
    "path": "src/conversions/rectangular_to_polar.rs",
    "content": "//! Conversions between rectangular (Cartesian) and polar coordinate systems.\n//!\n//! This module provides utilities for converting rectangular coordinates\n//! into polar coordinates with angles expressed in degrees.\n//!\n//! More information: <https://en.wikipedia.org/wiki/Polar_coordinate_system>\n\n/// Convert rectangular (Cartesian) coordinates to polar coordinates.\n///\n/// The returned tuple contains:\n/// - magnitude (r)\n/// - angle (θ) in degrees\n///\n/// Both values are rounded to 2 decimal places.\n///\n/// # Formula\n/// - r = sqrt(x² + y²)\n/// - θ = atan2(y, x) converted to degrees\npub fn rectangular_to_polar(real: f64, imag: f64) -> (f64, f64) {\n    let magnitude = (real.powi(2) + imag.powi(2)).sqrt();\n    let angle = imag.atan2(real).to_degrees();\n\n    (\n        round_to_two_decimals(magnitude),\n        round_to_two_decimals(angle),\n    )\n}\n\nfn round_to_two_decimals(value: f64) -> f64 {\n    (value * 100.0).round() / 100.0\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_rectangular_to_polar() {\n        assert_eq!(rectangular_to_polar(5.0, -5.0), (7.07, -45.0));\n        assert_eq!(rectangular_to_polar(-1.0, 1.0), (1.41, 135.0));\n        assert_eq!(rectangular_to_polar(-1.0, -1.0), (1.41, -135.0));\n        assert_eq!(rectangular_to_polar(1e-10, 1e-10), (0.0, 45.0));\n        assert_eq!(rectangular_to_polar(-1e-10, 1e-10), (0.0, 135.0));\n        assert_eq!(rectangular_to_polar(9.75, 5.93), (11.41, 31.31));\n        assert_eq!(rectangular_to_polar(10000.0, 99999.0), (100497.76, 84.29));\n    }\n}\n"
  },
  {
    "path": "src/conversions/rgb_cmyk_conversion.rs",
    "content": "/// Author : https://github.com/ali77gh\\\n/// References:\\\n/// RGB:  https://en.wikipedia.org/wiki/RGB_color_model\\\n/// CMYK: https://en.wikipedia.org/wiki/CMYK_color_model\\\n\n/// This function Converts RGB to CMYK format\n///\n/// ### Params\n/// * `r` - red\n/// * `g` - green\n/// * `b` - blue\n///\n/// ### Returns\n/// (C, M, Y, K)\npub fn rgb_to_cmyk(rgb: (u8, u8, u8)) -> (u8, u8, u8, u8) {\n    // Safety: no need to check if input is positive and less than 255 because it's u8\n\n    // change scale from [0,255] to [0,1]\n    let (r, g, b) = (\n        rgb.0 as f64 / 255f64,\n        rgb.1 as f64 / 255f64,\n        rgb.2 as f64 / 255f64,\n    );\n\n    match 1f64 - r.max(g).max(b) {\n        1f64 => (0, 0, 0, 100), // pure black\n        k => (\n            (100f64 * (1f64 - r - k) / (1f64 - k)) as u8, // c\n            (100f64 * (1f64 - g - k) / (1f64 - k)) as u8, // m\n            (100f64 * (1f64 - b - k) / (1f64 - k)) as u8, // y\n            (100f64 * k) as u8,                           // k\n        ),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_rgb_to_cmyk {\n        ($($name:ident: $tc:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (rgb, cmyk) = $tc;\n                    assert_eq!(rgb_to_cmyk(rgb), cmyk);\n                }\n            )*\n        }\n    }\n\n    test_rgb_to_cmyk! {\n        white: ((255, 255, 255), (0, 0, 0, 0)),\n        gray: ((128, 128, 128), (0, 0, 0, 49)),\n        black: ((0, 0, 0), (0, 0, 0, 100)),\n        red: ((255, 0, 0), (0, 100, 100, 0)),\n        green: ((0, 255, 0), (100, 0, 100, 0)),\n        blue: ((0, 0, 255), (100, 100, 0, 0)),\n    }\n}\n"
  },
  {
    "path": "src/conversions/rgb_hsv_conversion.rs",
    "content": "//! Module for converting between RGB and HSV color representations\n//!\n//! The RGB color model is an additive color model in which red, green, and blue light\n//! are added together in various ways to reproduce a broad array of colors. The name\n//! of the model comes from the initials of the three additive primary colors, red,\n//! green, and blue. Meanwhile, the HSV representation models how colors appear under\n//! light. In it, colors are represented using three components: hue, saturation and\n//! (brightness-)value.\n//!\n//! References:\n//! - https://en.wikipedia.org/wiki/RGB_color_model\n//! - https://en.wikipedia.org/wiki/HSL_and_HSV\n//! - https://www.rapidtables.com/convert/color/hsv-to-rgb.html\n\n/// Errors that can occur during color conversion\n#[derive(Debug, PartialEq)]\npub enum ColorError {\n    /// Hue value is out of valid range [0, 360]\n    InvalidHue(f64),\n    /// Saturation value is out of valid range [0, 1]\n    InvalidSaturation(f64),\n    /// Value component is out of valid range [0, 1]\n    InvalidValue(f64),\n}\n\nimpl std::fmt::Display for ColorError {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            ColorError::InvalidHue(val) => write!(f, \"hue should be between 0 and 360, got {val}\"),\n            ColorError::InvalidSaturation(val) => {\n                write!(f, \"saturation should be between 0 and 1, got {val}\")\n            }\n            ColorError::InvalidValue(val) => {\n                write!(f, \"value should be between 0 and 1, got {val}\")\n            }\n        }\n    }\n}\n\nimpl std::error::Error for ColorError {}\n\n/// RGB color representation with red, green, and blue components (0-255)\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub struct Rgb {\n    pub red: u8,\n    pub green: u8,\n    pub blue: u8,\n}\n\nimpl Rgb {\n    /// Create a new RGB color\n    pub fn new(red: u8, green: u8, blue: u8) -> Self {\n        Rgb { red, green, blue }\n    }\n}\n\n/// HSV color representation with hue (0-360), saturation (0-1), and value (0-1)\n#[derive(Debug, Clone, Copy, PartialEq)]\npub struct Hsv {\n    pub hue: f64,\n    pub saturation: f64,\n    pub value: f64,\n}\n\nimpl Hsv {\n    /// Create a new HSV color with validation\n    pub fn new(hue: f64, saturation: f64, value: f64) -> Result<Self, ColorError> {\n        if !(0.0..=360.0).contains(&hue) {\n            return Err(ColorError::InvalidHue(hue));\n        }\n        if !(0.0..=1.0).contains(&saturation) {\n            return Err(ColorError::InvalidSaturation(saturation));\n        }\n        if !(0.0..=1.0).contains(&value) {\n            return Err(ColorError::InvalidValue(value));\n        }\n        Ok(Hsv {\n            hue,\n            saturation,\n            value,\n        })\n    }\n\n    /// Check if two HSV colors are approximately equal\n    ///\n    /// Uses tolerance values:\n    /// - Hue: 0.2 degrees\n    /// - Saturation: 0.002\n    /// - Value: 0.002\n    pub fn approximately_equal(&self, other: &Hsv) -> bool {\n        let hue_diff = (self.hue - other.hue).abs();\n        let sat_diff = (self.saturation - other.saturation).abs();\n        let val_diff = (self.value - other.value).abs();\n\n        hue_diff < 0.2 && sat_diff < 0.002 && val_diff < 0.002\n    }\n}\n\n/// Convert HSV color representation to RGB\n///\n/// Converts from HSV (Hue, Saturation, Value) to RGB (Red, Green, Blue).\n///\n/// # Arguments\n///\n/// * `hue` - Hue value in degrees (0-360)\n/// * `saturation` - Saturation value (0-1)\n/// * `value` - Value/brightness (0-1)\n///\n/// # Returns\n///\n/// * `Ok(Rgb)` - RGB color with components in range 0-255\n/// * `Err(ColorError)` - If any input is out of valid range\npub fn hsv_to_rgb(hue: f64, saturation: f64, value: f64) -> Result<Rgb, ColorError> {\n    if !(0.0..=360.0).contains(&hue) {\n        return Err(ColorError::InvalidHue(hue));\n    }\n    if !(0.0..=1.0).contains(&saturation) {\n        return Err(ColorError::InvalidSaturation(saturation));\n    }\n    if !(0.0..=1.0).contains(&value) {\n        return Err(ColorError::InvalidValue(value));\n    }\n\n    let chroma = value * saturation;\n    let hue_section = hue / 60.0;\n    let second_largest_component = chroma * (1.0 - ((hue_section % 2.0) - 1.0).abs());\n    let match_value = value - chroma;\n\n    let (red, green, blue) = if (0.0..=1.0).contains(&hue_section) {\n        (\n            chroma + match_value,\n            second_largest_component + match_value,\n            match_value,\n        )\n    } else if (1.0..=2.0).contains(&hue_section) {\n        (\n            second_largest_component + match_value,\n            chroma + match_value,\n            match_value,\n        )\n    } else if (2.0..=3.0).contains(&hue_section) {\n        (\n            match_value,\n            chroma + match_value,\n            second_largest_component + match_value,\n        )\n    } else if (3.0..=4.0).contains(&hue_section) {\n        (\n            match_value,\n            second_largest_component + match_value,\n            chroma + match_value,\n        )\n    } else if (4.0..=5.0).contains(&hue_section) {\n        (\n            second_largest_component + match_value,\n            match_value,\n            chroma + match_value,\n        )\n    } else {\n        (\n            chroma + match_value,\n            match_value,\n            second_largest_component + match_value,\n        )\n    };\n\n    Ok(Rgb {\n        red: (red * 255.0).round() as u8,\n        green: (green * 255.0).round() as u8,\n        blue: (blue * 255.0).round() as u8,\n    })\n}\n\n/// Convert RGB color representation to HSV\n///\n/// Converts from RGB (Red, Green, Blue) to HSV (Hue, Saturation, Value).\n///\n/// # Arguments\n///\n/// * `red` - Red component (0-255)\n/// * `green` - Green component (0-255)\n/// * `blue` - Blue component (0-255)\n///\n/// # Returns\n///\n/// * `Ok(Hsv)` - HSV color with hue in [0, 360] and saturation/value in [0, 1]\npub fn rgb_to_hsv(red: u8, green: u8, blue: u8) -> Result<Hsv, ColorError> {\n    let float_red = f64::from(red) / 255.0;\n    let float_green = f64::from(green) / 255.0;\n    let float_blue = f64::from(blue) / 255.0;\n\n    let value = float_red.max(float_green).max(float_blue);\n    let min_val = float_red.min(float_green).min(float_blue);\n    let chroma = value - min_val;\n\n    let saturation = if value == 0.0 { 0.0 } else { chroma / value };\n\n    let hue = if chroma == 0.0 {\n        0.0\n    } else if (value - float_red).abs() < f64::EPSILON {\n        60.0 * (0.0 + (float_green - float_blue) / chroma)\n    } else if (value - float_green).abs() < f64::EPSILON {\n        60.0 * (2.0 + (float_blue - float_red) / chroma)\n    } else {\n        60.0 * (4.0 + (float_red - float_green) / chroma)\n    };\n\n    let hue = (hue + 360.0) % 360.0;\n\n    Ok(Hsv {\n        hue,\n        saturation,\n        value,\n    })\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_hsv_to_rgb_basic_colors() {\n        // Black\n        assert_eq!(hsv_to_rgb(0.0, 0.0, 0.0).unwrap(), Rgb::new(0, 0, 0));\n\n        // White\n        assert_eq!(hsv_to_rgb(0.0, 0.0, 1.0).unwrap(), Rgb::new(255, 255, 255));\n\n        // Red\n        assert_eq!(hsv_to_rgb(0.0, 1.0, 1.0).unwrap(), Rgb::new(255, 0, 0));\n\n        // Yellow\n        assert_eq!(hsv_to_rgb(60.0, 1.0, 1.0).unwrap(), Rgb::new(255, 255, 0));\n\n        // Green\n        assert_eq!(hsv_to_rgb(120.0, 1.0, 1.0).unwrap(), Rgb::new(0, 255, 0));\n\n        // Blue\n        assert_eq!(hsv_to_rgb(240.0, 1.0, 1.0).unwrap(), Rgb::new(0, 0, 255));\n\n        // Magenta\n        assert_eq!(hsv_to_rgb(300.0, 1.0, 1.0).unwrap(), Rgb::new(255, 0, 255));\n    }\n\n    #[test]\n    fn test_hsv_to_rgb_intermediate_colors() {\n        assert_eq!(hsv_to_rgb(180.0, 0.5, 0.5).unwrap(), Rgb::new(64, 128, 128));\n        assert_eq!(\n            hsv_to_rgb(234.0, 0.14, 0.88).unwrap(),\n            Rgb::new(193, 196, 224)\n        );\n        assert_eq!(hsv_to_rgb(330.0, 0.75, 0.5).unwrap(), Rgb::new(128, 32, 80));\n    }\n\n    #[test]\n    fn test_hsv_to_rgb_invalid_hue() {\n        assert_eq!(\n            hsv_to_rgb(-1.0, 0.5, 0.5),\n            Err(ColorError::InvalidHue(-1.0))\n        );\n        assert_eq!(\n            hsv_to_rgb(361.0, 0.5, 0.5),\n            Err(ColorError::InvalidHue(361.0))\n        );\n    }\n\n    #[test]\n    fn test_hsv_to_rgb_invalid_saturation() {\n        assert_eq!(\n            hsv_to_rgb(180.0, -0.1, 0.5),\n            Err(ColorError::InvalidSaturation(-0.1))\n        );\n        assert_eq!(\n            hsv_to_rgb(180.0, 1.1, 0.5),\n            Err(ColorError::InvalidSaturation(1.1))\n        );\n    }\n\n    #[test]\n    fn test_hsv_to_rgb_invalid_value() {\n        assert_eq!(\n            hsv_to_rgb(180.0, 0.5, -0.1),\n            Err(ColorError::InvalidValue(-0.1))\n        );\n        assert_eq!(\n            hsv_to_rgb(180.0, 0.5, 1.1),\n            Err(ColorError::InvalidValue(1.1))\n        );\n    }\n\n    #[test]\n    fn test_rgb_to_hsv_basic_colors() {\n        // Black\n        let hsv = rgb_to_hsv(0, 0, 0).unwrap();\n        assert!(Hsv::new(0.0, 0.0, 0.0).unwrap().approximately_equal(&hsv));\n\n        // White\n        let hsv = rgb_to_hsv(255, 255, 255).unwrap();\n        assert!(Hsv::new(0.0, 0.0, 1.0).unwrap().approximately_equal(&hsv));\n\n        // Red\n        let hsv = rgb_to_hsv(255, 0, 0).unwrap();\n        assert!(Hsv::new(0.0, 1.0, 1.0).unwrap().approximately_equal(&hsv));\n\n        // Yellow\n        let hsv = rgb_to_hsv(255, 255, 0).unwrap();\n        assert!(Hsv::new(60.0, 1.0, 1.0).unwrap().approximately_equal(&hsv));\n\n        // Green\n        let hsv = rgb_to_hsv(0, 255, 0).unwrap();\n        assert!(Hsv::new(120.0, 1.0, 1.0).unwrap().approximately_equal(&hsv));\n\n        // Blue\n        let hsv = rgb_to_hsv(0, 0, 255).unwrap();\n        assert!(Hsv::new(240.0, 1.0, 1.0).unwrap().approximately_equal(&hsv));\n\n        // Magenta\n        let hsv = rgb_to_hsv(255, 0, 255).unwrap();\n        assert!(Hsv::new(300.0, 1.0, 1.0).unwrap().approximately_equal(&hsv));\n    }\n\n    #[test]\n    fn test_rgb_to_hsv_intermediate_colors() {\n        let hsv = rgb_to_hsv(64, 128, 128).unwrap();\n        assert!(Hsv::new(180.0, 0.5, 0.5).unwrap().approximately_equal(&hsv));\n\n        let hsv = rgb_to_hsv(193, 196, 224).unwrap();\n        assert!(Hsv::new(234.0, 0.14, 0.88)\n            .unwrap()\n            .approximately_equal(&hsv));\n\n        let hsv = rgb_to_hsv(128, 32, 80).unwrap();\n        assert!(Hsv::new(330.0, 0.75, 0.5)\n            .unwrap()\n            .approximately_equal(&hsv));\n    }\n\n    #[test]\n    fn test_round_trip_conversion() {\n        let test_cases = vec![\n            (0.0, 0.0, 0.0),\n            (0.0, 0.0, 1.0),\n            (0.0, 1.0, 1.0),\n            (60.0, 1.0, 1.0),\n            (120.0, 1.0, 1.0),\n            (240.0, 1.0, 1.0),\n            (300.0, 1.0, 1.0),\n            (180.0, 0.5, 0.5),\n            (234.0, 0.14, 0.88),\n            (330.0, 0.75, 0.5),\n        ];\n\n        for (hue, sat, val) in test_cases {\n            let original_hsv = Hsv::new(hue, sat, val).unwrap();\n            let rgb = hsv_to_rgb(hue, sat, val).unwrap();\n            let converted_hsv = rgb_to_hsv(rgb.red, rgb.green, rgb.blue).unwrap();\n            assert!(\n                original_hsv.approximately_equal(&converted_hsv),\n                \"Round trip failed for HSV({hue}, {sat}, {val})\"\n            );\n        }\n    }\n\n    #[test]\n    fn test_approximately_equal_hsv() {\n        let hsv1 = Hsv::new(0.0, 0.0, 0.0).unwrap();\n        let hsv2 = Hsv::new(0.0, 0.0, 0.0).unwrap();\n        assert!(hsv1.approximately_equal(&hsv2));\n\n        let hsv1 = Hsv::new(180.0, 0.5, 0.3).unwrap();\n        let hsv2 = Hsv::new(179.9999, 0.500001, 0.30001).unwrap();\n        assert!(hsv1.approximately_equal(&hsv2));\n\n        let hsv1 = Hsv::new(0.0, 0.0, 0.0).unwrap();\n        let hsv2 = Hsv::new(1.0, 0.0, 0.0).unwrap();\n        assert!(!hsv1.approximately_equal(&hsv2));\n\n        let hsv1 = Hsv::new(180.0, 0.5, 0.3).unwrap();\n        let hsv2 = Hsv::new(179.9999, 0.6, 0.30001).unwrap();\n        assert!(!hsv1.approximately_equal(&hsv2));\n    }\n\n    #[test]\n    fn test_hsv_new_validation() {\n        assert!(Hsv::new(0.0, 0.0, 0.0).is_ok());\n        assert!(Hsv::new(360.0, 1.0, 1.0).is_ok());\n        assert_eq!(Hsv::new(-1.0, 0.5, 0.5), Err(ColorError::InvalidHue(-1.0)));\n        assert_eq!(\n            Hsv::new(361.0, 0.5, 0.5),\n            Err(ColorError::InvalidHue(361.0))\n        );\n        assert_eq!(\n            Hsv::new(180.0, -0.1, 0.5),\n            Err(ColorError::InvalidSaturation(-0.1))\n        );\n        assert_eq!(\n            Hsv::new(180.0, 1.1, 0.5),\n            Err(ColorError::InvalidSaturation(1.1))\n        );\n        assert_eq!(\n            Hsv::new(180.0, 0.5, -0.1),\n            Err(ColorError::InvalidValue(-0.1))\n        );\n        assert_eq!(\n            Hsv::new(180.0, 0.5, 1.1),\n            Err(ColorError::InvalidValue(1.1))\n        );\n    }\n\n    #[test]\n    fn test_edge_cases() {\n        // Hue = 360 should work (edge of valid range)\n        assert!(hsv_to_rgb(360.0, 1.0, 1.0).is_ok());\n\n        // Saturation and value at boundaries\n        assert!(hsv_to_rgb(180.0, 0.0, 0.0).is_ok());\n        assert!(hsv_to_rgb(180.0, 1.0, 1.0).is_ok());\n\n        // All RGB values at max\n        assert!(rgb_to_hsv(255, 255, 255).is_ok());\n\n        // All RGB values at min\n        assert!(rgb_to_hsv(0, 0, 0).is_ok());\n    }\n\n    #[test]\n    fn test_rgb_struct() {\n        let rgb = Rgb::new(100, 150, 200);\n        assert_eq!(rgb.red, 100);\n        assert_eq!(rgb.green, 150);\n        assert_eq!(rgb.blue, 200);\n    }\n}\n"
  },
  {
    "path": "src/conversions/roman_numerals.rs",
    "content": "//! Roman Numeral Conversion\n//!\n//! This module provides conversion between Roman numerals and integers.\n//!\n//! Roman numerals use combinations of letters from the Latin alphabet:\n//! I, V, X, L, C, D, and M to represent numbers.\n//!\n//! # Rules\n//!\n//! - I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000\n//! - When a smaller value appears before a larger value, subtract the smaller\n//!   (e.g., IV = 4, IX = 9)\n//! - When a smaller value appears after a larger value, add the smaller\n//!   (e.g., VI = 6, XI = 11)\n//!\n//! # References\n//!\n//! - [Roman Numerals - Wikipedia](https://en.wikipedia.org/wiki/Roman_numerals)\n//! - [LeetCode #13 - Roman to Integer](https://leetcode.com/problems/roman-to-integer/)\n\n/// Roman numeral symbols and their corresponding values in descending order.\n/// Used for conversion from integer to Roman numeral.\nconst ROMAN_NUMERALS: [(u32, &str); 13] = [\n    (1000, \"M\"),\n    (900, \"CM\"),\n    (500, \"D\"),\n    (400, \"CD\"),\n    (100, \"C\"),\n    (90, \"XC\"),\n    (50, \"L\"),\n    (40, \"XL\"),\n    (10, \"X\"),\n    (9, \"IX\"),\n    (5, \"V\"),\n    (4, \"IV\"),\n    (1, \"I\"),\n];\n\n/// Converts a Roman numeral string to an integer.\n///\n/// # Arguments\n///\n/// * `roman` - A string slice containing a valid Roman numeral\n///\n/// # Returns\n///\n/// `Ok(u32)` with the integer value, or `Err(String)` if the input is invalid\n///\n/// # Rules\n///\n/// - Valid Roman numerals are in range 1-3999\n/// - Uses standard subtractive notation (IV, IX, XL, XC, CD, CM)\n/// - Input must contain only valid Roman numeral characters: I, V, X, L, C, D, M\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::conversions::roman_to_int;\n///\n/// assert_eq!(roman_to_int(\"III\").unwrap(), 3);\n/// assert_eq!(roman_to_int(\"CLIV\").unwrap(), 154);\n/// assert_eq!(roman_to_int(\"MIX\").unwrap(), 1009);\n/// assert_eq!(roman_to_int(\"MMMCMXCIX\").unwrap(), 3999);\n///\n/// // Invalid input returns error\n/// assert!(roman_to_int(\"INVALID\").is_err());\n/// ```\npub fn roman_to_int(roman: &str) -> Result<u32, String> {\n    if roman.is_empty() {\n        return Err(\"Roman numeral cannot be empty\".to_string());\n    }\n\n    // Convert to uppercase for case-insensitive processing\n    let roman = roman.to_uppercase();\n    let chars: Vec<char> = roman.chars().collect();\n\n    // Validate that all characters are valid Roman numerals\n    for ch in &chars {\n        if !matches!(ch, 'I' | 'V' | 'X' | 'L' | 'C' | 'D' | 'M') {\n            return Err(format!(\"Invalid Roman numeral character: '{ch}'\"));\n        }\n    }\n\n    let mut total: u32 = 0;\n    let mut place = 0;\n\n    while place < chars.len() {\n        let current_val = char_to_value(chars[place]);\n\n        // Check if we need to use subtractive notation\n        if place + 1 < chars.len() {\n            let next_val = char_to_value(chars[place + 1]);\n\n            if current_val < next_val {\n                // Subtractive case (e.g., IV, IX, XL, XC, CD, CM)\n                total += next_val - current_val;\n                place += 2;\n                continue;\n            }\n        }\n\n        // Normal case - just add the value\n        total += current_val;\n        place += 1;\n    }\n\n    if total == 0 || total > 3999 {\n        return Err(format!(\n            \"Result {total} is out of valid range (1-3999) for Roman numerals\"\n        ));\n    }\n\n    Ok(total)\n}\n\n/// Converts an integer to a Roman numeral string.\n///\n/// # Arguments\n///\n/// * `number` - An integer in the range 1-3999\n///\n/// # Returns\n///\n/// `Ok(String)` with the Roman numeral representation, or `Err(String)` if out of range\n///\n/// # Rules\n///\n/// - Valid input range is 1-3999\n/// - Uses standard subtractive notation (IV, IX, XL, XC, CD, CM)\n/// - Returns the shortest possible representation\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::conversions::int_to_roman;\n///\n/// assert_eq!(int_to_roman(3).unwrap(), \"III\");\n/// assert_eq!(int_to_roman(154).unwrap(), \"CLIV\");\n/// assert_eq!(int_to_roman(1009).unwrap(), \"MIX\");\n/// assert_eq!(int_to_roman(3999).unwrap(), \"MMMCMXCIX\");\n///\n/// // Out of range returns error\n/// assert!(int_to_roman(0).is_err());\n/// assert!(int_to_roman(4000).is_err());\n/// ```\npub fn int_to_roman(mut number: u32) -> Result<String, String> {\n    if number == 0 || number > 3999 {\n        return Err(format!(\n            \"Number {number} is out of valid range (1-3999) for Roman numerals\"\n        ));\n    }\n\n    let mut result = String::new();\n\n    for (value, numeral) in ROMAN_NUMERALS.iter() {\n        let count = number / value;\n        if count > 0 {\n            result.push_str(&numeral.repeat(count as usize));\n            number %= value;\n        }\n\n        if number == 0 {\n            break;\n        }\n    }\n\n    Ok(result)\n}\n\n/// Helper function to convert a Roman numeral character to its integer value.\n///\n/// # Arguments\n///\n/// * `ch` - A Roman numeral character (I, V, X, L, C, D, M)\n///\n/// # Returns\n///\n/// The integer value of the character\n///\n/// # Panics\n///\n/// Panics if an invalid character is provided (this should be caught by validation)\nfn char_to_value(ch: char) -> u32 {\n    match ch {\n        'I' => 1,\n        'V' => 5,\n        'X' => 10,\n        'L' => 50,\n        'C' => 100,\n        'D' => 500,\n        'M' => 1000,\n        _ => panic!(\"Invalid Roman numeral character: {ch}\"),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_roman_to_int_basic() {\n        assert_eq!(roman_to_int(\"I\").unwrap(), 1);\n        assert_eq!(roman_to_int(\"V\").unwrap(), 5);\n        assert_eq!(roman_to_int(\"X\").unwrap(), 10);\n        assert_eq!(roman_to_int(\"L\").unwrap(), 50);\n        assert_eq!(roman_to_int(\"C\").unwrap(), 100);\n        assert_eq!(roman_to_int(\"D\").unwrap(), 500);\n        assert_eq!(roman_to_int(\"M\").unwrap(), 1000);\n    }\n\n    #[test]\n    fn test_roman_to_int_additive() {\n        assert_eq!(roman_to_int(\"II\").unwrap(), 2);\n        assert_eq!(roman_to_int(\"III\").unwrap(), 3);\n        assert_eq!(roman_to_int(\"VI\").unwrap(), 6);\n        assert_eq!(roman_to_int(\"VII\").unwrap(), 7);\n        assert_eq!(roman_to_int(\"VIII\").unwrap(), 8);\n        assert_eq!(roman_to_int(\"XI\").unwrap(), 11);\n        assert_eq!(roman_to_int(\"XV\").unwrap(), 15);\n        assert_eq!(roman_to_int(\"XX\").unwrap(), 20);\n        assert_eq!(roman_to_int(\"XXX\").unwrap(), 30);\n    }\n\n    #[test]\n    fn test_roman_to_int_subtractive() {\n        assert_eq!(roman_to_int(\"IV\").unwrap(), 4);\n        assert_eq!(roman_to_int(\"IX\").unwrap(), 9);\n        assert_eq!(roman_to_int(\"XL\").unwrap(), 40);\n        assert_eq!(roman_to_int(\"XC\").unwrap(), 90);\n        assert_eq!(roman_to_int(\"CD\").unwrap(), 400);\n        assert_eq!(roman_to_int(\"CM\").unwrap(), 900);\n    }\n\n    #[test]\n    fn test_roman_to_int_complex() {\n        assert_eq!(roman_to_int(\"CLIV\").unwrap(), 154);\n        assert_eq!(roman_to_int(\"MCMXC\").unwrap(), 1990);\n        assert_eq!(roman_to_int(\"MMXIV\").unwrap(), 2014);\n        assert_eq!(roman_to_int(\"MIX\").unwrap(), 1009);\n        assert_eq!(roman_to_int(\"MMD\").unwrap(), 2500);\n        assert_eq!(roman_to_int(\"MMMCMXCIX\").unwrap(), 3999);\n    }\n\n    #[test]\n    fn test_roman_to_int_case_insensitive() {\n        assert_eq!(roman_to_int(\"iii\").unwrap(), 3);\n        assert_eq!(roman_to_int(\"Cliv\").unwrap(), 154);\n        assert_eq!(roman_to_int(\"mIx\").unwrap(), 1009);\n    }\n\n    #[test]\n    fn test_roman_to_int_invalid_character() {\n        assert!(roman_to_int(\"INVALID\").is_err());\n        assert!(roman_to_int(\"XYZ\").is_err());\n        assert!(roman_to_int(\"123\").is_err());\n        assert!(roman_to_int(\"X5\").is_err());\n    }\n\n    #[test]\n    fn test_roman_to_int_empty() {\n        assert!(roman_to_int(\"\").is_err());\n    }\n\n    #[test]\n    fn test_int_to_roman_basic() {\n        assert_eq!(int_to_roman(1).unwrap(), \"I\");\n        assert_eq!(int_to_roman(5).unwrap(), \"V\");\n        assert_eq!(int_to_roman(10).unwrap(), \"X\");\n        assert_eq!(int_to_roman(50).unwrap(), \"L\");\n        assert_eq!(int_to_roman(100).unwrap(), \"C\");\n        assert_eq!(int_to_roman(500).unwrap(), \"D\");\n        assert_eq!(int_to_roman(1000).unwrap(), \"M\");\n    }\n\n    #[test]\n    fn test_int_to_roman_additive() {\n        assert_eq!(int_to_roman(2).unwrap(), \"II\");\n        assert_eq!(int_to_roman(3).unwrap(), \"III\");\n        assert_eq!(int_to_roman(6).unwrap(), \"VI\");\n        assert_eq!(int_to_roman(7).unwrap(), \"VII\");\n        assert_eq!(int_to_roman(8).unwrap(), \"VIII\");\n        assert_eq!(int_to_roman(11).unwrap(), \"XI\");\n        assert_eq!(int_to_roman(15).unwrap(), \"XV\");\n        assert_eq!(int_to_roman(20).unwrap(), \"XX\");\n        assert_eq!(int_to_roman(30).unwrap(), \"XXX\");\n    }\n\n    #[test]\n    fn test_int_to_roman_subtractive() {\n        assert_eq!(int_to_roman(4).unwrap(), \"IV\");\n        assert_eq!(int_to_roman(9).unwrap(), \"IX\");\n        assert_eq!(int_to_roman(40).unwrap(), \"XL\");\n        assert_eq!(int_to_roman(90).unwrap(), \"XC\");\n        assert_eq!(int_to_roman(400).unwrap(), \"CD\");\n        assert_eq!(int_to_roman(900).unwrap(), \"CM\");\n    }\n\n    #[test]\n    fn test_int_to_roman_complex() {\n        assert_eq!(int_to_roman(154).unwrap(), \"CLIV\");\n        assert_eq!(int_to_roman(1990).unwrap(), \"MCMXC\");\n        assert_eq!(int_to_roman(2014).unwrap(), \"MMXIV\");\n        assert_eq!(int_to_roman(1009).unwrap(), \"MIX\");\n        assert_eq!(int_to_roman(2500).unwrap(), \"MMD\");\n        assert_eq!(int_to_roman(3999).unwrap(), \"MMMCMXCIX\");\n    }\n\n    #[test]\n    fn test_int_to_roman_out_of_range() {\n        assert!(int_to_roman(0).is_err());\n        assert!(int_to_roman(4000).is_err());\n        assert!(int_to_roman(5000).is_err());\n    }\n\n    #[test]\n    fn test_roundtrip_conversion() {\n        // Test that converting to Roman and back gives the same number\n        for i in 1..=3999 {\n            let roman = int_to_roman(i).unwrap();\n            let back = roman_to_int(&roman).unwrap();\n            assert_eq!(i, back, \"Roundtrip failed for {i}: {roman} -> {back}\");\n        }\n    }\n\n    #[test]\n    fn test_all_examples_from_python() {\n        // Test cases from the original Python implementation\n        let tests = [\n            (\"III\", 3),\n            (\"CLIV\", 154),\n            (\"MIX\", 1009),\n            (\"MMD\", 2500),\n            (\"MMMCMXCIX\", 3999),\n        ];\n\n        for (roman, expected) in tests.iter() {\n            assert_eq!(roman_to_int(roman).unwrap(), *expected);\n            assert_eq!(int_to_roman(*expected).unwrap(), *roman);\n        }\n    }\n\n    #[test]\n    fn test_edge_cases() {\n        // Minimum value\n        assert_eq!(int_to_roman(1).unwrap(), \"I\");\n        assert_eq!(roman_to_int(\"I\").unwrap(), 1);\n\n        // Maximum value\n        assert_eq!(int_to_roman(3999).unwrap(), \"MMMCMXCIX\");\n        assert_eq!(roman_to_int(\"MMMCMXCIX\").unwrap(), 3999);\n\n        // Powers of 10\n        assert_eq!(int_to_roman(10).unwrap(), \"X\");\n        assert_eq!(int_to_roman(100).unwrap(), \"C\");\n        assert_eq!(int_to_roman(1000).unwrap(), \"M\");\n    }\n}\n"
  },
  {
    "path": "src/conversions/speed.rs",
    "content": "//! Convert speed units\n//!\n//! References:\n//! - <https://en.wikipedia.org/wiki/Kilometres_per_hour>\n//! - <https://en.wikipedia.org/wiki/Miles_per_hour>\n//! - <https://en.wikipedia.org/wiki/Knot_(unit)>\n//! - <https://en.wikipedia.org/wiki/Metre_per_second>\n//! - <https://en.wikipedia.org/wiki/Foot_per_second>\n//! - <https://en.wikipedia.org/wiki/Mach_number>\n//! - <https://en.wikipedia.org/wiki/Speed_of_light>\n\nuse std::fmt;\n\n/// Supported speed units\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum SpeedUnit {\n    /// Kilometers per hour (km/h)\n    KilometersPerHour,\n    /// Meters per second (m/s) - SI derived unit\n    MetersPerSecond,\n    /// Miles per hour (mph)\n    MilesPerHour,\n    /// Nautical miles per hour (knot)\n    Knot,\n    /// Feet per second (fps or ft/s)\n    FeetPerSecond,\n    /// Mach number (dimensionless) - speed divided by speed of sound at sea level (340.3 m/s)\n    Mach,\n    /// Speed of light (c) - speed divided by speed of light in vacuum (299,792,458 m/s)\n    SpeedOfLight,\n}\n\nimpl fmt::Display for SpeedUnit {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            SpeedUnit::KilometersPerHour => write!(f, \"km/h\"),\n            SpeedUnit::MetersPerSecond => write!(f, \"m/s\"),\n            SpeedUnit::MilesPerHour => write!(f, \"mph\"),\n            SpeedUnit::Knot => write!(f, \"knot\"),\n            SpeedUnit::FeetPerSecond => write!(f, \"ft/s\"),\n            SpeedUnit::Mach => write!(f, \"Mach\"),\n            SpeedUnit::SpeedOfLight => write!(f, \"c\"),\n        }\n    }\n}\n\nimpl SpeedUnit {\n    /// Get the conversion factor to km/h\n    fn as_kmh_multiplier(self) -> f64 {\n        match self {\n            SpeedUnit::KilometersPerHour => 1.0,\n            SpeedUnit::MetersPerSecond => 3.6,\n            SpeedUnit::MilesPerHour => 1.609344,\n            SpeedUnit::Knot => 1.852,\n            SpeedUnit::FeetPerSecond => 1.09728,\n            SpeedUnit::Mach => 1225.08,\n            SpeedUnit::SpeedOfLight => 1_079_252_848.8,\n        }\n    }\n\n    /// Get the conversion factor from km/h to this unit\n    fn kmh_multiplier(self) -> f64 {\n        match self {\n            SpeedUnit::KilometersPerHour => 1.0,\n            SpeedUnit::MetersPerSecond => 0.277777778,\n            SpeedUnit::MilesPerHour => 0.621371192,\n            SpeedUnit::Knot => 0.539956803,\n            SpeedUnit::FeetPerSecond => 0.911344415,\n            SpeedUnit::Mach => 0.000816164,\n            SpeedUnit::SpeedOfLight => 9.265669311e-10,\n        }\n    }\n}\n\n/// Convert speed from one unit to another\n///\n/// # Arguments\n///\n/// * `speed` - The speed value to convert\n/// * `from` - The unit to convert from\n/// * `to` - The unit to convert to\n///\n/// # Returns\n///\n/// The converted speed value rounded to 3 decimal places\npub fn convert_speed(speed: f64, from: SpeedUnit, to: SpeedUnit) -> f64 {\n    let kmh = speed * from.as_kmh_multiplier();\n    let result = kmh * to.kmh_multiplier();\n    (result * 1000.0).round() / 1000.0\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_speed_conversion() {\n        assert_eq!(\n            convert_speed(\n                100.0,\n                SpeedUnit::KilometersPerHour,\n                SpeedUnit::MetersPerSecond\n            ),\n            27.778\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::KilometersPerHour, SpeedUnit::MilesPerHour),\n            62.137\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::KilometersPerHour, SpeedUnit::Knot),\n            53.996\n        );\n        assert_eq!(\n            convert_speed(\n                100.0,\n                SpeedUnit::MetersPerSecond,\n                SpeedUnit::KilometersPerHour\n            ),\n            360.0\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::MetersPerSecond, SpeedUnit::MilesPerHour),\n            223.694\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::MetersPerSecond, SpeedUnit::Knot),\n            194.384\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::MilesPerHour, SpeedUnit::KilometersPerHour),\n            160.934\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::MilesPerHour, SpeedUnit::MetersPerSecond),\n            44.704\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::MilesPerHour, SpeedUnit::Knot),\n            86.898\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::Knot, SpeedUnit::KilometersPerHour),\n            185.2\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::Knot, SpeedUnit::MetersPerSecond),\n            51.444\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::Knot, SpeedUnit::MilesPerHour),\n            115.078\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::FeetPerSecond, SpeedUnit::MetersPerSecond),\n            30.48\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::MetersPerSecond, SpeedUnit::FeetPerSecond),\n            328.084\n        );\n        assert_eq!(\n            convert_speed(\n                100.0,\n                SpeedUnit::FeetPerSecond,\n                SpeedUnit::KilometersPerHour\n            ),\n            109.728\n        );\n        assert_eq!(\n            convert_speed(100.0, SpeedUnit::FeetPerSecond, SpeedUnit::MilesPerHour),\n            68.182\n        );\n        assert_eq!(\n            convert_speed(1.0, SpeedUnit::Mach, SpeedUnit::KilometersPerHour),\n            1225.08\n        );\n        assert_eq!(\n            convert_speed(1.0, SpeedUnit::Mach, SpeedUnit::MetersPerSecond),\n            340.3\n        );\n        assert_eq!(\n            convert_speed(1000.0, SpeedUnit::KilometersPerHour, SpeedUnit::Mach),\n            0.816\n        );\n        assert_eq!(\n            convert_speed(2.0, SpeedUnit::Mach, SpeedUnit::KilometersPerHour),\n            2450.16\n        );\n        assert_eq!(\n            convert_speed(1.0, SpeedUnit::SpeedOfLight, SpeedUnit::MetersPerSecond),\n            299792458.24\n        );\n        assert_eq!(\n            convert_speed(1.0, SpeedUnit::SpeedOfLight, SpeedUnit::KilometersPerHour),\n            1079252848.8\n        );\n        assert_eq!(\n            convert_speed(\n                299792458.0,\n                SpeedUnit::MetersPerSecond,\n                SpeedUnit::SpeedOfLight\n            ),\n            1.0\n        );\n        assert_eq!(\n            convert_speed(0.1, SpeedUnit::SpeedOfLight, SpeedUnit::MetersPerSecond),\n            29979245.824\n        );\n        assert_eq!(\n            convert_speed(\n                100.0,\n                SpeedUnit::KilometersPerHour,\n                SpeedUnit::KilometersPerHour\n            ),\n            100.0\n        );\n    }\n\n    #[test]\n    fn test_display() {\n        assert_eq!(SpeedUnit::KilometersPerHour.to_string(), \"km/h\");\n        assert_eq!(SpeedUnit::MetersPerSecond.to_string(), \"m/s\");\n        assert_eq!(SpeedUnit::MilesPerHour.to_string(), \"mph\");\n        assert_eq!(SpeedUnit::Knot.to_string(), \"knot\");\n        assert_eq!(SpeedUnit::FeetPerSecond.to_string(), \"ft/s\");\n        assert_eq!(SpeedUnit::Mach.to_string(), \"Mach\");\n        assert_eq!(SpeedUnit::SpeedOfLight.to_string(), \"c\");\n    }\n}\n"
  },
  {
    "path": "src/conversions/temperature.rs",
    "content": "//! Convert between different units of temperature\n//!\n//! Supports conversions between 8 temperature scales using Kelvin as an intermediary:\n//! - Kelvin (K) - SI base unit, absolute scale\n//! - Celsius (°C) - Standard metric scale\n//! - Fahrenheit (°F) - Imperial scale\n//! - Rankine (°R) - Absolute Fahrenheit scale\n//! - Delisle (°De) - Historical inverted scale (higher values = colder)\n//! - Newton (°N) - Historical scale by Isaac Newton\n//! - Réaumur (°Ré) - Historical European scale\n//! - Rømer (°Rø) - Historical Danish scale\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum TemperatureUnit {\n    Kelvin,\n    Celsius,\n    Fahrenheit,\n    Rankine,\n    Delisle,\n    Newton,\n    Reaumur,\n    Romer,\n}\n\nimpl TemperatureUnit {\n    fn to_kelvin(self, value: f64) -> f64 {\n        match self {\n            TemperatureUnit::Kelvin => value,\n            TemperatureUnit::Celsius => value + 273.15,\n            TemperatureUnit::Fahrenheit => (value + 459.67) * 5.0 / 9.0,\n            TemperatureUnit::Rankine => value * 5.0 / 9.0,\n            TemperatureUnit::Delisle => 373.15 - value * 2.0 / 3.0,\n            TemperatureUnit::Newton => value * 100.0 / 33.0 + 273.15,\n            TemperatureUnit::Reaumur => value * 5.0 / 4.0 + 273.15,\n            TemperatureUnit::Romer => (value - 7.5) * 40.0 / 21.0 + 273.15,\n        }\n    }\n\n    fn kelvin_to_unit(self, kelvin: f64) -> f64 {\n        match self {\n            TemperatureUnit::Kelvin => kelvin,\n            TemperatureUnit::Celsius => kelvin - 273.15,\n            TemperatureUnit::Fahrenheit => kelvin * 9.0 / 5.0 - 459.67,\n            TemperatureUnit::Rankine => kelvin * 9.0 / 5.0,\n            TemperatureUnit::Delisle => (373.15 - kelvin) * 3.0 / 2.0,\n            TemperatureUnit::Newton => (kelvin - 273.15) * 33.0 / 100.0,\n            TemperatureUnit::Reaumur => (kelvin - 273.15) * 4.0 / 5.0,\n            TemperatureUnit::Romer => (kelvin - 273.15) * 21.0 / 40.0 + 7.5,\n        }\n    }\n}\n\npub fn convert_temperature(value: f64, from: TemperatureUnit, to: TemperatureUnit) -> f64 {\n    let kelvin = from.to_kelvin(value);\n    to.kelvin_to_unit(kelvin)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    const EPSILON: f64 = 1e-10;\n\n    fn approx_eq(a: f64, b: f64) -> bool {\n        (a - b).abs() < EPSILON\n    }\n\n    #[test]\n    fn test_celsius_conversions() {\n        assert!(approx_eq(\n            convert_temperature(0.0, TemperatureUnit::Celsius, TemperatureUnit::Fahrenheit),\n            32.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(100.0, TemperatureUnit::Celsius, TemperatureUnit::Fahrenheit),\n            212.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(0.0, TemperatureUnit::Celsius, TemperatureUnit::Kelvin),\n            273.15\n        ));\n        assert!(approx_eq(\n            convert_temperature(0.0, TemperatureUnit::Celsius, TemperatureUnit::Rankine),\n            491.67\n        ));\n        assert!(approx_eq(\n            convert_temperature(0.0, TemperatureUnit::Celsius, TemperatureUnit::Delisle),\n            150.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(0.0, TemperatureUnit::Celsius, TemperatureUnit::Newton),\n            0.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(0.0, TemperatureUnit::Celsius, TemperatureUnit::Reaumur),\n            0.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(0.0, TemperatureUnit::Celsius, TemperatureUnit::Romer),\n            7.5\n        ));\n    }\n\n    #[test]\n    fn test_fahrenheit_conversions() {\n        assert!(approx_eq(\n            convert_temperature(32.0, TemperatureUnit::Fahrenheit, TemperatureUnit::Celsius),\n            0.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(212.0, TemperatureUnit::Fahrenheit, TemperatureUnit::Celsius),\n            100.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(32.0, TemperatureUnit::Fahrenheit, TemperatureUnit::Kelvin),\n            273.15\n        ));\n        assert!(approx_eq(\n            convert_temperature(32.0, TemperatureUnit::Fahrenheit, TemperatureUnit::Rankine),\n            491.67\n        ));\n    }\n\n    #[test]\n    fn test_kelvin_conversions() {\n        assert!(approx_eq(\n            convert_temperature(273.15, TemperatureUnit::Kelvin, TemperatureUnit::Celsius),\n            0.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(273.15, TemperatureUnit::Kelvin, TemperatureUnit::Fahrenheit),\n            32.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(273.15, TemperatureUnit::Kelvin, TemperatureUnit::Rankine),\n            491.67\n        ));\n    }\n\n    #[test]\n    fn test_round_trip_conversions() {\n        let temp = 25.0;\n        let units = [\n            TemperatureUnit::Celsius,\n            TemperatureUnit::Fahrenheit,\n            TemperatureUnit::Kelvin,\n            TemperatureUnit::Rankine,\n            TemperatureUnit::Delisle,\n            TemperatureUnit::Newton,\n            TemperatureUnit::Reaumur,\n            TemperatureUnit::Romer,\n        ];\n\n        for from_unit in units.iter() {\n            for to_unit in units.iter() {\n                let converted = convert_temperature(temp, *from_unit, *to_unit);\n                let back = convert_temperature(converted, *to_unit, *from_unit);\n                assert!(\n                    approx_eq(back, temp),\n                    \"Round trip failed: {from_unit:?} -> {to_unit:?} -> {from_unit:?}: {back} != {temp}\"\n                );\n            }\n        }\n    }\n\n    #[test]\n    fn test_special_temperatures() {\n        // Absolute zero\n        assert!(approx_eq(\n            convert_temperature(0.0, TemperatureUnit::Kelvin, TemperatureUnit::Celsius),\n            -273.15\n        ));\n        assert!(approx_eq(\n            convert_temperature(0.0, TemperatureUnit::Kelvin, TemperatureUnit::Fahrenheit),\n            -459.67\n        ));\n\n        // Water freezing point\n        assert!(approx_eq(\n            convert_temperature(0.0, TemperatureUnit::Celsius, TemperatureUnit::Fahrenheit),\n            32.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(0.0, TemperatureUnit::Celsius, TemperatureUnit::Kelvin),\n            273.15\n        ));\n\n        // Water boiling point\n        assert!(approx_eq(\n            convert_temperature(100.0, TemperatureUnit::Celsius, TemperatureUnit::Fahrenheit),\n            212.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(100.0, TemperatureUnit::Celsius, TemperatureUnit::Kelvin),\n            373.15\n        ));\n\n        // Celsius equals Fahrenheit\n        assert!(approx_eq(\n            convert_temperature(-40.0, TemperatureUnit::Celsius, TemperatureUnit::Fahrenheit),\n            -40.0\n        ));\n    }\n\n    #[test]\n    fn test_historical_scales() {\n        // Delisle (inverted scale)\n        assert!(approx_eq(\n            convert_temperature(100.0, TemperatureUnit::Celsius, TemperatureUnit::Delisle),\n            0.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(0.0, TemperatureUnit::Delisle, TemperatureUnit::Celsius),\n            100.0\n        ));\n\n        // Newton scale\n        assert!(approx_eq(\n            convert_temperature(100.0, TemperatureUnit::Celsius, TemperatureUnit::Newton),\n            33.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(33.0, TemperatureUnit::Newton, TemperatureUnit::Celsius),\n            100.0\n        ));\n\n        // Rømer scale\n        assert!(approx_eq(\n            convert_temperature(100.0, TemperatureUnit::Celsius, TemperatureUnit::Romer),\n            60.0\n        ));\n        assert!(approx_eq(\n            convert_temperature(60.0, TemperatureUnit::Romer, TemperatureUnit::Celsius),\n            100.0\n        ));\n    }\n\n    #[test]\n    fn test_same_unit_conversion() {\n        let temp = 42.0;\n        for unit in [\n            TemperatureUnit::Celsius,\n            TemperatureUnit::Fahrenheit,\n            TemperatureUnit::Kelvin,\n            TemperatureUnit::Rankine,\n            TemperatureUnit::Delisle,\n            TemperatureUnit::Newton,\n            TemperatureUnit::Reaumur,\n            TemperatureUnit::Romer,\n        ] {\n            assert!(approx_eq(convert_temperature(temp, unit, unit), temp));\n        }\n    }\n}\n"
  },
  {
    "path": "src/conversions/time.rs",
    "content": "//! # Time Unit Conversion\n//!\n//! A unit of time is any particular time interval, used as a standard way of\n//! measuring or expressing duration. The base unit of time in the International\n//! System of Units (SI), and by extension most of the Western world, is the second,\n//! defined as about 9 billion oscillations of the caesium atom.\n//!\n//! More information: <https://en.wikipedia.org/wiki/Unit_of_time>\n\n/// Supported time units for conversion\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum TimeUnit {\n    Seconds,\n    Minutes,\n    Hours,\n    Days,\n    Weeks,\n    Months,\n    Years,\n}\n\nimpl TimeUnit {\n    /// Returns the value of the time unit in seconds\n    fn to_seconds(self) -> f64 {\n        match self {\n            TimeUnit::Seconds => 1.0,\n            TimeUnit::Minutes => 60.0,\n            TimeUnit::Hours => 3600.0,\n            TimeUnit::Days => 86400.0,\n            TimeUnit::Weeks => 604800.0,\n            TimeUnit::Months => 2_629_800.0, // Approximate value\n            TimeUnit::Years => 31_557_600.0, // Approximate value\n        }\n    }\n\n    /// Parse a string into a TimeUnit (case-insensitive)\n    fn from_str(s: &str) -> Result<Self, String> {\n        match s.to_lowercase().as_str() {\n            \"seconds\" => Ok(TimeUnit::Seconds),\n            \"minutes\" => Ok(TimeUnit::Minutes),\n            \"hours\" => Ok(TimeUnit::Hours),\n            \"days\" => Ok(TimeUnit::Days),\n            \"weeks\" => Ok(TimeUnit::Weeks),\n            \"months\" => Ok(TimeUnit::Months),\n            \"years\" => Ok(TimeUnit::Years),\n            _ => Err(format!(\n                \"Invalid unit {s} is not in seconds, minutes, hours, days, weeks, months, years.\"\n            )),\n        }\n    }\n}\n\n/// Convert time from one unit to another\n///\n/// # Arguments\n///\n/// * `time_value` - The time value to convert (must be non-negative)\n/// * `unit_from` - The source unit (case-insensitive)\n/// * `unit_to` - The target unit (case-insensitive)\n///\n/// # Returns\n///\n/// Returns the converted time value rounded to 3 decimal places\n///\n/// # Errors\n///\n/// Returns an error if:\n/// * `time_value` is negative or not a valid number\n/// * `unit_from` or `unit_to` is not a valid time unit\npub fn convert_time(time_value: f64, unit_from: &str, unit_to: &str) -> Result<f64, String> {\n    // Validate that time_value is non-negative\n    if time_value < 0.0 || time_value.is_nan() || time_value.is_infinite() {\n        return Err(\"'time_value' must be a non-negative number.\".to_string());\n    }\n\n    // Parse units\n    let from_unit = TimeUnit::from_str(unit_from)?;\n    let to_unit = TimeUnit::from_str(unit_to)?;\n\n    // Convert: time_value -> seconds -> target unit\n    let seconds = time_value * from_unit.to_seconds();\n    let result = seconds / to_unit.to_seconds();\n\n    // Round to 3 decimal places\n    Ok((result * 1000.0).round() / 1000.0)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_seconds_to_hours() {\n        assert_eq!(convert_time(3600.0, \"seconds\", \"hours\").unwrap(), 1.0);\n    }\n\n    #[test]\n    fn test_case_insensitive() {\n        assert_eq!(convert_time(3500.0, \"Seconds\", \"Hours\").unwrap(), 0.972);\n        assert_eq!(convert_time(1.0, \"DaYs\", \"hours\").unwrap(), 24.0);\n        assert_eq!(convert_time(120.0, \"minutes\", \"SeCoNdS\").unwrap(), 7200.0);\n    }\n\n    #[test]\n    fn test_weeks_to_days() {\n        assert_eq!(convert_time(2.0, \"WEEKS\", \"days\").unwrap(), 14.0);\n    }\n\n    #[test]\n    fn test_hours_to_minutes() {\n        assert_eq!(convert_time(0.5, \"hours\", \"MINUTES\").unwrap(), 30.0);\n    }\n\n    #[test]\n    fn test_days_to_months() {\n        assert_eq!(convert_time(360.0, \"days\", \"months\").unwrap(), 11.828);\n    }\n\n    #[test]\n    fn test_months_to_years() {\n        assert_eq!(convert_time(360.0, \"months\", \"years\").unwrap(), 30.0);\n    }\n\n    #[test]\n    fn test_years_to_seconds() {\n        assert_eq!(convert_time(1.0, \"years\", \"seconds\").unwrap(), 31_557_600.0);\n    }\n\n    #[test]\n    fn test_negative_value() {\n        let result = convert_time(-3600.0, \"seconds\", \"hours\");\n        assert!(result.is_err());\n        assert_eq!(\n            result.unwrap_err(),\n            \"'time_value' must be a non-negative number.\"\n        );\n    }\n\n    #[test]\n    fn test_invalid_from_unit() {\n        let result = convert_time(1.0, \"cool\", \"century\");\n        assert!(result.is_err());\n        assert!(result.unwrap_err().contains(\"Invalid unit cool\"));\n    }\n\n    #[test]\n    fn test_invalid_to_unit() {\n        let result = convert_time(1.0, \"seconds\", \"hot\");\n        assert!(result.is_err());\n        assert!(result.unwrap_err().contains(\"Invalid unit hot\"));\n    }\n\n    #[test]\n    fn test_zero_value() {\n        assert_eq!(convert_time(0.0, \"hours\", \"minutes\").unwrap(), 0.0);\n    }\n\n    #[test]\n    fn test_same_unit() {\n        assert_eq!(convert_time(100.0, \"seconds\", \"seconds\").unwrap(), 100.0);\n    }\n}\n"
  },
  {
    "path": "src/conversions/volume.rs",
    "content": "//! Convert between different units of volume\n//!\n//! Supports conversions between various volume units using cubic meters as an intermediary:\n//! - Metric: cubic meter, cubic centimeter, cubic millimeter, liter, milliliter, centiliter, deciliter, kiloliter, hectoliter\n//! - Imperial: gallon, quart, pint, fluid ounce, tablespoon, teaspoon, barrel\n//! - US Customary: gallon, quart (liquid/dry), pint (liquid/dry), cup, fluid ounce, tablespoon, teaspoon, barrel (oil/liquid)\n//! - Cubic: cubic yard, cubic foot, cubic inch\n//! - Other: board foot, cord, metric cup, Canadian tablespoon/teaspoon\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum VolumeUnit {\n    // Metric units\n    CubicMeter,\n    CubicCentimeter,\n    CubicMillimeter,\n    Liter,\n    Milliliter,\n    Centiliter,\n    Deciliter,\n    Kiloliter,\n    Hectoliter,\n\n    // Imperial units\n    GallonImperial,\n    QuartImperial,\n    PintImperial,\n    FluidOunceImperial,\n    TablespoonImperial,\n    TeaspoonImperial,\n    BarrelImperial,\n\n    // US customary units (liquid)\n    GallonUs,\n    QuartUsLiquid,\n    PintUsLiquid,\n    CupUs,\n    FluidOunceUs,\n    TablespoonUs,\n    TeaspoonUs,\n\n    // US customary units (dry)\n    QuartUsDry,\n    PintUsDry,\n\n    // US barrels\n    BarrelUsOil,\n    BarrelUsLiquid,\n\n    // Cubic units\n    CubicYard,\n    CubicFoot,\n    CubicInch,\n\n    // Other units\n    BoardFoot,\n    Cord,\n    CupMetric,\n    TablespoonCanadian,\n    TeaspoonCanadian,\n}\n\nimpl VolumeUnit {\n    /// Convert from this unit to cubic meters\n    fn to_cubic_meters(self, value: f64) -> f64 {\n        let factor = match self {\n            // Metric units - merge identical values\n            VolumeUnit::CubicMeter | VolumeUnit::Kiloliter => 1.0,\n            VolumeUnit::CubicCentimeter | VolumeUnit::Milliliter => 1e-6,\n            VolumeUnit::CubicMillimeter => 1e-9,\n            VolumeUnit::Liter => 0.001,\n            VolumeUnit::Centiliter => 1e-5,\n            VolumeUnit::Deciliter => 1e-4,\n            VolumeUnit::Hectoliter => 0.1,\n\n            // Imperial units\n            VolumeUnit::GallonImperial => 0.00454609,\n            VolumeUnit::QuartImperial => 0.0011365225,\n            VolumeUnit::PintImperial => 0.00056826125,\n            VolumeUnit::FluidOunceImperial => 2.84130625e-5,\n            VolumeUnit::TablespoonImperial => 1.7758164e-5,\n            VolumeUnit::TeaspoonImperial => 5.919388e-6,\n            VolumeUnit::BarrelImperial => 0.16365924,\n\n            // US customary units (liquid)\n            VolumeUnit::GallonUs => 0.003785411784,\n            VolumeUnit::QuartUsLiquid => 0.000946352946,\n            VolumeUnit::PintUsLiquid => 0.000473176473,\n            VolumeUnit::CupUs => 0.0002365882365,\n            VolumeUnit::FluidOunceUs => 2.95735295625e-5,\n            VolumeUnit::TablespoonUs => 1.47867647813e-5,\n            VolumeUnit::TeaspoonUs => 4.92892159375e-6,\n\n            // US customary units (dry)\n            VolumeUnit::QuartUsDry => 0.00110122095,\n            VolumeUnit::PintUsDry => 0.0005506104713575,\n\n            // US barrels\n            VolumeUnit::BarrelUsOil => 0.158987294928,\n            VolumeUnit::BarrelUsLiquid => 0.119240471196,\n\n            // Cubic units\n            VolumeUnit::CubicYard => 0.764554857984,\n            VolumeUnit::CubicFoot => 0.028316846592,\n            VolumeUnit::CubicInch => 1.6387064e-5,\n\n            // Other units\n            VolumeUnit::BoardFoot => 0.002359737216,\n            VolumeUnit::Cord => 3.624556363776,\n            VolumeUnit::CupMetric => 0.00025,\n            VolumeUnit::TablespoonCanadian => 1.4206526e-5,\n            VolumeUnit::TeaspoonCanadian => 4.73550833e-6,\n        };\n\n        value * factor\n    }\n\n    /// Convert from cubic meters to this unit\n    fn cubic_meters_to_unit(self, cubic_meters: f64) -> f64 {\n        let factor = match self {\n            // Metric units - merge identical values\n            VolumeUnit::CubicMeter | VolumeUnit::Kiloliter => 1.0,\n            VolumeUnit::CubicCentimeter | VolumeUnit::Milliliter => 1e-6,\n            VolumeUnit::CubicMillimeter => 1e-9,\n            VolumeUnit::Liter => 0.001,\n            VolumeUnit::Centiliter => 1e-5,\n            VolumeUnit::Deciliter => 1e-4,\n            VolumeUnit::Hectoliter => 0.1,\n\n            // Imperial units\n            VolumeUnit::GallonImperial => 0.00454609,\n            VolumeUnit::QuartImperial => 0.0011365225,\n            VolumeUnit::PintImperial => 0.00056826125,\n            VolumeUnit::FluidOunceImperial => 2.84130625e-5,\n            VolumeUnit::TablespoonImperial => 1.7758164e-5,\n            VolumeUnit::TeaspoonImperial => 5.919388e-6,\n            VolumeUnit::BarrelImperial => 0.16365924,\n\n            // US customary units (liquid)\n            VolumeUnit::GallonUs => 0.003785411784,\n            VolumeUnit::QuartUsLiquid => 0.000946352946,\n            VolumeUnit::PintUsLiquid => 0.000473176473,\n            VolumeUnit::CupUs => 0.0002365882365,\n            VolumeUnit::FluidOunceUs => 2.95735295625e-5,\n            VolumeUnit::TablespoonUs => 1.47867647813e-5,\n            VolumeUnit::TeaspoonUs => 4.92892159375e-6,\n\n            // US customary units (dry)\n            VolumeUnit::QuartUsDry => 0.00110122095,\n            VolumeUnit::PintUsDry => 0.0005506104713575,\n\n            // US barrels\n            VolumeUnit::BarrelUsOil => 0.158987294928,\n            VolumeUnit::BarrelUsLiquid => 0.119240471196,\n\n            // Cubic units\n            VolumeUnit::CubicYard => 0.764554857984,\n            VolumeUnit::CubicFoot => 0.028316846592,\n            VolumeUnit::CubicInch => 1.6387064e-5,\n\n            // Other units\n            VolumeUnit::BoardFoot => 0.002359737216,\n            VolumeUnit::Cord => 3.624556363776,\n            VolumeUnit::CupMetric => 0.00025,\n            VolumeUnit::TablespoonCanadian => 1.4206526e-5,\n            VolumeUnit::TeaspoonCanadian => 4.73550833e-6,\n        };\n\n        cubic_meters / factor\n    }\n}\n\n/// Convert a volume value from one unit to another\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::conversions::{convert_volume, VolumeUnit};\n///\n/// let liters = convert_volume(1.0, VolumeUnit::CubicMeter, VolumeUnit::Liter);\n/// assert_eq!(liters, 1000.0);\n///\n/// let gallons = convert_volume(1.0, VolumeUnit::Liter, VolumeUnit::GallonUs);\n/// assert!((gallons - 0.264172).abs() < 0.0001);\n/// ```\npub fn convert_volume(value: f64, from: VolumeUnit, to: VolumeUnit) -> f64 {\n    let cubic_meters = from.to_cubic_meters(value);\n    to.cubic_meters_to_unit(cubic_meters)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    const EPSILON: f64 = 1e-9;\n\n    fn approx_eq(a: f64, b: f64, tolerance: f64) -> bool {\n        (a - b).abs() < tolerance\n    }\n\n    #[test]\n    fn test_volume_conversions() {\n        // Metric conversions\n        assert_eq!(\n            convert_volume(4.0, VolumeUnit::CubicMeter, VolumeUnit::Liter),\n            4000.0\n        );\n        assert_eq!(\n            convert_volume(1000.0, VolumeUnit::Milliliter, VolumeUnit::Liter),\n            1.0\n        );\n        assert_eq!(\n            convert_volume(1.0, VolumeUnit::CubicCentimeter, VolumeUnit::Milliliter),\n            1.0\n        );\n        assert_eq!(\n            convert_volume(1.0, VolumeUnit::Kiloliter, VolumeUnit::CubicMeter),\n            1.0\n        );\n        assert_eq!(\n            convert_volume(100.0, VolumeUnit::Centiliter, VolumeUnit::Liter),\n            1.0\n        );\n        assert_eq!(\n            convert_volume(10.0, VolumeUnit::Deciliter, VolumeUnit::Liter),\n            1.0\n        );\n        assert_eq!(\n            convert_volume(10.0, VolumeUnit::Hectoliter, VolumeUnit::CubicMeter),\n            1.0\n        );\n\n        // Imperial conversions\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::GallonImperial, VolumeUnit::Liter),\n            4.54609,\n            0.001\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::PintImperial, VolumeUnit::Milliliter),\n            568.261,\n            0.1\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::FluidOunceImperial, VolumeUnit::Milliliter),\n            28.413,\n            0.01\n        ));\n        assert!(approx_eq(\n            convert_volume(4.0, VolumeUnit::QuartImperial, VolumeUnit::GallonImperial),\n            1.0,\n            0.001\n        ));\n        assert!(approx_eq(\n            convert_volume(\n                20.0,\n                VolumeUnit::FluidOunceImperial,\n                VolumeUnit::PintImperial\n            ),\n            1.0,\n            0.001\n        ));\n\n        // US customary liquid conversions\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::GallonUs, VolumeUnit::Liter),\n            3.785,\n            0.001\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::PintUsLiquid, VolumeUnit::Milliliter),\n            473.176,\n            0.01\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::CupUs, VolumeUnit::Milliliter),\n            236.588,\n            0.01\n        ));\n        assert!(approx_eq(\n            convert_volume(16.0, VolumeUnit::TablespoonUs, VolumeUnit::CupUs),\n            1.0,\n            EPSILON\n        ));\n        assert!(approx_eq(\n            convert_volume(3.0, VolumeUnit::TeaspoonUs, VolumeUnit::TablespoonUs),\n            1.0,\n            EPSILON\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::FluidOunceUs, VolumeUnit::Milliliter),\n            29.574,\n            0.01\n        ));\n        assert!(approx_eq(\n            convert_volume(4.0, VolumeUnit::QuartUsLiquid, VolumeUnit::GallonUs),\n            1.0,\n            0.001\n        ));\n        assert!(approx_eq(\n            convert_volume(2.0, VolumeUnit::PintUsLiquid, VolumeUnit::QuartUsLiquid),\n            1.0,\n            0.001\n        ));\n        assert!(approx_eq(\n            convert_volume(2.0, VolumeUnit::CupUs, VolumeUnit::PintUsLiquid),\n            1.0,\n            EPSILON\n        ));\n        assert!(approx_eq(\n            convert_volume(8.0, VolumeUnit::FluidOunceUs, VolumeUnit::CupUs),\n            1.0,\n            0.001\n        ));\n\n        // US dry conversions\n        assert!(approx_eq(\n            convert_volume(2.0, VolumeUnit::PintUsDry, VolumeUnit::QuartUsDry),\n            1.0,\n            0.001\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::QuartUsDry, VolumeUnit::Liter),\n            1.101,\n            0.001\n        ));\n\n        // Cubic units\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::CubicFoot, VolumeUnit::Liter),\n            28.317,\n            0.01\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::CubicYard, VolumeUnit::CubicMeter),\n            0.764555,\n            0.0001\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::CubicInch, VolumeUnit::Milliliter),\n            16.387,\n            0.01\n        ));\n        assert!(approx_eq(\n            convert_volume(27.0, VolumeUnit::CubicFoot, VolumeUnit::CubicYard),\n            1.0,\n            0.001\n        ));\n        assert!(approx_eq(\n            convert_volume(1728.0, VolumeUnit::CubicInch, VolumeUnit::CubicFoot),\n            1.0,\n            0.1\n        ));\n\n        // Mixed imperial/US conversions\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::GallonImperial, VolumeUnit::GallonUs),\n            1.20095,\n            0.001\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::PintImperial, VolumeUnit::PintUsLiquid),\n            1.20095,\n            0.001\n        ));\n        assert!(approx_eq(\n            convert_volume(\n                1.0,\n                VolumeUnit::FluidOunceImperial,\n                VolumeUnit::FluidOunceUs\n            ),\n            0.96076,\n            0.001\n        ));\n\n        // Barrel conversions\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::BarrelUsOil, VolumeUnit::Liter),\n            158.987,\n            0.01\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::BarrelUsOil, VolumeUnit::GallonUs),\n            42.0,\n            0.01\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::BarrelUsLiquid, VolumeUnit::GallonUs),\n            31.5,\n            0.1\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::BarrelImperial, VolumeUnit::GallonImperial),\n            36.0,\n            0.1\n        ));\n\n        // Other units\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::Cord, VolumeUnit::CubicMeter),\n            3.62456,\n            0.001\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::BoardFoot, VolumeUnit::CubicFoot),\n            0.08333,\n            0.001\n        ));\n\n        // Metric cup\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::CupMetric, VolumeUnit::Milliliter),\n            250.0,\n            0.01\n        ));\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::CupUs, VolumeUnit::CupMetric),\n            0.9464,\n            0.001\n        ));\n\n        // Canadian units\n        assert!(approx_eq(\n            convert_volume(1.0, VolumeUnit::TablespoonCanadian, VolumeUnit::Milliliter),\n            14.207,\n            0.01\n        ));\n        assert!(approx_eq(\n            convert_volume(\n                3.0,\n                VolumeUnit::TeaspoonCanadian,\n                VolumeUnit::TablespoonCanadian\n            ),\n            1.0,\n            0.001\n        ));\n\n        // Edge cases - converting to same unit\n        assert!(approx_eq(\n            convert_volume(5.0, VolumeUnit::Liter, VolumeUnit::Liter),\n            5.0,\n            EPSILON\n        ));\n        assert!(approx_eq(\n            convert_volume(10.0, VolumeUnit::GallonUs, VolumeUnit::GallonUs),\n            10.0,\n            EPSILON\n        ));\n\n        // Large values\n        assert!(approx_eq(\n            convert_volume(1000.0, VolumeUnit::CubicMeter, VolumeUnit::Liter),\n            1_000_000.0,\n            0.1\n        ));\n\n        // Small values\n        assert!(approx_eq(\n            convert_volume(0.001, VolumeUnit::Milliliter, VolumeUnit::CubicMeter),\n            1e-9,\n            1e-12\n        ));\n    }\n\n    #[test]\n    fn test_round_trip_conversions() {\n        let volume = 5.0;\n        let units = [\n            VolumeUnit::CubicMeter,\n            VolumeUnit::Liter,\n            VolumeUnit::Milliliter,\n            VolumeUnit::GallonUs,\n            VolumeUnit::GallonImperial,\n            VolumeUnit::CupUs,\n            VolumeUnit::CubicFoot,\n            VolumeUnit::CubicYard,\n        ];\n\n        for from_unit in units.iter() {\n            for to_unit in units.iter() {\n                let converted = convert_volume(volume, *from_unit, *to_unit);\n                let back = convert_volume(converted, *to_unit, *from_unit);\n                assert!(\n                    approx_eq(back, volume, EPSILON * volume.abs().max(1.0)),\n                    \"Round trip failed: {from_unit:?} -> {to_unit:?} -> {from_unit:?}: {back} != {volume}\"\n                );\n            }\n        }\n    }\n\n    #[test]\n    fn test_same_unit_conversion() {\n        let volume = 42.0;\n        for unit in [\n            VolumeUnit::CubicMeter,\n            VolumeUnit::Liter,\n            VolumeUnit::GallonUs,\n            VolumeUnit::GallonImperial,\n            VolumeUnit::CubicFoot,\n            VolumeUnit::CupUs,\n        ] {\n            assert!(approx_eq(\n                convert_volume(volume, unit, unit),\n                volume,\n                EPSILON\n            ));\n        }\n    }\n}\n"
  },
  {
    "path": "src/conversions/weight.rs",
    "content": "//! Conversion of weight units.\n//!\n//! This module provides conversion between various weight units including:\n//! - Metric: Gigatonne (Gt), Megatonne (Mt), Metric Ton (t), Kilogram (kg), Gram (g),\n//!   Milligram (mg), Microgram (μg), Nanogram (ng), Picogram (pg)\n//! - Imperial/US: Long Ton, Short Ton, Hundredweight (cwt), Quarter (qtr), Stone (st),\n//!   Pound (lb), Ounce (oz), Dram (dr), Grain (gr)\n//! - Troy: Troy Pound (lb t), Troy Ounce (oz t), Pennyweight (dwt)\n//! - Other: Carat (ct), Atomic Mass Unit (amu)\n//!\n//! # References\n//! - [Kilogram](https://en.wikipedia.org/wiki/Kilogram)\n//! - [Gram](https://en.wikipedia.org/wiki/Gram)\n//! - [Milligram](https://en.wikipedia.org/wiki/Milligram)\n//! - [Microgram](https://en.wikipedia.org/wiki/Microgram)\n//! - [Nanogram](https://en.wikipedia.org/wiki/Orders_of_magnitude_(mass))\n//! - [Picogram](https://en.wikipedia.org/wiki/Orders_of_magnitude_(mass))\n//! - [Tonne](https://en.wikipedia.org/wiki/Tonne)\n//! - [Gigatonne](https://en.wikipedia.org/wiki/Tonne#Derived_units)\n//! - [Megatonne](https://en.wikipedia.org/wiki/Tonne#Derived_units)\n//! - [Long Ton](https://en.wikipedia.org/wiki/Long_ton)\n//! - [Short Ton](https://en.wikipedia.org/wiki/Short_ton)\n//! - [Pound](https://en.wikipedia.org/wiki/Pound_(mass))\n//! - [Ounce](https://en.wikipedia.org/wiki/Ounce)\n//! - [Stone](https://en.wikipedia.org/wiki/Stone_(unit))\n//! - [Quarter](https://en.wikipedia.org/wiki/Quarter_(unit))\n//! - [Hundredweight](https://en.wikipedia.org/wiki/Hundredweight)\n//! - [Grain](https://en.wikipedia.org/wiki/Grain_(unit))\n//! - [Dram](https://en.wikipedia.org/wiki/Dram_(unit))\n//! - [Troy Pound](https://en.wikipedia.org/wiki/Troy_weight)\n//! - [Troy Ounce](https://en.wikipedia.org/wiki/Troy_weight)\n//! - [Pennyweight](https://en.wikipedia.org/wiki/Pennyweight)\n//! - [Carat](https://en.wikipedia.org/wiki/Carat_(mass))\n//! - [Dalton (Atomic Mass Unit)](https://en.wikipedia.org/wiki/Dalton_(unit))\n\nuse std::fmt;\nuse std::str::FromStr;\n\n/// Trait for types that can be converted into a WeightUnit\npub trait IntoWeightUnit {\n    fn into_weight_unit(self) -> Result<WeightUnit, String>;\n}\n\nimpl IntoWeightUnit for WeightUnit {\n    fn into_weight_unit(self) -> Result<WeightUnit, String> {\n        Ok(self)\n    }\n}\n\nimpl IntoWeightUnit for &str {\n    fn into_weight_unit(self) -> Result<WeightUnit, String> {\n        WeightUnit::from_str(self)\n    }\n}\n\nimpl IntoWeightUnit for String {\n    fn into_weight_unit(self) -> Result<WeightUnit, String> {\n        WeightUnit::from_str(&self)\n    }\n}\n\n/// Supported weight units\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum WeightUnit {\n    // Large metric units\n    Gigatonne,\n    Megatonne,\n    MetricTon,\n\n    // Standard metric units\n    Kilogram,\n    Gram,\n    Milligram,\n    Microgram,\n    Nanogram,\n    Picogram,\n\n    // Imperial/US tons and large units\n    LongTon,\n    ShortTon,\n    Hundredweight,\n    Quarter,\n\n    // Imperial/US common units\n    Stone,\n    Pound,\n    Ounce,\n    Dram,\n    Grain,\n\n    // Troy weight system\n    TroyPound,\n    TroyOunce,\n    Pennyweight,\n\n    // Other units\n    Carat,\n    AtomicMassUnit,\n}\n\nimpl fmt::Display for WeightUnit {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let s = match self {\n            // Large metric units\n            Self::Gigatonne => \"Gt\",\n            Self::Megatonne => \"Mt\",\n            Self::MetricTon => \"t\",\n\n            // Standard metric units\n            Self::Kilogram => \"kg\",\n            Self::Gram => \"g\",\n            Self::Milligram => \"mg\",\n            Self::Microgram => \"μg\",\n            Self::Nanogram => \"ng\",\n            Self::Picogram => \"pg\",\n\n            // Imperial/US tons and large units\n            Self::LongTon => \"long ton\",\n            Self::ShortTon => \"short ton\",\n            Self::Hundredweight => \"cwt\",\n            Self::Quarter => \"qtr\",\n\n            // Imperial/US common units\n            Self::Stone => \"st\",\n            Self::Pound => \"lb\",\n            Self::Ounce => \"oz\",\n            Self::Dram => \"dr\",\n            Self::Grain => \"gr\",\n\n            // Troy weight system\n            Self::TroyPound => \"lb t\",\n            Self::TroyOunce => \"oz t\",\n            Self::Pennyweight => \"dwt\",\n\n            // Other units\n            Self::Carat => \"ct\",\n            Self::AtomicMassUnit => \"amu\",\n        };\n        write!(f, \"{s}\")\n    }\n}\n\nimpl WeightUnit {\n    /// Get the conversion factor to convert this unit to kilograms\n    fn to_kilogram_factor(self) -> f64 {\n        match self {\n            // Large metric units\n            Self::Gigatonne => 1e12,\n            Self::Megatonne => 1e9,\n            Self::MetricTon => 1_000.0,\n\n            // Standard metric units (based on 1 kg = 1000 g)\n            Self::Kilogram => 1.0,\n            Self::Gram => 1e-3,\n            Self::Milligram => 1e-6,\n            Self::Microgram => 1e-9,\n            Self::Nanogram => 1e-12,\n            Self::Picogram => 1e-15,\n\n            // Imperial/US tons and large units\n            // Using precise values: 1 lb = 0.45359237 kg exactly (international avoirdupois pound)\n            Self::LongTon => 1_016.046_908_8, // 2240 lb × 0.45359237 kg/lb\n            Self::ShortTon => 907.184_74,     // 2000 lb × 0.45359237 kg/lb\n            Self::Hundredweight => 50.802_345_44, // 112 lb × 0.45359237 kg/lb\n            Self::Quarter => 12.700_586_36,   // 28 lb × 0.45359237 kg/lb\n\n            // Imperial/US common units (based on 1 lb = 0.45359237 kg exactly)\n            Self::Stone => 6.350_293_18,      // 14 lb × 0.45359237 kg/lb\n            Self::Pound => 0.453_592_37,      // Exactly defined\n            Self::Ounce => 0.028_349_523_125, // 1/16 lb\n            Self::Dram => 0.001_771_845_195_312_5, // 1/256 lb\n            Self::Grain => 0.000_064_798_91,  // 1/7000 lb\n\n            // Troy weight system (1 troy lb = 0.3732417216 kg exactly)\n            Self::TroyPound => 0.373_241_721_6, // Exactly defined\n            Self::TroyOunce => 0.031_103_476_8, // 1/12 troy lb\n            Self::Pennyweight => 0.001_555_173_84, // 1/240 troy lb\n\n            // Other units\n            Self::Carat => 0.000_2,                       // Exactly 200 mg\n            Self::AtomicMassUnit => 1.660_539_066_60e-27, // 2019 CODATA value\n        }\n    }\n\n    /// Get all supported units as strings\n    pub fn supported_units() -> Vec<&'static str> {\n        vec![\n            \"gigatonne\",\n            \"megatonne\",\n            \"metric-ton\",\n            \"kilogram\",\n            \"gram\",\n            \"milligram\",\n            \"microgram\",\n            \"nanogram\",\n            \"picogram\",\n            \"long-ton\",\n            \"short-ton\",\n            \"hundredweight\",\n            \"quarter\",\n            \"stone\",\n            \"pound\",\n            \"ounce\",\n            \"dram\",\n            \"grain\",\n            \"troy-pound\",\n            \"troy-ounce\",\n            \"pennyweight\",\n            \"carat\",\n            \"atomic-mass-unit\",\n        ]\n    }\n}\n\nimpl FromStr for WeightUnit {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let unit = match s.to_lowercase().as_str() {\n            // Large metric units\n            \"gigatonne\" | \"gt\" | \"gigaton\" => Self::Gigatonne,\n            \"megatonne\" | \"mt\" | \"megaton\" => Self::Megatonne,\n            \"metric-ton\" | \"metric_ton\" | \"tonne\" | \"t\" | \"ton\" => Self::MetricTon,\n\n            // Standard metric units\n            \"kilogram\" | \"kg\" | \"kilo\" => Self::Kilogram,\n            \"gram\" | \"g\" | \"gm\" => Self::Gram,\n            \"milligram\" | \"mg\" => Self::Milligram,\n            \"microgram\" | \"μg\" | \"ug\" | \"mcg\" => Self::Microgram,\n            \"nanogram\" | \"ng\" => Self::Nanogram,\n            \"picogram\" | \"pg\" => Self::Picogram,\n\n            // Imperial/US tons and large units\n            \"long-ton\" | \"long_ton\" | \"imperial_ton\" | \"uk_ton\" => Self::LongTon,\n            \"short-ton\" | \"short_ton\" | \"us_ton\" => Self::ShortTon,\n            \"hundredweight\" | \"cwt\" => Self::Hundredweight,\n            \"quarter\" | \"qtr\" => Self::Quarter,\n\n            // Imperial/US common units\n            \"stone\" | \"st\" => Self::Stone,\n            \"pound\" | \"lb\" | \"lbs\" => Self::Pound,\n            \"ounce\" | \"oz\" => Self::Ounce,\n            \"dram\" | \"drachm\" | \"dr\" => Self::Dram,\n            \"grain\" | \"gr\" => Self::Grain,\n\n            // Troy weight system\n            \"troy-pound\" | \"troy_pound\" | \"lb_t\" | \"lbt\" => Self::TroyPound,\n            \"troy-ounce\" | \"troy_ounce\" | \"oz_t\" | \"ozt\" => Self::TroyOunce,\n            \"pennyweight\" | \"dwt\" | \"pwt\" => Self::Pennyweight,\n\n            // Other units\n            \"carat\" | \"carrat\" | \"ct\" => Self::Carat,\n            \"atomic-mass-unit\" | \"atomic_mass_unit\" | \"amu\" | \"dalton\" | \"da\" => {\n                Self::AtomicMassUnit\n            }\n            _ => return Err(format!(\"Unknown weight unit: {s}\")),\n        };\n        Ok(unit)\n    }\n}\n\n/// Convert weight from one unit to another.\n///\n/// This function accepts both `WeightUnit` enums and string identifiers.\n///\n/// # Arguments\n///\n/// * `value` - The numerical value to convert\n/// * `from_unit` - The unit to convert from (can be a `WeightUnit` enum or a string)\n/// * `to_unit` - The unit to convert to (can be a `WeightUnit` enum or a string)\n///\n/// # Returns\n///\n/// The converted value, or an error if the unit is invalid\n///\n/// # Examples\n///\n/// Using enums (type-safe):\n/// ```ignore\n/// let result = convert_weight(100.0, WeightUnit::Pound, WeightUnit::Kilogram);\n/// ```\n///\n/// Using strings (convenient):\n/// ```ignore\n/// let result = convert_weight(100.0, \"pound\", \"kilogram\");\n/// ```\npub fn convert_weight<F, T>(value: f64, from_unit: F, to_unit: T) -> Result<f64, String>\nwhere\n    F: IntoWeightUnit,\n    T: IntoWeightUnit,\n{\n    let from = from_unit.into_weight_unit().map_err(|_| {\n        format!(\n            \"Invalid 'from_unit' value. Supported values are:\\n{}\",\n            WeightUnit::supported_units().join(\", \")\n        )\n    })?;\n\n    let to = to_unit.into_weight_unit().map_err(|_| {\n        format!(\n            \"Invalid 'to_unit' value. Supported values are:\\n{}\",\n            WeightUnit::supported_units().join(\", \")\n        )\n    })?;\n\n    // Convert to kilograms first, then to target unit\n    let kilograms = value * from.to_kilogram_factor();\n    Ok(kilograms / to.to_kilogram_factor())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    const EPSILON: f64 = 1e-6; // Tolerance for floating point comparisons\n\n    fn approx_eq(a: f64, b: f64) -> bool {\n        let diff = (a - b).abs();\n        // Use relative comparison for large numbers, absolute for small numbers\n        if a.abs() > 1e10 || b.abs() > 1e10 {\n            let max = a.abs().max(b.abs());\n            diff / max < EPSILON\n        } else {\n            diff < EPSILON\n        }\n    }\n\n    #[test]\n    fn test_kilogram_conversions() {\n        // Test conversions from kilogram\n        assert!(approx_eq(\n            convert_weight(4.0, \"kilogram\", \"kilogram\").unwrap(),\n            4.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"kilogram\", \"gram\").unwrap(),\n            1_000.0\n        ));\n        assert!(approx_eq(\n            convert_weight(4.0, \"kilogram\", \"milligram\").unwrap(),\n            4_000_000.0\n        ));\n        assert!(approx_eq(\n            convert_weight(4.0, \"kilogram\", \"metric-ton\").unwrap(),\n            0.004\n        ));\n        assert!(approx_eq(\n            convert_weight(3.0, \"kilogram\", \"long-ton\").unwrap(),\n            0.002_952_396_2\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"kilogram\", \"short-ton\").unwrap(),\n            0.001_102_311_3\n        ));\n        assert!(approx_eq(\n            convert_weight(4.0, \"kilogram\", \"pound\").unwrap(),\n            8.818_490_487\n        ));\n        assert!(approx_eq(\n            convert_weight(5.0, \"kilogram\", \"stone\").unwrap(),\n            0.787_365_222\n        ));\n        assert!(approx_eq(\n            convert_weight(4.0, \"kilogram\", \"ounce\").unwrap(),\n            141.095_847_8\n        ));\n        assert!(approx_eq(\n            convert_weight(3.0, \"kilogram\", \"carat\").unwrap(),\n            15_000.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"kilogram\", \"atomic-mass-unit\").unwrap(),\n            6.022_140_762e26\n        ));\n    }\n\n    #[test]\n    fn test_large_metric_conversions() {\n        // Test gigatonne conversions\n        assert!(approx_eq(\n            convert_weight(1.0, \"gigatonne\", \"megatonne\").unwrap(),\n            1_000.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"gigatonne\", \"metric-ton\").unwrap(),\n            1e9\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"gigatonne\", \"kilogram\").unwrap(),\n            1e12\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"gigatonne\", \"gram\").unwrap(),\n            1e15\n        ));\n\n        // Test megatonne conversions\n        assert!(approx_eq(\n            convert_weight(1.0, \"megatonne\", \"metric-ton\").unwrap(),\n            1_000_000.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"megatonne\", \"kilogram\").unwrap(),\n            1e9\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"megatonne\", \"gram\").unwrap(),\n            1e12\n        ));\n    }\n\n    #[test]\n    fn test_gram_conversions() {\n        // Test conversions from gram\n        assert!(approx_eq(\n            convert_weight(1.0, \"gram\", \"kilogram\").unwrap(),\n            0.001\n        ));\n        assert!(approx_eq(convert_weight(3.0, \"gram\", \"gram\").unwrap(), 3.0));\n        assert!(approx_eq(\n            convert_weight(2.0, \"gram\", \"milligram\").unwrap(),\n            2_000.0\n        ));\n        assert!(approx_eq(\n            convert_weight(4.0, \"gram\", \"metric-ton\").unwrap(),\n            4e-6\n        ));\n        assert!(approx_eq(\n            convert_weight(3.0, \"gram\", \"pound\").unwrap(),\n            0.006_613_867_8\n        ));\n    }\n\n    #[test]\n    fn test_milligram_conversions() {\n        // Test conversions from milligram\n        assert!(approx_eq(\n            convert_weight(1.0, \"milligram\", \"kilogram\").unwrap(),\n            1e-6\n        ));\n        assert!(approx_eq(\n            convert_weight(2.0, \"milligram\", \"gram\").unwrap(),\n            0.002\n        ));\n        assert!(approx_eq(\n            convert_weight(3.0, \"milligram\", \"milligram\").unwrap(),\n            3.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"milligram\", \"carat\").unwrap(),\n            0.005\n        ));\n    }\n\n    #[test]\n    fn test_small_metric_conversions() {\n        // Test microgram conversions (1 μg = 0.000001 g)\n        assert!(approx_eq(\n            convert_weight(1.0, \"microgram\", \"gram\").unwrap(),\n            1e-6\n        ));\n        assert!(approx_eq(\n            convert_weight(1_000.0, \"microgram\", \"milligram\").unwrap(),\n            1.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"microgram\", \"kilogram\").unwrap(),\n            1e-9\n        ));\n\n        // Test nanogram conversions (1 ng = 0.000000001 g)\n        assert!(approx_eq(\n            convert_weight(1.0, \"nanogram\", \"gram\").unwrap(),\n            1e-9\n        ));\n        assert!(approx_eq(\n            convert_weight(1_000.0, \"nanogram\", \"microgram\").unwrap(),\n            1.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"nanogram\", \"kilogram\").unwrap(),\n            1e-12\n        ));\n\n        // Test picogram conversions (1 pg = 0.000000000001 g)\n        assert!(approx_eq(\n            convert_weight(1.0, \"picogram\", \"gram\").unwrap(),\n            1e-12\n        ));\n        assert!(approx_eq(\n            convert_weight(1_000.0, \"picogram\", \"nanogram\").unwrap(),\n            1.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"picogram\", \"kilogram\").unwrap(),\n            1e-15\n        ));\n    }\n\n    #[test]\n    fn test_metric_ton_conversions() {\n        // Test conversions from metric ton\n        assert!(approx_eq(\n            convert_weight(2.0, \"metric-ton\", \"kilogram\").unwrap(),\n            2_000.0\n        ));\n        assert!(approx_eq(\n            convert_weight(2.0, \"metric-ton\", \"gram\").unwrap(),\n            2_000_000.0\n        ));\n        assert!(approx_eq(\n            convert_weight(3.0, \"metric-ton\", \"milligram\").unwrap(),\n            3_000_000_000.0\n        ));\n        assert!(approx_eq(\n            convert_weight(2.0, \"metric-ton\", \"metric-ton\").unwrap(),\n            2.0\n        ));\n        assert!(approx_eq(\n            convert_weight(3.0, \"metric-ton\", \"pound\").unwrap(),\n            6_613.867_865\n        ));\n    }\n\n    #[test]\n    fn test_long_ton_conversions() {\n        // Test conversions from long ton (UK ton = 1016.0469088 kg precisely)\n        assert!(approx_eq(\n            convert_weight(4.0, \"long-ton\", \"kilogram\").unwrap(),\n            4_064.187_635_2\n        ));\n        assert!(approx_eq(\n            convert_weight(4.0, \"long-ton\", \"gram\").unwrap(),\n            4_064_187.635_2\n        ));\n        assert!(approx_eq(\n            convert_weight(4.0, \"long-ton\", \"metric-ton\").unwrap(),\n            4.064_187_635_2\n        ));\n        assert!(approx_eq(\n            convert_weight(3.0, \"long-ton\", \"long-ton\").unwrap(),\n            3.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"long-ton\", \"short-ton\").unwrap(),\n            1.12\n        ));\n    }\n\n    #[test]\n    fn test_imperial_large_units() {\n        // Test hundredweight (112 lb = 50.80234544 kg precisely)\n        assert!(approx_eq(\n            convert_weight(1.0, \"hundredweight\", \"kilogram\").unwrap(),\n            50.802_345_44\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"hundredweight\", \"gram\").unwrap(),\n            50_802.345_44\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"hundredweight\", \"pound\").unwrap(),\n            112.0\n        ));\n        assert!(approx_eq(\n            convert_weight(20.0, \"hundredweight\", \"long-ton\").unwrap(),\n            1.0\n        ));\n\n        // Test quarter (28 lb = 12.70058636 kg precisely)\n        assert!(approx_eq(\n            convert_weight(1.0, \"quarter\", \"kilogram\").unwrap(),\n            12.700_586_36\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"quarter\", \"gram\").unwrap(),\n            12_700.586_36\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"quarter\", \"pound\").unwrap(),\n            28.0\n        ));\n        assert!(approx_eq(\n            convert_weight(4.0, \"quarter\", \"hundredweight\").unwrap(),\n            1.0\n        ));\n    }\n\n    #[test]\n    fn test_short_ton_conversions() {\n        // Test conversions from short ton (2000 lb = 907.18474 kg precisely)\n        assert!(approx_eq(\n            convert_weight(3.0, \"short-ton\", \"kilogram\").unwrap(),\n            2_721.554_22\n        ));\n        assert!(approx_eq(\n            convert_weight(3.0, \"short-ton\", \"gram\").unwrap(),\n            2_721_554.22\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"short-ton\", \"milligram\").unwrap(),\n            907_184_740.0\n        ));\n        assert!(approx_eq(\n            convert_weight(4.0, \"short-ton\", \"metric-ton\").unwrap(),\n            3.628_738_96\n        ));\n        assert!(approx_eq(\n            convert_weight(2.0, \"short-ton\", \"pound\").unwrap(),\n            4_000.0\n        ));\n    }\n\n    #[test]\n    fn test_pound_conversions() {\n        // Test conversions from pound (0.45359237 kg exactly)\n        assert!(approx_eq(\n            convert_weight(4.0, \"pound\", \"kilogram\").unwrap(),\n            1.814_369_48\n        ));\n        assert!(approx_eq(\n            convert_weight(2.0, \"pound\", \"gram\").unwrap(),\n            907.184_74\n        ));\n        assert!(approx_eq(\n            convert_weight(3.0, \"pound\", \"milligram\").unwrap(),\n            1_360_777.11\n        ));\n        assert!(approx_eq(\n            convert_weight(3.0, \"pound\", \"pound\").unwrap(),\n            3.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"pound\", \"ounce\").unwrap(),\n            16.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"pound\", \"carat\").unwrap(),\n            2_267.961_85\n        ));\n    }\n\n    #[test]\n    fn test_stone_conversions() {\n        // Test conversions from stone (14 lb = 6.35029318 kg precisely)\n        assert!(approx_eq(\n            convert_weight(5.0, \"stone\", \"kilogram\").unwrap(),\n            31.751_465_9\n        ));\n        assert!(approx_eq(\n            convert_weight(2.0, \"stone\", \"gram\").unwrap(),\n            12_700.586_36\n        ));\n        assert!(approx_eq(\n            convert_weight(2.0, \"stone\", \"pound\").unwrap(),\n            28.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"stone\", \"ounce\").unwrap(),\n            224.0\n        ));\n    }\n\n    #[test]\n    fn test_ounce_conversions() {\n        // Test conversions from ounce (1/16 lb = 0.028349523125 kg precisely)\n        assert!(approx_eq(\n            convert_weight(3.0, \"ounce\", \"kilogram\").unwrap(),\n            0.085_048_569_375\n        ));\n        assert!(approx_eq(\n            convert_weight(3.0, \"ounce\", \"gram\").unwrap(),\n            85.048_569_375\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"ounce\", \"pound\").unwrap(),\n            0.0625\n        ));\n        assert!(approx_eq(\n            convert_weight(2.0, \"ounce\", \"ounce\").unwrap(),\n            2.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"ounce\", \"carat\").unwrap(),\n            141.747_615_625\n        ));\n    }\n\n    #[test]\n    fn test_small_imperial_units() {\n        // Test dram (1/256 lb = 0.0017718451953125 kg precisely)\n        assert!(approx_eq(\n            convert_weight(1.0, \"dram\", \"gram\").unwrap(),\n            1.771_845_195_312_5\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"dram\", \"kilogram\").unwrap(),\n            0.001_771_845_195_312_5\n        ));\n        assert!(approx_eq(\n            convert_weight(256.0, \"dram\", \"pound\").unwrap(),\n            1.0\n        ));\n        assert!(approx_eq(\n            convert_weight(16.0, \"dram\", \"ounce\").unwrap(),\n            1.0\n        ));\n\n        // Test grain (1/7000 lb = 0.00006479891 kg precisely)\n        assert!(approx_eq(\n            convert_weight(1.0, \"grain\", \"gram\").unwrap(),\n            0.064_798_91\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"grain\", \"kilogram\").unwrap(),\n            0.000_064_798_91\n        ));\n        assert!(approx_eq(\n            convert_weight(7000.0, \"grain\", \"pound\").unwrap(),\n            1.0\n        ));\n    }\n\n    #[test]\n    fn test_carat_conversions() {\n        // Test conversions from carat\n        assert!(approx_eq(\n            convert_weight(1.0, \"carat\", \"kilogram\").unwrap(),\n            0.000_2\n        ));\n        assert!(approx_eq(\n            convert_weight(4.0, \"carat\", \"gram\").unwrap(),\n            0.8\n        ));\n        assert!(approx_eq(\n            convert_weight(2.0, \"carat\", \"milligram\").unwrap(),\n            400.0\n        ));\n        assert!(approx_eq(\n            convert_weight(4.0, \"carat\", \"carat\").unwrap(),\n            4.0\n        ));\n    }\n\n    #[test]\n    fn test_troy_weight_system() {\n        // Test troy pound (0.3732417216 kg exactly)\n        assert!(approx_eq(\n            convert_weight(1.0, \"troy-pound\", \"gram\").unwrap(),\n            373.241_721_6\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"troy-pound\", \"kilogram\").unwrap(),\n            0.373_241_721_6\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"troy-pound\", \"pound\").unwrap(),\n            0.822_857_143\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"troy-pound\", \"troy-ounce\").unwrap(),\n            12.0\n        ));\n\n        // Test troy ounce (1/12 troy lb = 0.0311034768 kg exactly)\n        assert!(approx_eq(\n            convert_weight(1.0, \"troy-ounce\", \"gram\").unwrap(),\n            31.103_476_8\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"troy-ounce\", \"kilogram\").unwrap(),\n            0.031_103_476_8\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"troy-ounce\", \"ounce\").unwrap(),\n            1.097_142_857\n        ));\n        assert!(approx_eq(\n            convert_weight(12.0, \"troy-ounce\", \"troy-pound\").unwrap(),\n            1.0\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"troy-ounce\", \"pennyweight\").unwrap(),\n            20.0\n        ));\n\n        // Test pennyweight (1/240 troy lb = 0.00155517384 kg exactly)\n        assert!(approx_eq(\n            convert_weight(1.0, \"pennyweight\", \"gram\").unwrap(),\n            1.555_173_84\n        ));\n        assert!(approx_eq(\n            convert_weight(1.0, \"pennyweight\", \"kilogram\").unwrap(),\n            0.001_555_173_84\n        ));\n        assert!(approx_eq(\n            convert_weight(20.0, \"pennyweight\", \"troy-ounce\").unwrap(),\n            1.0\n        ));\n        assert!(approx_eq(\n            convert_weight(240.0, \"pennyweight\", \"troy-pound\").unwrap(),\n            1.0\n        ));\n    }\n\n    #[test]\n    fn test_atomic_mass_unit_conversions() {\n        // Test conversions from atomic mass unit\n        assert!(approx_eq(\n            convert_weight(4.0, \"atomic-mass-unit\", \"kilogram\").unwrap(),\n            6.642_160_796e-27\n        ));\n        assert!(approx_eq(\n            convert_weight(2.0, \"atomic-mass-unit\", \"atomic-mass-unit\").unwrap(),\n            2.0\n        ));\n    }\n\n    #[test]\n    fn test_using_enums() {\n        // Test using enums (type-safe)\n        assert!(approx_eq(\n            convert_weight(1.0, WeightUnit::Kilogram, WeightUnit::Gram).unwrap(),\n            1_000.0\n        ));\n        assert!(approx_eq(\n            convert_weight(100.0, WeightUnit::Pound, WeightUnit::Kilogram).unwrap(),\n            45.359_237\n        ));\n    }\n\n    #[test]\n    fn test_mixed_usage() {\n        // Test mixed usage (enum and string)\n        assert!(approx_eq(\n            convert_weight(1.0, WeightUnit::Kilogram, \"pound\").unwrap(),\n            2.204_622_622\n        ));\n        assert!(approx_eq(\n            convert_weight(16.0, \"ounce\", WeightUnit::Pound).unwrap(),\n            1.0\n        ));\n    }\n\n    #[test]\n    fn test_invalid_units() {\n        // Test invalid units\n        assert!(convert_weight(4.0, \"slug\", \"kilogram\").is_err());\n        assert!(convert_weight(4.0, \"kilogram\", \"wrongUnit\").is_err());\n    }\n\n    #[test]\n    fn test_roundtrip_conversion() {\n        // Test roundtrip conversion\n        let original = 100.0;\n        let converted = convert_weight(original, \"pound\", \"kilogram\").unwrap();\n        let back = convert_weight(converted, \"kilogram\", \"pound\").unwrap();\n        assert!(approx_eq(original, back));\n    }\n\n    #[test]\n    fn test_string_ownership() {\n        // Test String (owned) conversion\n        let unit_string = String::from(\"kilogram\");\n        assert_eq!(\n            unit_string.into_weight_unit().unwrap(),\n            WeightUnit::Kilogram\n        );\n\n        let invalid_string = String::from(\"invalid\");\n        assert!(invalid_string.into_weight_unit().is_err());\n    }\n\n    #[test]\n    fn test_display_implementation() {\n        // Test Display implementation for all units\n        assert_eq!(format!(\"{}\", WeightUnit::Gigatonne), \"Gt\");\n        assert_eq!(format!(\"{}\", WeightUnit::Megatonne), \"Mt\");\n        assert_eq!(format!(\"{}\", WeightUnit::MetricTon), \"t\");\n        assert_eq!(format!(\"{}\", WeightUnit::Kilogram), \"kg\");\n        assert_eq!(format!(\"{}\", WeightUnit::Gram), \"g\");\n        assert_eq!(format!(\"{}\", WeightUnit::Milligram), \"mg\");\n        assert_eq!(format!(\"{}\", WeightUnit::Microgram), \"μg\");\n        assert_eq!(format!(\"{}\", WeightUnit::Nanogram), \"ng\");\n        assert_eq!(format!(\"{}\", WeightUnit::Picogram), \"pg\");\n        assert_eq!(format!(\"{}\", WeightUnit::LongTon), \"long ton\");\n        assert_eq!(format!(\"{}\", WeightUnit::ShortTon), \"short ton\");\n        assert_eq!(format!(\"{}\", WeightUnit::Hundredweight), \"cwt\");\n        assert_eq!(format!(\"{}\", WeightUnit::Quarter), \"qtr\");\n        assert_eq!(format!(\"{}\", WeightUnit::Stone), \"st\");\n        assert_eq!(format!(\"{}\", WeightUnit::Pound), \"lb\");\n        assert_eq!(format!(\"{}\", WeightUnit::Ounce), \"oz\");\n        assert_eq!(format!(\"{}\", WeightUnit::Dram), \"dr\");\n        assert_eq!(format!(\"{}\", WeightUnit::Grain), \"gr\");\n        assert_eq!(format!(\"{}\", WeightUnit::TroyPound), \"lb t\");\n        assert_eq!(format!(\"{}\", WeightUnit::TroyOunce), \"oz t\");\n        assert_eq!(format!(\"{}\", WeightUnit::Pennyweight), \"dwt\");\n        assert_eq!(format!(\"{}\", WeightUnit::Carat), \"ct\");\n        assert_eq!(format!(\"{}\", WeightUnit::AtomicMassUnit), \"amu\");\n    }\n\n    #[test]\n    fn test_alternative_names() {\n        // Test alternative unit names\n        assert!(convert_weight(1.0, \"kg\", \"gram\").is_ok());\n        assert!(convert_weight(1.0, \"lb\", \"kilogram\").is_ok());\n        assert!(convert_weight(1.0, \"oz\", \"gram\").is_ok());\n        assert!(convert_weight(1.0, \"tonne\", \"kilogram\").is_ok());\n        assert!(convert_weight(1.0, \"dalton\", \"kilogram\").is_ok());\n        assert!(convert_weight(1.0, \"gt\", \"megatonne\").is_ok());\n        assert!(convert_weight(1.0, \"mt\", \"metric-ton\").is_ok());\n        assert!(convert_weight(1.0, \"ug\", \"gram\").is_ok());\n        assert!(convert_weight(1.0, \"μg\", \"microgram\").is_ok());\n        assert!(convert_weight(1.0, \"cwt\", \"kilogram\").is_ok());\n        assert!(convert_weight(1.0, \"qtr\", \"quarter\").is_ok());\n        assert!(convert_weight(1.0, \"dr\", \"gram\").is_ok());\n        assert!(convert_weight(1.0, \"gr\", \"grain\").is_ok());\n        assert!(convert_weight(1.0, \"ozt\", \"gram\").is_ok());\n        assert!(convert_weight(1.0, \"lbt\", \"troy-pound\").is_ok());\n        assert!(convert_weight(1.0, \"dwt\", \"gram\").is_ok());\n    }\n}\n"
  },
  {
    "path": "src/data_structures/README.md",
    "content": "### [B-Trees](./b_tree.rs)\n\nB-Trees are version of 2-3 trees, which are self-balancing. They are used to improve Disk reads and have a complexity of\nO(log(n)), for every tree operations.The number of Childrens/Keys a particular node has, is\ndetermined by the Branching Factor/Degree of that tree.\nB-Trees will always have sorted keys.\n\n- Branching Factor(B) / Degree (D):\n  If B = n, n <= Children per Node < 2(n), n-1 <= Keys per Node < 2(n) - 1\n\n__Properties__\n* Worst/Average case performance for all operations\tO(log n)\n* Space complexity\tO(n)\n\n__Sources to read:__\n* [Busying Oneself with B-Trees](https://medium.com/basecs/busying-oneself-with-b-trees-78bbf10522e7)\n* [Geeksforgeeks](https://www.geeksforgeeks.org/introduction-of-b-tree-2/)\n* [Rust API Docs](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html)\n* [Keon Algorithms](https://github.com/keon/algorithms)\n* [MIT Open Course](https://www.youtube.com/watch?v=TOb1tuEZ2X4)\n\n### [AVL Tree](./avl_tree.rs)\n\nAn AVL Tree is a self-balancing binary search tree. The heights of any two sibling\nnodes must differ by at most one; the tree may rebalance itself after insertion or\ndeletion to uphold this property.\n\n__Properties__\n* Worst/Average time complexity for basic operations: O(log n)\n* Worst/Average space complexity: O(n)\n\n__Sources to read:__\n* [Wikipedia](https://en.wikipedia.org/wiki/AVL_tree)\n* Geeksforgeeks\n([Insertion](https://www.geeksforgeeks.org/avl-tree-set-1-insertion),\n[Deletion](https://www.geeksforgeeks.org/avl-tree-set-2-deletion))\n\n\n### [Doubly linked list](./linked_list.rs)\n![alt text][doubly-linked-list]\n\nA linked list is also a `linear` data structure, and each element in the linked list is actually a separate object while all the objects are `linked together by the reference filed` in each element. In a `doubly linked list`, each node contains, besides the `next` node link, a second link field pointing to the `previous` node in the sequence. The two links may be called `next` and `prev`. And many modern operating systems use doubly linked lists to maintain references to active processes, threads and other dynamic objects.\n\n__Properties__\n* Indexing O(n)\n* Insertion O(1)\n  * Beginning O(1)\n  * Middle (Indexing time+O(1))\n  * End O(n)\n* Deletion O(1)\n  * Beginning O(1)\n  * Middle (Indexing time+O(1))\n  * End O(n)\n* Search O(n)\n\n__Source to read:__\n* [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n* [LeetCode](https://leetcode.com/explore/learn/card/linked-list/)\n* [Brilliant](https://brilliant.org/wiki/linked-lists/)\n* [Rust API Docs](https://doc.rust-lang.org/std/collections/struct.LinkedList.html)\n\n\n### [Stack Using Singly Linked List](./stack_using_singly_linked_list.rs)\n![][stack]\n\nFrom Wikipedia, a stack is an abstract data type that serves as a collection of elements, with two main principal operations, `Push` and `Pop`.\n\n__Properties__\n* Push O(1)\n* Pop head.data O(1) tail.data O(n)\n* Peek O(1)\n\n\n__Source to read:__\n* [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)\n* [rust-unofficial](https://rust-unofficial.github.io/too-many-lists/index.html)\n* [Stack Implementation and complexity](https://medium.com/@kaichimomose/stack-implementation-and-complexity-c176924e6a6b)\n\n\n\n[doubly-linked-list]: https://upload.wikimedia.org/wikipedia/commons/thumb/5/5e/Doubly-linked-list.svg/610px-Doubly-linked-list.svg.png\n\n[stack]: https://upload.wikimedia.org/wikipedia/commons/thumb/b/b4/Lifo_stack.png/700px-Lifo_stack.png"
  },
  {
    "path": "src/data_structures/avl_tree.rs",
    "content": "use std::{\n    cmp::{max, Ordering},\n    iter::FromIterator,\n    mem,\n    ops::Not,\n};\n\n/// An internal node of an `AVLTree`.\nstruct AVLNode<T: Ord> {\n    value: T,\n    height: usize,\n    left: Option<Box<AVLNode<T>>>,\n    right: Option<Box<AVLNode<T>>>,\n}\n\n/// A set based on an AVL Tree.\n///\n/// An AVL Tree is a self-balancing binary search tree. It tracks the height of each node\n/// and performs internal rotations to maintain a height difference of at most 1 between\n/// each sibling pair.\npub struct AVLTree<T: Ord> {\n    root: Option<Box<AVLNode<T>>>,\n    length: usize,\n}\n\n/// Refers to the left or right subtree of an `AVLNode`.\n#[derive(Clone, Copy)]\nenum Side {\n    Left,\n    Right,\n}\n\nimpl<T: Ord> AVLTree<T> {\n    /// Creates an empty `AVLTree`.\n    pub fn new() -> AVLTree<T> {\n        AVLTree {\n            root: None,\n            length: 0,\n        }\n    }\n\n    /// Returns `true` if the tree contains a value.\n    pub fn contains(&self, value: &T) -> bool {\n        let mut current = &self.root;\n        while let Some(node) = current {\n            current = match value.cmp(&node.value) {\n                Ordering::Equal => return true,\n                Ordering::Less => &node.left,\n                Ordering::Greater => &node.right,\n            }\n        }\n        false\n    }\n\n    /// Adds a value to the tree.\n    ///\n    /// Returns `true` if the tree did not yet contain the value.\n    pub fn insert(&mut self, value: T) -> bool {\n        let inserted = insert(&mut self.root, value);\n        if inserted {\n            self.length += 1;\n        }\n        inserted\n    }\n\n    /// Removes a value from the tree.\n    ///\n    /// Returns `true` if the tree contained the value.\n    pub fn remove(&mut self, value: &T) -> bool {\n        let removed = remove(&mut self.root, value);\n        if removed {\n            self.length -= 1;\n        }\n        removed\n    }\n\n    /// Returns the number of values in the tree.\n    pub fn len(&self) -> usize {\n        self.length\n    }\n\n    /// Returns `true` if the tree contains no values.\n    pub fn is_empty(&self) -> bool {\n        self.length == 0\n    }\n\n    /// Returns an iterator that visits the nodes in the tree in order.\n    fn node_iter(&self) -> NodeIter<'_, T> {\n        let cap = self.root.as_ref().map_or(0, |n| n.height);\n        let mut node_iter = NodeIter {\n            stack: Vec::with_capacity(cap),\n        };\n        // Initialize stack with path to leftmost child\n        let mut child = &self.root;\n        while let Some(node) = child {\n            node_iter.stack.push(node.as_ref());\n            child = &node.left;\n        }\n        node_iter\n    }\n\n    /// Returns an iterator that visits the values in the tree in ascending order.\n    pub fn iter(&self) -> Iter<'_, T> {\n        Iter {\n            node_iter: self.node_iter(),\n        }\n    }\n}\n\n/// Recursive helper function for `AVLTree` insertion.\nfn insert<T: Ord>(tree: &mut Option<Box<AVLNode<T>>>, value: T) -> bool {\n    if let Some(node) = tree {\n        let inserted = match value.cmp(&node.value) {\n            Ordering::Equal => false,\n            Ordering::Less => insert(&mut node.left, value),\n            Ordering::Greater => insert(&mut node.right, value),\n        };\n        if inserted {\n            node.rebalance();\n        }\n        inserted\n    } else {\n        *tree = Some(Box::new(AVLNode {\n            value,\n            height: 1,\n            left: None,\n            right: None,\n        }));\n        true\n    }\n}\n\n/// Recursive helper function for `AVLTree` deletion.\nfn remove<T: Ord>(tree: &mut Option<Box<AVLNode<T>>>, value: &T) -> bool {\n    if let Some(node) = tree {\n        let removed = match value.cmp(&node.value) {\n            Ordering::Less => remove(&mut node.left, value),\n            Ordering::Greater => remove(&mut node.right, value),\n            Ordering::Equal => {\n                *tree = match (node.left.take(), node.right.take()) {\n                    (None, None) => None,\n                    (Some(b), None) | (None, Some(b)) => Some(b),\n                    (Some(left), Some(right)) => Some(merge(left, right)),\n                };\n                return true;\n            }\n        };\n        if removed {\n            node.rebalance();\n        }\n        removed\n    } else {\n        false\n    }\n}\n\n/// Merges two trees and returns the root of the merged tree.\nfn merge<T: Ord>(left: Box<AVLNode<T>>, right: Box<AVLNode<T>>) -> Box<AVLNode<T>> {\n    let mut op_right = Some(right);\n    // Guaranteed not to panic since right has at least one node\n    let mut root = take_min(&mut op_right).unwrap();\n    root.left = Some(left);\n    root.right = op_right;\n    root.rebalance();\n    root\n}\n\n/// Removes the smallest node from the tree, if one exists.\nfn take_min<T: Ord>(tree: &mut Option<Box<AVLNode<T>>>) -> Option<Box<AVLNode<T>>> {\n    if let Some(mut node) = tree.take() {\n        // Recurse along the left side\n        if let Some(small) = take_min(&mut node.left) {\n            // Took the smallest from below; update this node and put it back in the tree\n            node.rebalance();\n            *tree = Some(node);\n            Some(small)\n        } else {\n            // Take this node and replace it with its right child\n            *tree = node.right.take();\n            Some(node)\n        }\n    } else {\n        None\n    }\n}\n\nimpl<T: Ord> AVLNode<T> {\n    /// Returns a reference to the left or right child.\n    fn child(&self, side: Side) -> &Option<Box<AVLNode<T>>> {\n        match side {\n            Side::Left => &self.left,\n            Side::Right => &self.right,\n        }\n    }\n\n    /// Returns a mutable reference to the left or right child.\n    fn child_mut(&mut self, side: Side) -> &mut Option<Box<AVLNode<T>>> {\n        match side {\n            Side::Left => &mut self.left,\n            Side::Right => &mut self.right,\n        }\n    }\n\n    /// Returns the height of the left or right subtree.\n    fn height(&self, side: Side) -> usize {\n        self.child(side).as_ref().map_or(0, |n| n.height)\n    }\n\n    /// Returns the height difference between the left and right subtrees.\n    fn balance_factor(&self) -> i8 {\n        let (left, right) = (self.height(Side::Left), self.height(Side::Right));\n        if left < right {\n            (right - left) as i8\n        } else {\n            -((left - right) as i8)\n        }\n    }\n\n    /// Recomputes the `height` field.\n    fn update_height(&mut self) {\n        self.height = 1 + max(self.height(Side::Left), self.height(Side::Right));\n    }\n\n    /// Performs a left or right rotation.\n    fn rotate(&mut self, side: Side) {\n        let mut subtree = self.child_mut(!side).take().unwrap();\n        *self.child_mut(!side) = subtree.child_mut(side).take();\n        self.update_height();\n        // Swap root and child nodes in memory\n        mem::swap(self, subtree.as_mut());\n        // Set old root (subtree) as child of new root (self)\n        *self.child_mut(side) = Some(subtree);\n        self.update_height();\n    }\n\n    /// Performs left or right tree rotations to balance this node.\n    fn rebalance(&mut self) {\n        self.update_height();\n        let side = match self.balance_factor() {\n            -2 => Side::Left,\n            2 => Side::Right,\n            _ => return,\n        };\n        let subtree = self.child_mut(side).as_mut().unwrap();\n        // Left-Right and Right-Left require rotation of heavy subtree\n        if let (Side::Left, 1) | (Side::Right, -1) = (side, subtree.balance_factor()) {\n            subtree.rotate(side);\n        }\n        // Rotate in opposite direction of heavy side\n        self.rotate(!side);\n    }\n}\n\nimpl<T: Ord> Default for AVLTree<T> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl Not for Side {\n    type Output = Side;\n\n    fn not(self) -> Self::Output {\n        match self {\n            Side::Left => Side::Right,\n            Side::Right => Side::Left,\n        }\n    }\n}\n\nimpl<T: Ord> FromIterator<T> for AVLTree<T> {\n    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {\n        let mut tree = AVLTree::new();\n        for value in iter {\n            tree.insert(value);\n        }\n        tree\n    }\n}\n\n/// An iterator over the nodes of an `AVLTree`.\n///\n/// This struct is created by the `node_iter` method of `AVLTree`.\nstruct NodeIter<'a, T: Ord> {\n    stack: Vec<&'a AVLNode<T>>,\n}\n\nimpl<'a, T: Ord> Iterator for NodeIter<'a, T> {\n    type Item = &'a AVLNode<T>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        if let Some(node) = self.stack.pop() {\n            // Push left path of right subtree to stack\n            let mut child = &node.right;\n            while let Some(subtree) = child {\n                self.stack.push(subtree.as_ref());\n                child = &subtree.left;\n            }\n            Some(node)\n        } else {\n            None\n        }\n    }\n}\n\n/// An iterator over the items of an `AVLTree`.\n///\n/// This struct is created by the `iter` method of `AVLTree`.\npub struct Iter<'a, T: Ord> {\n    node_iter: NodeIter<'a, T>,\n}\n\nimpl<'a, T: Ord> Iterator for Iter<'a, T> {\n    type Item = &'a T;\n\n    fn next(&mut self) -> Option<&'a T> {\n        match self.node_iter.next() {\n            Some(node) => Some(&node.value),\n            None => None,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::AVLTree;\n\n    /// Returns `true` if all nodes in the tree are balanced.\n    fn is_balanced<T: Ord>(tree: &AVLTree<T>) -> bool {\n        tree.node_iter()\n            .all(|n| (-1..=1).contains(&n.balance_factor()))\n    }\n\n    #[test]\n    fn len() {\n        let tree: AVLTree<_> = (1..4).collect();\n        assert_eq!(tree.len(), 3);\n    }\n\n    #[test]\n    fn contains() {\n        let tree: AVLTree<_> = (1..4).collect();\n        assert!(tree.contains(&1));\n        assert!(!tree.contains(&4));\n    }\n\n    #[test]\n    fn insert() {\n        let mut tree = AVLTree::new();\n        // First insert succeeds\n        assert!(tree.insert(1));\n        // Second insert fails\n        assert!(!tree.insert(1));\n    }\n\n    #[test]\n    fn remove() {\n        let mut tree: AVLTree<_> = (1..8).collect();\n        // First remove succeeds\n        assert!(tree.remove(&4));\n        // Second remove fails\n        assert!(!tree.remove(&4));\n    }\n\n    #[test]\n    fn sorted() {\n        let tree: AVLTree<_> = (1..8).rev().collect();\n        assert!((1..8).eq(tree.iter().copied()));\n    }\n\n    #[test]\n    fn balanced() {\n        let mut tree: AVLTree<_> = (1..8).collect();\n        assert!(is_balanced(&tree));\n        for x in 1..8 {\n            tree.remove(&x);\n            assert!(is_balanced(&tree));\n        }\n    }\n}\n"
  },
  {
    "path": "src/data_structures/b_tree.rs",
    "content": "use std::convert::TryFrom;\nuse std::fmt::Debug;\nuse std::mem;\n\nstruct Node<T> {\n    keys: Vec<T>,\n    children: Vec<Node<T>>,\n}\n\npub struct BTree<T> {\n    root: Node<T>,\n    props: BTreeProps,\n}\n\n// Why to need a different Struct for props...\n// Check - http://smallcultfollowing.com/babysteps/blog/2018/11/01/after-nll-interprocedural-conflicts/#fnref:improvement\nstruct BTreeProps {\n    degree: usize,\n    max_keys: usize,\n    mid_key_index: usize,\n}\n\nimpl<T> Node<T>\nwhere\n    T: Ord,\n{\n    fn new(degree: usize, _keys: Option<Vec<T>>, _children: Option<Vec<Node<T>>>) -> Self {\n        Node {\n            keys: match _keys {\n                Some(_keys) => _keys,\n                None => Vec::with_capacity(degree - 1),\n            },\n            children: match _children {\n                Some(_children) => _children,\n                None => Vec::with_capacity(degree),\n            },\n        }\n    }\n\n    fn is_leaf(&self) -> bool {\n        self.children.is_empty()\n    }\n}\n\nimpl BTreeProps {\n    fn new(degree: usize) -> Self {\n        BTreeProps {\n            degree,\n            max_keys: degree - 1,\n            mid_key_index: (degree - 1) / 2,\n        }\n    }\n\n    fn is_maxed_out<T: Ord + Copy>(&self, node: &Node<T>) -> bool {\n        node.keys.len() == self.max_keys\n    }\n\n    // Split Child expects the Child Node to be full\n    /// Move the middle_key to parent node and split the child_node's\n    /// keys/chilren_nodes into half\n    fn split_child<T: Ord + Copy + Default>(&self, parent: &mut Node<T>, child_index: usize) {\n        let child = &mut parent.children[child_index];\n        let middle_key = child.keys[self.mid_key_index];\n        let right_keys = match child.keys.split_off(self.mid_key_index).split_first() {\n            Some((_first, _others)) => {\n                // We don't need _first, as it will move to parent node.\n                _others.to_vec()\n            }\n            None => Vec::with_capacity(self.max_keys),\n        };\n        let right_children = if child.is_leaf() {\n            None\n        } else {\n            Some(child.children.split_off(self.mid_key_index + 1))\n        };\n        let new_child_node: Node<T> = Node::new(self.degree, Some(right_keys), right_children);\n\n        parent.keys.insert(child_index, middle_key);\n        parent.children.insert(child_index + 1, new_child_node);\n    }\n\n    fn insert_non_full<T: Ord + Copy + Default>(&mut self, node: &mut Node<T>, key: T) {\n        let mut index: isize = isize::try_from(node.keys.len()).ok().unwrap() - 1;\n        while index >= 0 && node.keys[index as usize] >= key {\n            index -= 1;\n        }\n\n        let mut u_index: usize = usize::try_from(index + 1).ok().unwrap();\n        if node.is_leaf() {\n            // Just insert it, as we know this method will be called only when node is not full\n            node.keys.insert(u_index, key);\n        } else {\n            if self.is_maxed_out(&node.children[u_index]) {\n                self.split_child(node, u_index);\n                if node.keys[u_index] < key {\n                    u_index += 1;\n                }\n            }\n\n            self.insert_non_full(&mut node.children[u_index], key);\n        }\n    }\n    fn traverse_node<T: Ord + Debug>(node: &Node<T>, depth: usize) {\n        if node.is_leaf() {\n            print!(\" {0:{<1$}{2:?}{0:}<1$} \", \"\", depth, node.keys);\n        } else {\n            let _depth = depth + 1;\n            for (index, key) in node.keys.iter().enumerate() {\n                Self::traverse_node(&node.children[index], _depth);\n                // Check https://doc.rust-lang.org/std/fmt/index.html\n                // And https://stackoverflow.com/a/35280799/2849127\n                print!(\"{0:{<1$}{2:?}{0:}<1$}\", \"\", depth, key);\n            }\n            Self::traverse_node(node.children.last().unwrap(), _depth);\n        }\n    }\n}\n\nimpl<T> BTree<T>\nwhere\n    T: Ord + Copy + Debug + Default,\n{\n    pub fn new(branch_factor: usize) -> Self {\n        let degree = 2 * branch_factor;\n        BTree {\n            root: Node::new(degree, None, None),\n            props: BTreeProps::new(degree),\n        }\n    }\n\n    pub fn insert(&mut self, key: T) {\n        if self.props.is_maxed_out(&self.root) {\n            // Create an empty root and split the old root...\n            let mut new_root = Node::new(self.props.degree, None, None);\n            mem::swap(&mut new_root, &mut self.root);\n            self.root.children.insert(0, new_root);\n            self.props.split_child(&mut self.root, 0);\n        }\n        self.props.insert_non_full(&mut self.root, key);\n    }\n\n    pub fn traverse(&self) {\n        BTreeProps::traverse_node(&self.root, 0);\n        println!();\n    }\n\n    pub fn search(&self, key: T) -> bool {\n        let mut current_node = &self.root;\n        loop {\n            match current_node.keys.binary_search(&key) {\n                Ok(_) => return true,\n                Err(index) => {\n                    if current_node.is_leaf() {\n                        return false;\n                    }\n                    current_node = &current_node.children[index];\n                }\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::BTree;\n\n    macro_rules! test_search {\n        ($($name:ident: $number_of_children:expr,)*) => {\n        $(\n            #[test]\n            fn $name() {\n                let mut tree = BTree::new($number_of_children);\n                tree.insert(10);\n                tree.insert(20);\n                tree.insert(30);\n                tree.insert(5);\n                tree.insert(6);\n                tree.insert(7);\n                tree.insert(11);\n                tree.insert(12);\n                tree.insert(15);\n                assert!(!tree.search(4));\n                assert!(tree.search(5));\n                assert!(tree.search(6));\n                assert!(tree.search(7));\n                assert!(!tree.search(8));\n                assert!(!tree.search(9));\n                assert!(tree.search(10));\n                assert!(tree.search(11));\n                assert!(tree.search(12));\n                assert!(!tree.search(13));\n                assert!(!tree.search(14));\n                assert!(tree.search(15));\n                assert!(!tree.search(16));\n            }\n        )*\n        }\n    }\n\n    test_search! {\n        children_2: 2,\n        children_3: 3,\n        children_4: 4,\n        children_5: 5,\n        children_10: 10,\n        children_60: 60,\n        children_101: 101,\n    }\n}\n"
  },
  {
    "path": "src/data_structures/binary_search_tree.rs",
    "content": "use std::cmp::Ordering;\nuse std::ops::Deref;\n\n/// This struct implements as Binary Search Tree (BST), which is a\n/// simple data structure for storing sorted data\npub struct BinarySearchTree<T>\nwhere\n    T: Ord,\n{\n    value: Option<T>,\n    left: Option<Box<BinarySearchTree<T>>>,\n    right: Option<Box<BinarySearchTree<T>>>,\n}\n\nimpl<T> Default for BinarySearchTree<T>\nwhere\n    T: Ord,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<T> BinarySearchTree<T>\nwhere\n    T: Ord,\n{\n    /// Create a new, empty BST\n    pub fn new() -> BinarySearchTree<T> {\n        BinarySearchTree {\n            value: None,\n            left: None,\n            right: None,\n        }\n    }\n\n    /// Find a value in this tree. Returns True if value is in this\n    /// tree, and false otherwise\n    pub fn search(&self, value: &T) -> bool {\n        match &self.value {\n            Some(key) => {\n                match key.cmp(value) {\n                    Ordering::Equal => {\n                        // key == value\n                        true\n                    }\n                    Ordering::Greater => {\n                        // key > value\n                        match &self.left {\n                            Some(node) => node.search(value),\n                            None => false,\n                        }\n                    }\n                    Ordering::Less => {\n                        // key < value\n                        match &self.right {\n                            Some(node) => node.search(value),\n                            None => false,\n                        }\n                    }\n                }\n            }\n            None => false,\n        }\n    }\n\n    /// Returns a new iterator which iterates over this tree in order\n    pub fn iter(&self) -> impl Iterator<Item = &T> {\n        BinarySearchTreeIter::new(self)\n    }\n\n    /// Insert a value into the appropriate location in this tree.\n    pub fn insert(&mut self, value: T) {\n        match &self.value {\n            None => self.value = Some(value),\n            Some(key) => {\n                let target_node = if value < *key {\n                    &mut self.left\n                } else {\n                    &mut self.right\n                };\n                match target_node {\n                    Some(ref mut node) => {\n                        node.insert(value);\n                    }\n                    None => {\n                        let mut node = BinarySearchTree::new();\n                        node.value = Some(value);\n                        *target_node = Some(Box::new(node));\n                    }\n                }\n            }\n        }\n    }\n\n    /// Returns the smallest value in this tree\n    pub fn minimum(&self) -> Option<&T> {\n        match &self.left {\n            Some(node) => node.minimum(),\n            None => self.value.as_ref(),\n        }\n    }\n\n    /// Returns the largest value in this tree\n    pub fn maximum(&self) -> Option<&T> {\n        match &self.right {\n            Some(node) => node.maximum(),\n            None => self.value.as_ref(),\n        }\n    }\n\n    /// Returns the largest value in this tree smaller than value\n    pub fn floor(&self, value: &T) -> Option<&T> {\n        match &self.value {\n            Some(key) => {\n                match key.cmp(value) {\n                    Ordering::Greater => {\n                        // key > value\n                        match &self.left {\n                            Some(node) => node.floor(value),\n                            None => None,\n                        }\n                    }\n                    Ordering::Less => {\n                        // key < value\n                        match &self.right {\n                            Some(node) => {\n                                let val = node.floor(value);\n                                match val {\n                                    Some(_) => val,\n                                    None => Some(key),\n                                }\n                            }\n                            None => Some(key),\n                        }\n                    }\n                    Ordering::Equal => Some(key),\n                }\n            }\n            None => None,\n        }\n    }\n\n    /// Returns the smallest value in this tree larger than value\n    pub fn ceil(&self, value: &T) -> Option<&T> {\n        match &self.value {\n            Some(key) => {\n                match key.cmp(value) {\n                    Ordering::Less => {\n                        // key < value\n                        match &self.right {\n                            Some(node) => node.ceil(value),\n                            None => None,\n                        }\n                    }\n                    Ordering::Greater => {\n                        // key > value\n                        match &self.left {\n                            Some(node) => {\n                                let val = node.ceil(value);\n                                match val {\n                                    Some(_) => val,\n                                    None => Some(key),\n                                }\n                            }\n                            None => Some(key),\n                        }\n                    }\n                    Ordering::Equal => {\n                        // key == value\n                        Some(key)\n                    }\n                }\n            }\n            None => None,\n        }\n    }\n}\n\nstruct BinarySearchTreeIter<'a, T>\nwhere\n    T: Ord,\n{\n    stack: Vec<&'a BinarySearchTree<T>>,\n}\n\nimpl<T> BinarySearchTreeIter<'_, T>\nwhere\n    T: Ord,\n{\n    pub fn new(tree: &BinarySearchTree<T>) -> BinarySearchTreeIter<'_, T> {\n        let mut iter = BinarySearchTreeIter { stack: vec![tree] };\n        iter.stack_push_left();\n        iter\n    }\n\n    fn stack_push_left(&mut self) {\n        while let Some(child) = &self.stack.last().unwrap().left {\n            self.stack.push(child);\n        }\n    }\n}\n\nimpl<'a, T> Iterator for BinarySearchTreeIter<'a, T>\nwhere\n    T: Ord,\n{\n    type Item = &'a T;\n\n    fn next(&mut self) -> Option<&'a T> {\n        if self.stack.is_empty() {\n            None\n        } else {\n            let node = self.stack.pop().unwrap();\n            if let Some(right_node) = &node.right {\n                self.stack.push(right_node.deref());\n                self.stack_push_left();\n            }\n            node.value.as_ref()\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::BinarySearchTree;\n\n    fn prequel_memes_tree() -> BinarySearchTree<&'static str> {\n        let mut tree = BinarySearchTree::new();\n        tree.insert(\"hello there\");\n        tree.insert(\"general kenobi\");\n        tree.insert(\"you are a bold one\");\n        tree.insert(\"kill him\");\n        tree.insert(\"back away...I will deal with this jedi slime myself\");\n        tree.insert(\"your move\");\n        tree.insert(\"you fool\");\n        tree\n    }\n\n    #[test]\n    fn test_search() {\n        let tree = prequel_memes_tree();\n        assert!(tree.search(&\"hello there\"));\n        assert!(tree.search(&\"you are a bold one\"));\n        assert!(tree.search(&\"general kenobi\"));\n        assert!(tree.search(&\"you fool\"));\n        assert!(tree.search(&\"kill him\"));\n        assert!(\n            !tree.search(&\"but i was going to tosche station to pick up some power converters\",)\n        );\n        assert!(!tree.search(&\"only a sith deals in absolutes\"));\n        assert!(!tree.search(&\"you underestimate my power\"));\n    }\n\n    #[test]\n    fn test_maximum_and_minimum() {\n        let tree = prequel_memes_tree();\n        assert_eq!(*tree.maximum().unwrap(), \"your move\");\n        assert_eq!(\n            *tree.minimum().unwrap(),\n            \"back away...I will deal with this jedi slime myself\"\n        );\n        let mut tree2: BinarySearchTree<i32> = BinarySearchTree::new();\n        assert!(tree2.maximum().is_none());\n        assert!(tree2.minimum().is_none());\n        tree2.insert(0);\n        assert_eq!(*tree2.minimum().unwrap(), 0);\n        assert_eq!(*tree2.maximum().unwrap(), 0);\n        tree2.insert(-5);\n        assert_eq!(*tree2.minimum().unwrap(), -5);\n        assert_eq!(*tree2.maximum().unwrap(), 0);\n        tree2.insert(5);\n        assert_eq!(*tree2.minimum().unwrap(), -5);\n        assert_eq!(*tree2.maximum().unwrap(), 5);\n    }\n\n    #[test]\n    fn test_floor_and_ceil() {\n        let tree = prequel_memes_tree();\n        assert_eq!(*tree.floor(&\"hello there\").unwrap(), \"hello there\");\n        assert_eq!(\n            *tree\n                .floor(&\"these are not the droids you're looking for\")\n                .unwrap(),\n            \"kill him\"\n        );\n        assert!(tree.floor(&\"another death star\").is_none());\n        assert_eq!(*tree.floor(&\"you fool\").unwrap(), \"you fool\");\n        assert_eq!(\n            *tree.floor(&\"but i was going to tasche station\").unwrap(),\n            \"back away...I will deal with this jedi slime myself\"\n        );\n        assert_eq!(\n            *tree.floor(&\"you underestimate my power\").unwrap(),\n            \"you fool\"\n        );\n        assert_eq!(*tree.floor(&\"your new empire\").unwrap(), \"your move\");\n        assert_eq!(*tree.ceil(&\"hello there\").unwrap(), \"hello there\");\n        assert_eq!(\n            *tree\n                .ceil(&\"these are not the droids you're looking for\")\n                .unwrap(),\n            \"you are a bold one\"\n        );\n        assert_eq!(\n            *tree.ceil(&\"another death star\").unwrap(),\n            \"back away...I will deal with this jedi slime myself\"\n        );\n        assert_eq!(*tree.ceil(&\"you fool\").unwrap(), \"you fool\");\n        assert_eq!(\n            *tree.ceil(&\"but i was going to tasche station\").unwrap(),\n            \"general kenobi\"\n        );\n        assert_eq!(\n            *tree.ceil(&\"you underestimate my power\").unwrap(),\n            \"your move\"\n        );\n        assert!(tree.ceil(&\"your new empire\").is_none());\n    }\n\n    #[test]\n    fn test_iterator() {\n        let tree = prequel_memes_tree();\n        let mut iter = tree.iter();\n        assert_eq!(\n            iter.next().unwrap(),\n            &\"back away...I will deal with this jedi slime myself\"\n        );\n        assert_eq!(iter.next().unwrap(), &\"general kenobi\");\n        assert_eq!(iter.next().unwrap(), &\"hello there\");\n        assert_eq!(iter.next().unwrap(), &\"kill him\");\n        assert_eq!(iter.next().unwrap(), &\"you are a bold one\");\n        assert_eq!(iter.next().unwrap(), &\"you fool\");\n        assert_eq!(iter.next().unwrap(), &\"your move\");\n        assert_eq!(iter.next(), None);\n        assert_eq!(iter.next(), None);\n    }\n}\n"
  },
  {
    "path": "src/data_structures/fenwick_tree.rs",
    "content": "use std::ops::{Add, AddAssign, Sub, SubAssign};\n\n/// A Fenwick Tree (also known as a Binary Indexed Tree) that supports efficient\n/// prefix sum, range sum and point queries, as well as point updates.\n///\n/// The Fenwick Tree uses **1-based** indexing internally but presents a **0-based** interface to the user.\n/// This design improves efficiency and simplifies both internal operations and external usage.\npub struct FenwickTree<T>\nwhere\n    T: Add<Output = T> + AddAssign + Sub<Output = T> + SubAssign + Copy + Default,\n{\n    /// Internal storage of the Fenwick Tree. The first element (index 0) is unused\n    /// to simplify index calculations, so the effective tree size is `data.len() - 1`.\n    data: Vec<T>,\n}\n\n/// Enum representing the possible errors that can occur during FenwickTree operations.\n#[derive(Debug, PartialEq, Eq)]\npub enum FenwickTreeError {\n    /// Error indicating that an index was out of the valid range.\n    IndexOutOfBounds,\n    /// Error indicating that a provided range was invalid (e.g., left > right).\n    InvalidRange,\n}\n\nimpl<T> FenwickTree<T>\nwhere\n    T: Add<Output = T> + AddAssign + Sub<Output = T> + SubAssign + Copy + Default,\n{\n    /// Creates a new Fenwick Tree with a specified capacity.\n    ///\n    /// The tree will have `capacity + 1` elements, all initialized to the default\n    /// value of type `T`. The additional element allows for 1-based indexing internally.\n    ///\n    /// # Arguments\n    ///\n    /// * `capacity` - The number of elements the tree can hold (excluding the extra element).\n    ///\n    /// # Returns\n    ///\n    /// A new `FenwickTree` instance.\n    pub fn with_capacity(capacity: usize) -> Self {\n        FenwickTree {\n            data: vec![T::default(); capacity + 1],\n        }\n    }\n\n    /// Updates the tree by adding a value to the element at a specified index.\n    ///\n    /// This operation also propagates the update to subsequent elements in the tree.\n    ///\n    /// # Arguments\n    ///\n    /// * `index` - The zero-based index where the value should be added.\n    /// * `value` - The value to add to the element at the specified index.\n    ///\n    /// # Returns\n    ///\n    /// A `Result` indicating success (`Ok`) or an error (`FenwickTreeError::IndexOutOfBounds`)\n    /// if the index is out of bounds.\n    pub fn update(&mut self, index: usize, value: T) -> Result<(), FenwickTreeError> {\n        if index >= self.data.len() - 1 {\n            return Err(FenwickTreeError::IndexOutOfBounds);\n        }\n\n        let mut idx = index + 1;\n        while idx < self.data.len() {\n            self.data[idx] += value;\n            idx += lowbit(idx);\n        }\n\n        Ok(())\n    }\n\n    /// Computes the sum of elements from the start of the tree up to a specified index.\n    ///\n    /// This operation efficiently calculates the prefix sum using the tree structure.\n    ///\n    /// # Arguments\n    ///\n    /// * `index` - The zero-based index up to which the sum should be computed.\n    ///\n    /// # Returns\n    ///\n    /// A `Result` containing the prefix sum (`Ok(sum)`) or an error (`FenwickTreeError::IndexOutOfBounds`)\n    /// if the index is out of bounds.\n    pub fn prefix_query(&self, index: usize) -> Result<T, FenwickTreeError> {\n        if index >= self.data.len() - 1 {\n            return Err(FenwickTreeError::IndexOutOfBounds);\n        }\n\n        let mut idx = index + 1;\n        let mut result = T::default();\n        while idx > 0 {\n            result += self.data[idx];\n            idx -= lowbit(idx);\n        }\n\n        Ok(result)\n    }\n\n    /// Computes the sum of elements within a specified range `[left, right]`.\n    ///\n    /// This operation calculates the range sum by performing two prefix sum queries.\n    ///\n    /// # Arguments\n    ///\n    /// * `left` - The zero-based starting index of the range.\n    /// * `right` - The zero-based ending index of the range.\n    ///\n    /// # Returns\n    ///\n    /// A `Result` containing the range sum (`Ok(sum)`) or an error (`FenwickTreeError::InvalidRange`)\n    /// if the left index is greater than the right index or the right index is out of bounds.\n    pub fn range_query(&self, left: usize, right: usize) -> Result<T, FenwickTreeError> {\n        if left > right || right >= self.data.len() - 1 {\n            return Err(FenwickTreeError::InvalidRange);\n        }\n\n        let right_query = self.prefix_query(right)?;\n        let left_query = if left == 0 {\n            T::default()\n        } else {\n            self.prefix_query(left - 1)?\n        };\n\n        Ok(right_query - left_query)\n    }\n\n    /// Retrieves the value at a specific index by isolating it from the prefix sum.\n    ///\n    /// This operation determines the value at `index` by subtracting the prefix sum up to `index - 1`\n    /// from the prefix sum up to `index`.\n    ///\n    /// # Arguments\n    ///\n    /// * `index` - The zero-based index of the element to retrieve.\n    ///\n    /// # Returns\n    ///\n    /// A `Result` containing the value at the specified index (`Ok(value)`) or an error (`FenwickTreeError::IndexOutOfBounds`)\n    /// if the index is out of bounds.\n    pub fn point_query(&self, index: usize) -> Result<T, FenwickTreeError> {\n        if index >= self.data.len() - 1 {\n            return Err(FenwickTreeError::IndexOutOfBounds);\n        }\n\n        let index_query = self.prefix_query(index)?;\n        let prev_query = if index == 0 {\n            T::default()\n        } else {\n            self.prefix_query(index - 1)?\n        };\n\n        Ok(index_query - prev_query)\n    }\n\n    /// Sets the value at a specific index in the tree, updating the structure accordingly.\n    ///\n    /// This operation updates the value at `index` by computing the difference between the\n    /// desired value and the current value, then applying that difference using `update`.\n    ///\n    /// # Arguments\n    ///\n    /// * `index` - The zero-based index of the element to set.\n    /// * `value` - The new value to set at the specified index.\n    ///\n    /// # Returns\n    ///\n    /// A `Result` indicating success (`Ok`) or an error (`FenwickTreeError::IndexOutOfBounds`)\n    /// if the index is out of bounds.\n    pub fn set(&mut self, index: usize, value: T) -> Result<(), FenwickTreeError> {\n        self.update(index, value - self.point_query(index)?)\n    }\n}\n\n/// Computes the lowest set bit (rightmost `1` bit) of a number.\n///\n/// This function isolates the lowest set bit in the binary representation of `x`.\n/// It's used to navigate the Fenwick Tree by determining the next index to update or query.\n///\n///\n/// In a Fenwick Tree, operations like updating and querying use bitwise manipulation\n/// (via the lowbit function). These operations naturally align with 1-based indexing,\n/// making traversal between parent and child nodes more straightforward.\n///\n/// # Arguments\n///\n/// * `x` - The input number whose lowest set bit is to be determined.\n///\n/// # Returns\n///\n/// The value of the lowest set bit in `x`.\nconst fn lowbit(x: usize) -> usize {\n    x & (!x + 1)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_fenwick_tree() {\n        let mut fenwick_tree = FenwickTree::with_capacity(10);\n\n        assert_eq!(fenwick_tree.update(0, 5), Ok(()));\n        assert_eq!(fenwick_tree.update(1, 3), Ok(()));\n        assert_eq!(fenwick_tree.update(2, -2), Ok(()));\n        assert_eq!(fenwick_tree.update(3, 6), Ok(()));\n        assert_eq!(fenwick_tree.update(4, -4), Ok(()));\n        assert_eq!(fenwick_tree.update(5, 7), Ok(()));\n        assert_eq!(fenwick_tree.update(6, -1), Ok(()));\n        assert_eq!(fenwick_tree.update(7, 2), Ok(()));\n        assert_eq!(fenwick_tree.update(8, -3), Ok(()));\n        assert_eq!(fenwick_tree.update(9, 4), Ok(()));\n        assert_eq!(fenwick_tree.set(3, 10), Ok(()));\n        assert_eq!(fenwick_tree.point_query(3), Ok(10));\n        assert_eq!(fenwick_tree.set(5, 0), Ok(()));\n        assert_eq!(fenwick_tree.point_query(5), Ok(0));\n        assert_eq!(\n            fenwick_tree.update(10, 11),\n            Err(FenwickTreeError::IndexOutOfBounds)\n        );\n        assert_eq!(\n            fenwick_tree.set(10, 11),\n            Err(FenwickTreeError::IndexOutOfBounds)\n        );\n\n        assert_eq!(fenwick_tree.prefix_query(0), Ok(5));\n        assert_eq!(fenwick_tree.prefix_query(1), Ok(8));\n        assert_eq!(fenwick_tree.prefix_query(2), Ok(6));\n        assert_eq!(fenwick_tree.prefix_query(3), Ok(16));\n        assert_eq!(fenwick_tree.prefix_query(4), Ok(12));\n        assert_eq!(fenwick_tree.prefix_query(5), Ok(12));\n        assert_eq!(fenwick_tree.prefix_query(6), Ok(11));\n        assert_eq!(fenwick_tree.prefix_query(7), Ok(13));\n        assert_eq!(fenwick_tree.prefix_query(8), Ok(10));\n        assert_eq!(fenwick_tree.prefix_query(9), Ok(14));\n        assert_eq!(\n            fenwick_tree.prefix_query(10),\n            Err(FenwickTreeError::IndexOutOfBounds)\n        );\n\n        assert_eq!(fenwick_tree.range_query(0, 4), Ok(12));\n        assert_eq!(fenwick_tree.range_query(3, 7), Ok(7));\n        assert_eq!(fenwick_tree.range_query(2, 5), Ok(4));\n        assert_eq!(\n            fenwick_tree.range_query(4, 3),\n            Err(FenwickTreeError::InvalidRange)\n        );\n        assert_eq!(\n            fenwick_tree.range_query(2, 10),\n            Err(FenwickTreeError::InvalidRange)\n        );\n\n        assert_eq!(fenwick_tree.point_query(0), Ok(5));\n        assert_eq!(fenwick_tree.point_query(4), Ok(-4));\n        assert_eq!(fenwick_tree.point_query(9), Ok(4));\n        assert_eq!(\n            fenwick_tree.point_query(10),\n            Err(FenwickTreeError::IndexOutOfBounds)\n        );\n    }\n}\n"
  },
  {
    "path": "src/data_structures/floyds_algorithm.rs",
    "content": "// floyds_algorithm.rs\n// https://github.com/rust-lang/rust/blob/master/library/alloc/src/collections/linked_list.rs#L113\n// use std::collections::linked_list::LinkedList;\n// https://www.reddit.com/r/rust/comments/t7wquc/is_it_possible_to_solve_leetcode_problem141/\n\nuse crate::data_structures::linked_list::LinkedList; // Import the LinkedList from linked_list.rs\n\npub fn detect_cycle<T>(linked_list: &LinkedList<T>) -> Option<usize> {\n    let mut current = linked_list.head;\n    let mut checkpoint = linked_list.head;\n    let mut steps_until_reset = 1;\n    let mut times_reset = 0;\n\n    while let Some(node) = current {\n        steps_until_reset -= 1;\n        if steps_until_reset == 0 {\n            checkpoint = current;\n            times_reset += 1;\n            steps_until_reset = 1 << times_reset; // 2^times_reset\n        }\n\n        unsafe {\n            let node_ptr = node.as_ptr();\n            let next = (*node_ptr).next;\n            current = next;\n        }\n        if current == checkpoint {\n            return Some(linked_list.length as usize);\n        }\n    }\n\n    None\n}\n\npub fn has_cycle<T>(linked_list: &LinkedList<T>) -> bool {\n    let mut slow = linked_list.head;\n    let mut fast = linked_list.head;\n\n    while let (Some(slow_node), Some(fast_node)) = (slow, fast) {\n        unsafe {\n            slow = slow_node.as_ref().next;\n            fast = fast_node.as_ref().next;\n\n            if let Some(fast_next) = fast {\n                // fast = (*fast_next.as_ptr()).next;\n                fast = fast_next.as_ref().next;\n            } else {\n                return false; // If fast reaches the end, there's no cycle\n            }\n\n            if slow == fast {\n                return true; // Cycle detected\n            }\n        }\n    }\n    // println!(\"{}\", flag);\n    false // No cycle detected\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_detect_cycle_no_cycle() {\n        let mut linked_list = LinkedList::new();\n        linked_list.insert_at_tail(1);\n        linked_list.insert_at_tail(2);\n        linked_list.insert_at_tail(3);\n\n        assert!(!has_cycle(&linked_list));\n\n        assert_eq!(detect_cycle(&linked_list), None);\n    }\n\n    #[test]\n    fn test_detect_cycle_with_cycle() {\n        let mut linked_list = LinkedList::new();\n        linked_list.insert_at_tail(1);\n        linked_list.insert_at_tail(2);\n        linked_list.insert_at_tail(3);\n\n        // Create a cycle for testing\n        unsafe {\n            if let Some(mut tail) = linked_list.tail {\n                if let Some(head) = linked_list.head {\n                    tail.as_mut().next = Some(head);\n                }\n            }\n        }\n\n        assert!(has_cycle(&linked_list));\n        assert_eq!(detect_cycle(&linked_list), Some(3));\n    }\n}\n"
  },
  {
    "path": "src/data_structures/graph.rs",
    "content": "use std::collections::{HashMap, HashSet};\nuse std::fmt;\n\n#[derive(Debug, Clone)]\npub struct NodeNotInGraph;\n\nimpl fmt::Display for NodeNotInGraph {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"accessing a node that is not in the graph\")\n    }\n}\n\npub struct DirectedGraph {\n    adjacency_table: HashMap<String, Vec<(String, i32)>>,\n}\n\nimpl Graph for DirectedGraph {\n    fn new() -> DirectedGraph {\n        DirectedGraph {\n            adjacency_table: HashMap::new(),\n        }\n    }\n    fn adjacency_table_mutable(&mut self) -> &mut HashMap<String, Vec<(String, i32)>> {\n        &mut self.adjacency_table\n    }\n    fn adjacency_table(&self) -> &HashMap<String, Vec<(String, i32)>> {\n        &self.adjacency_table\n    }\n}\n\npub struct UndirectedGraph {\n    adjacency_table: HashMap<String, Vec<(String, i32)>>,\n}\n\nimpl Graph for UndirectedGraph {\n    fn new() -> UndirectedGraph {\n        UndirectedGraph {\n            adjacency_table: HashMap::new(),\n        }\n    }\n    fn adjacency_table_mutable(&mut self) -> &mut HashMap<String, Vec<(String, i32)>> {\n        &mut self.adjacency_table\n    }\n    fn adjacency_table(&self) -> &HashMap<String, Vec<(String, i32)>> {\n        &self.adjacency_table\n    }\n    fn add_edge(&mut self, edge: (&str, &str, i32)) {\n        self.add_node(edge.0);\n        self.add_node(edge.1);\n\n        self.adjacency_table\n            .entry(edge.0.to_string())\n            .and_modify(|e| {\n                e.push((edge.1.to_string(), edge.2));\n            });\n        self.adjacency_table\n            .entry(edge.1.to_string())\n            .and_modify(|e| {\n                e.push((edge.0.to_string(), edge.2));\n            });\n    }\n}\n\npub trait Graph {\n    fn new() -> Self;\n    fn adjacency_table_mutable(&mut self) -> &mut HashMap<String, Vec<(String, i32)>>;\n    fn adjacency_table(&self) -> &HashMap<String, Vec<(String, i32)>>;\n\n    fn add_node(&mut self, node: &str) -> bool {\n        match self.adjacency_table().get(node) {\n            None => {\n                self.adjacency_table_mutable()\n                    .insert((*node).to_string(), Vec::new());\n                true\n            }\n            _ => false,\n        }\n    }\n\n    fn add_edge(&mut self, edge: (&str, &str, i32)) {\n        self.add_node(edge.0);\n        self.add_node(edge.1);\n\n        self.adjacency_table_mutable()\n            .entry(edge.0.to_string())\n            .and_modify(|e| {\n                e.push((edge.1.to_string(), edge.2));\n            });\n    }\n\n    fn neighbours(&self, node: &str) -> Result<&Vec<(String, i32)>, NodeNotInGraph> {\n        match self.adjacency_table().get(node) {\n            None => Err(NodeNotInGraph),\n            Some(i) => Ok(i),\n        }\n    }\n\n    fn contains(&self, node: &str) -> bool {\n        self.adjacency_table().get(node).is_some()\n    }\n\n    fn nodes(&self) -> HashSet<&String> {\n        self.adjacency_table().keys().collect()\n    }\n\n    fn edges(&self) -> Vec<(&String, &String, i32)> {\n        let mut edges = Vec::new();\n        for (from_node, from_node_neighbours) in self.adjacency_table() {\n            for (to_node, weight) in from_node_neighbours {\n                edges.push((from_node, to_node, *weight));\n            }\n        }\n        edges\n    }\n}\n\n#[cfg(test)]\nmod test_undirected_graph {\n    use super::Graph;\n    use super::UndirectedGraph;\n    #[test]\n    fn test_add_edge() {\n        let mut graph = UndirectedGraph::new();\n\n        graph.add_edge((\"a\", \"b\", 5));\n        graph.add_edge((\"b\", \"c\", 10));\n        graph.add_edge((\"c\", \"a\", 7));\n\n        let expected_edges = [\n            (&String::from(\"a\"), &String::from(\"b\"), 5),\n            (&String::from(\"b\"), &String::from(\"a\"), 5),\n            (&String::from(\"c\"), &String::from(\"a\"), 7),\n            (&String::from(\"a\"), &String::from(\"c\"), 7),\n            (&String::from(\"b\"), &String::from(\"c\"), 10),\n            (&String::from(\"c\"), &String::from(\"b\"), 10),\n        ];\n        for edge in expected_edges.iter() {\n            assert!(graph.edges().contains(edge));\n        }\n    }\n\n    #[test]\n    fn test_neighbours() {\n        let mut graph = UndirectedGraph::new();\n\n        graph.add_edge((\"a\", \"b\", 5));\n        graph.add_edge((\"b\", \"c\", 10));\n        graph.add_edge((\"c\", \"a\", 7));\n\n        assert_eq!(\n            graph.neighbours(\"a\").unwrap(),\n            &vec![(String::from(\"b\"), 5), (String::from(\"c\"), 7)]\n        );\n    }\n}\n\n#[cfg(test)]\nmod test_directed_graph {\n    use super::DirectedGraph;\n    use super::Graph;\n\n    #[test]\n    fn test_add_node() {\n        let mut graph = DirectedGraph::new();\n        graph.add_node(\"a\");\n        graph.add_node(\"b\");\n        graph.add_node(\"c\");\n        assert_eq!(\n            graph.nodes(),\n            [&String::from(\"a\"), &String::from(\"b\"), &String::from(\"c\")]\n                .iter()\n                .cloned()\n                .collect()\n        );\n    }\n\n    #[test]\n    fn test_add_edge() {\n        let mut graph = DirectedGraph::new();\n\n        graph.add_edge((\"a\", \"b\", 5));\n        graph.add_edge((\"c\", \"a\", 7));\n        graph.add_edge((\"b\", \"c\", 10));\n\n        let expected_edges = [\n            (&String::from(\"a\"), &String::from(\"b\"), 5),\n            (&String::from(\"c\"), &String::from(\"a\"), 7),\n            (&String::from(\"b\"), &String::from(\"c\"), 10),\n        ];\n        for edge in expected_edges.iter() {\n            assert!(graph.edges().contains(edge));\n        }\n    }\n\n    #[test]\n    fn test_neighbours() {\n        let mut graph = DirectedGraph::new();\n\n        graph.add_edge((\"a\", \"b\", 5));\n        graph.add_edge((\"b\", \"c\", 10));\n        graph.add_edge((\"c\", \"a\", 7));\n\n        assert_eq!(\n            graph.neighbours(\"a\").unwrap(),\n            &vec![(String::from(\"b\"), 5)]\n        );\n    }\n\n    #[test]\n    fn test_contains() {\n        let mut graph = DirectedGraph::new();\n        graph.add_node(\"a\");\n        graph.add_node(\"b\");\n        graph.add_node(\"c\");\n        assert!(graph.contains(\"a\"));\n        assert!(graph.contains(\"b\"));\n        assert!(graph.contains(\"c\"));\n        assert!(!graph.contains(\"d\"));\n    }\n}\n"
  },
  {
    "path": "src/data_structures/hash_table.rs",
    "content": "use std::collections::LinkedList;\n\npub struct HashTable<K, V> {\n    elements: Vec<LinkedList<(K, V)>>,\n    count: usize,\n}\n\nimpl<K: Hashable + std::cmp::PartialEq, V> Default for HashTable<K, V> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\npub trait Hashable {\n    fn hash(&self) -> usize;\n}\n\nimpl<K: Hashable + std::cmp::PartialEq, V> HashTable<K, V> {\n    pub fn new() -> HashTable<K, V> {\n        let initial_capacity = 3000;\n        let mut elements = Vec::with_capacity(initial_capacity);\n\n        for _ in 0..initial_capacity {\n            elements.push(LinkedList::new());\n        }\n\n        HashTable { elements, count: 0 }\n    }\n\n    pub fn insert(&mut self, key: K, value: V) {\n        if self.count >= self.elements.len() * 3 / 4 {\n            self.resize();\n        }\n        let index = key.hash() % self.elements.len();\n        self.elements[index].push_back((key, value));\n        self.count += 1;\n    }\n\n    pub fn search(&self, key: K) -> Option<&V> {\n        let index = key.hash() % self.elements.len();\n        self.elements[index]\n            .iter()\n            .find(|(k, _)| *k == key)\n            .map(|(_, v)| v)\n    }\n\n    fn resize(&mut self) {\n        let new_size = self.elements.len() * 2;\n        let mut new_elements = Vec::with_capacity(new_size);\n\n        for _ in 0..new_size {\n            new_elements.push(LinkedList::new());\n        }\n\n        for old_list in self.elements.drain(..) {\n            for (key, value) in old_list {\n                let new_index = key.hash() % new_size;\n                new_elements[new_index].push_back((key, value));\n            }\n        }\n\n        self.elements = new_elements;\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[derive(Debug, PartialEq, Eq)]\n    struct TestKey(usize);\n\n    impl Hashable for TestKey {\n        fn hash(&self) -> usize {\n            self.0\n        }\n    }\n\n    #[test]\n    fn test_insert_and_search() {\n        let mut hash_table = HashTable::new();\n        let key = TestKey(1);\n        let value = TestKey(10);\n\n        hash_table.insert(key, value);\n        let result = hash_table.search(TestKey(1));\n\n        assert_eq!(result, Some(&TestKey(10)));\n    }\n\n    #[test]\n    fn test_resize() {\n        let mut hash_table = HashTable::new();\n        let initial_capacity = hash_table.elements.capacity();\n\n        for i in 0..=initial_capacity * 3 / 4 {\n            hash_table.insert(TestKey(i), TestKey(i + 10));\n        }\n\n        assert!(hash_table.elements.capacity() > initial_capacity);\n    }\n\n    #[test]\n    fn test_search_nonexistent() {\n        let mut hash_table = HashTable::new();\n        let key = TestKey(1);\n        let value = TestKey(10);\n\n        hash_table.insert(key, value);\n        let result = hash_table.search(TestKey(2));\n\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_multiple_inserts_and_searches() {\n        let mut hash_table = HashTable::new();\n        for i in 0..10 {\n            hash_table.insert(TestKey(i), TestKey(i + 100));\n        }\n\n        for i in 0..10 {\n            let result = hash_table.search(TestKey(i));\n            assert_eq!(result, Some(&TestKey(i + 100)));\n        }\n    }\n\n    #[test]\n    fn test_not_overwrite_existing_key() {\n        let mut hash_table = HashTable::new();\n        hash_table.insert(TestKey(1), TestKey(100));\n        hash_table.insert(TestKey(1), TestKey(200));\n\n        let result = hash_table.search(TestKey(1));\n        assert_eq!(result, Some(&TestKey(100)));\n    }\n\n    #[test]\n    fn test_empty_search() {\n        let hash_table: HashTable<TestKey, TestKey> = HashTable::new();\n        let result = hash_table.search(TestKey(1));\n\n        assert_eq!(result, None);\n    }\n}\n"
  },
  {
    "path": "src/data_structures/heap.rs",
    "content": "//! A generic heap data structure.\n//!\n//! This module provides a `Heap` implementation that can function as either a\n//! min-heap or a max-heap. It supports common heap operations such as adding,\n//! removing, and iterating over elements. The heap can also be created from\n//! an unsorted vector and supports custom comparators for flexible sorting\n//! behavior.\n\nuse std::{cmp::Ord, slice::Iter};\n\n/// A heap data structure that can be used as a min-heap, max-heap or with\n/// custom comparators.\n///\n/// This struct manages a collection of items where the heap property is maintained.\n/// The heap can be configured to order elements based on a provided comparator function,\n/// allowing for both min-heap and max-heap functionalities, as well as custom sorting orders.\npub struct Heap<T> {\n    items: Vec<T>,\n    comparator: fn(&T, &T) -> bool,\n}\n\nimpl<T> Heap<T> {\n    /// Creates a new, empty heap with a custom comparator function.\n    ///\n    /// # Parameters\n    /// - `comparator`: A function that defines the heap's ordering.\n    ///\n    /// # Returns\n    /// A new `Heap` instance.\n    pub fn new(comparator: fn(&T, &T) -> bool) -> Self {\n        Self {\n            items: vec![],\n            comparator,\n        }\n    }\n\n    /// Creates a heap from a vector and a custom comparator function.\n    ///\n    /// # Parameters\n    /// - `items`: A vector of items to be turned into a heap.\n    /// - `comparator`: A function that defines the heap's ordering.\n    ///\n    /// # Returns\n    /// A `Heap` instance with the elements from the provided vector.\n    pub fn from_vec(items: Vec<T>, comparator: fn(&T, &T) -> bool) -> Self {\n        let mut heap = Self { items, comparator };\n        heap.build_heap();\n        heap\n    }\n\n    /// Constructs the heap from an unsorted vector by applying the heapify process.\n    fn build_heap(&mut self) {\n        let last_parent_idx = (self.len() / 2).wrapping_sub(1);\n        for idx in (0..=last_parent_idx).rev() {\n            self.heapify_down(idx);\n        }\n    }\n\n    /// Returns the number of elements in the heap.\n    ///\n    /// # Returns\n    /// The number of elements in the heap.\n    pub fn len(&self) -> usize {\n        self.items.len()\n    }\n\n    /// Checks if the heap is empty.\n    ///\n    /// # Returns\n    /// `true` if the heap is empty, `false` otherwise.\n    pub fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n\n    /// Adds a new element to the heap and maintains the heap property.\n    ///\n    /// # Parameters\n    /// - `value`: The value to add to the heap.\n    pub fn add(&mut self, value: T) {\n        self.items.push(value);\n        self.heapify_up(self.len() - 1);\n    }\n\n    /// Removes and returns the root element from the heap.\n    ///\n    /// # Returns\n    /// The root element if the heap is not empty, otherwise `None`.\n    pub fn pop(&mut self) -> Option<T> {\n        if self.is_empty() {\n            return None;\n        }\n        let next = Some(self.items.swap_remove(0));\n        if !self.is_empty() {\n            self.heapify_down(0);\n        }\n        next\n    }\n\n    /// Returns an iterator over the elements in the heap.\n    ///\n    /// # Returns\n    /// An iterator over the elements in the heap, in their internal order.\n    pub fn iter(&self) -> Iter<'_, T> {\n        self.items.iter()\n    }\n\n    /// Moves an element upwards to restore the heap property.\n    ///\n    /// # Parameters\n    /// - `idx`: The index of the element to heapify up.\n    fn heapify_up(&mut self, mut idx: usize) {\n        while let Some(pdx) = self.parent_idx(idx) {\n            if (self.comparator)(&self.items[idx], &self.items[pdx]) {\n                self.items.swap(idx, pdx);\n                idx = pdx;\n            } else {\n                break;\n            }\n        }\n    }\n\n    /// Moves an element downwards to restore the heap property.\n    ///\n    /// # Parameters\n    /// - `idx`: The index of the element to heapify down.\n    fn heapify_down(&mut self, mut idx: usize) {\n        while self.children_present(idx) {\n            let cdx = {\n                if self.right_child_idx(idx) >= self.len() {\n                    self.left_child_idx(idx)\n                } else {\n                    let ldx = self.left_child_idx(idx);\n                    let rdx = self.right_child_idx(idx);\n                    if (self.comparator)(&self.items[ldx], &self.items[rdx]) {\n                        ldx\n                    } else {\n                        rdx\n                    }\n                }\n            };\n\n            if (self.comparator)(&self.items[cdx], &self.items[idx]) {\n                self.items.swap(idx, cdx);\n                idx = cdx;\n            } else {\n                break;\n            }\n        }\n    }\n\n    /// Returns the index of the parent of the element at `idx`.\n    ///\n    /// # Parameters\n    /// - `idx`: The index of the element.\n    ///\n    /// # Returns\n    /// The index of the parent element if it exists, otherwise `None`.\n    fn parent_idx(&self, idx: usize) -> Option<usize> {\n        if idx > 0 {\n            Some((idx - 1) / 2)\n        } else {\n            None\n        }\n    }\n\n    /// Checks if the element at `idx` has children.\n    ///\n    /// # Parameters\n    /// - `idx`: The index of the element.\n    ///\n    /// # Returns\n    /// `true` if the element has children, `false` otherwise.\n    fn children_present(&self, idx: usize) -> bool {\n        self.left_child_idx(idx) < self.len()\n    }\n\n    /// Returns the index of the left child of the element at `idx`.\n    ///\n    /// # Parameters\n    /// - `idx`: The index of the element.\n    ///\n    /// # Returns\n    /// The index of the left child.\n    fn left_child_idx(&self, idx: usize) -> usize {\n        idx * 2 + 1\n    }\n\n    /// Returns the index of the right child of the element at `idx`.\n    ///\n    /// # Parameters\n    /// - `idx`: The index of the element.\n    ///\n    /// # Returns\n    /// The index of the right child.\n    fn right_child_idx(&self, idx: usize) -> usize {\n        self.left_child_idx(idx) + 1\n    }\n}\n\nimpl<T> Heap<T>\nwhere\n    T: Ord,\n{\n    /// Creates a new min-heap.\n    ///\n    /// # Returns\n    /// A new `Heap` instance configured as a min-heap.\n    pub fn new_min() -> Heap<T> {\n        Self::new(|a, b| a < b)\n    }\n\n    /// Creates a new max-heap.\n    ///\n    /// # Returns\n    /// A new `Heap` instance configured as a max-heap.\n    pub fn new_max() -> Heap<T> {\n        Self::new(|a, b| a > b)\n    }\n\n    /// Creates a min-heap from an unsorted vector.\n    ///\n    /// # Parameters\n    /// - `items`: A vector of items to be turned into a min-heap.\n    ///\n    /// # Returns\n    /// A `Heap` instance configured as a min-heap.\n    pub fn from_vec_min(items: Vec<T>) -> Heap<T> {\n        Self::from_vec(items, |a, b| a < b)\n    }\n\n    /// Creates a max-heap from an unsorted vector.\n    ///\n    /// # Parameters\n    /// - `items`: A vector of items to be turned into a max-heap.\n    ///\n    /// # Returns\n    /// A `Heap` instance configured as a max-heap.\n    pub fn from_vec_max(items: Vec<T>) -> Heap<T> {\n        Self::from_vec(items, |a, b| a > b)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_empty_heap() {\n        let mut heap: Heap<i32> = Heap::new_max();\n        assert_eq!(heap.pop(), None);\n    }\n\n    #[test]\n    fn test_min_heap() {\n        let mut heap = Heap::new_min();\n        heap.add(4);\n        heap.add(2);\n        heap.add(9);\n        heap.add(11);\n        assert_eq!(heap.len(), 4);\n        assert_eq!(heap.pop(), Some(2));\n        assert_eq!(heap.pop(), Some(4));\n        assert_eq!(heap.pop(), Some(9));\n        heap.add(1);\n        assert_eq!(heap.pop(), Some(1));\n        assert_eq!(heap.pop(), Some(11));\n        assert_eq!(heap.pop(), None);\n    }\n\n    #[test]\n    fn test_max_heap() {\n        let mut heap = Heap::new_max();\n        heap.add(4);\n        heap.add(2);\n        heap.add(9);\n        heap.add(11);\n        assert_eq!(heap.len(), 4);\n        assert_eq!(heap.pop(), Some(11));\n        assert_eq!(heap.pop(), Some(9));\n        assert_eq!(heap.pop(), Some(4));\n        heap.add(1);\n        assert_eq!(heap.pop(), Some(2));\n        assert_eq!(heap.pop(), Some(1));\n        assert_eq!(heap.pop(), None);\n    }\n\n    #[test]\n    fn test_iter_heap() {\n        let mut heap = Heap::new_min();\n        heap.add(4);\n        heap.add(2);\n        heap.add(9);\n        heap.add(11);\n\n        let mut iter = heap.iter();\n        assert_eq!(iter.next(), Some(&2));\n        assert_eq!(iter.next(), Some(&4));\n        assert_eq!(iter.next(), Some(&9));\n        assert_eq!(iter.next(), Some(&11));\n        assert_eq!(iter.next(), None);\n\n        assert_eq!(heap.len(), 4);\n        assert_eq!(heap.pop(), Some(2));\n        assert_eq!(heap.pop(), Some(4));\n        assert_eq!(heap.pop(), Some(9));\n        assert_eq!(heap.pop(), Some(11));\n        assert_eq!(heap.pop(), None);\n    }\n\n    #[test]\n    fn test_from_vec_min() {\n        let vec = vec![3, 1, 4, 1, 5, 9, 2, 6, 5];\n        let mut heap = Heap::from_vec_min(vec);\n        assert_eq!(heap.len(), 9);\n        assert_eq!(heap.pop(), Some(1));\n        assert_eq!(heap.pop(), Some(1));\n        assert_eq!(heap.pop(), Some(2));\n        heap.add(0);\n        assert_eq!(heap.pop(), Some(0));\n    }\n\n    #[test]\n    fn test_from_vec_max() {\n        let vec = vec![3, 1, 4, 1, 5, 9, 2, 6, 5];\n        let mut heap = Heap::from_vec_max(vec);\n        assert_eq!(heap.len(), 9);\n        assert_eq!(heap.pop(), Some(9));\n        assert_eq!(heap.pop(), Some(6));\n        assert_eq!(heap.pop(), Some(5));\n        heap.add(10);\n        assert_eq!(heap.pop(), Some(10));\n    }\n}\n"
  },
  {
    "path": "src/data_structures/lazy_segment_tree.rs",
    "content": "use std::fmt::{Debug, Display};\nuse std::ops::{Add, AddAssign, Range};\n\npub struct LazySegmentTree<T: Debug + Default + Ord + Copy + Display + AddAssign + Add<Output = T>>\n{\n    len: usize,\n    tree: Vec<T>,\n    lazy: Vec<Option<T>>,\n    merge: fn(T, T) -> T,\n}\n\nimpl<T: Debug + Default + Ord + Copy + Display + AddAssign + Add<Output = T>> LazySegmentTree<T> {\n    pub fn from_vec(arr: &[T], merge: fn(T, T) -> T) -> Self {\n        let len = arr.len();\n        let mut sgtr = LazySegmentTree {\n            len,\n            tree: vec![T::default(); 4 * len],\n            lazy: vec![None; 4 * len],\n            merge,\n        };\n        if len != 0 {\n            sgtr.build_recursive(arr, 1, 0..len, merge);\n        }\n        sgtr\n    }\n\n    fn build_recursive(\n        &mut self,\n        arr: &[T],\n        idx: usize,\n        range: Range<usize>,\n        merge: fn(T, T) -> T,\n    ) {\n        if range.end - range.start == 1 {\n            self.tree[idx] = arr[range.start];\n        } else {\n            let mid = range.start + (range.end - range.start) / 2;\n            self.build_recursive(arr, 2 * idx, range.start..mid, merge);\n            self.build_recursive(arr, 2 * idx + 1, mid..range.end, merge);\n            self.tree[idx] = merge(self.tree[2 * idx], self.tree[2 * idx + 1]);\n        }\n    }\n\n    pub fn query(&mut self, range: Range<usize>) -> Option<T> {\n        self.query_recursive(1, 0..self.len, &range)\n    }\n\n    fn query_recursive(\n        &mut self,\n        idx: usize,\n        element_range: Range<usize>,\n        query_range: &Range<usize>,\n    ) -> Option<T> {\n        if element_range.start >= query_range.end || element_range.end <= query_range.start {\n            return None;\n        }\n        if self.lazy[idx].is_some() {\n            self.propagation(idx, &element_range, T::default());\n        }\n        if element_range.start >= query_range.start && element_range.end <= query_range.end {\n            return Some(self.tree[idx]);\n        }\n        let mid = element_range.start + (element_range.end - element_range.start) / 2;\n        let left = self.query_recursive(idx * 2, element_range.start..mid, query_range);\n        let right = self.query_recursive(idx * 2 + 1, mid..element_range.end, query_range);\n        match (left, right) {\n            (None, None) => None,\n            (None, Some(r)) => Some(r),\n            (Some(l), None) => Some(l),\n            (Some(l), Some(r)) => Some((self.merge)(l, r)),\n        }\n    }\n\n    pub fn update(&mut self, target_range: Range<usize>, val: T) {\n        self.update_recursive(1, 0..self.len, &target_range, val);\n    }\n\n    fn update_recursive(\n        &mut self,\n        idx: usize,\n        element_range: Range<usize>,\n        target_range: &Range<usize>,\n        val: T,\n    ) {\n        if element_range.start >= target_range.end || element_range.end <= target_range.start {\n            return;\n        }\n        if element_range.end - element_range.start == 1 {\n            self.tree[idx] += val;\n            return;\n        }\n        if element_range.start >= target_range.start && element_range.end <= target_range.end {\n            self.lazy[idx] = match self.lazy[idx] {\n                Some(lazy) => Some(lazy + val),\n                None => Some(val),\n            };\n            return;\n        }\n        if self.lazy[idx].is_some() && self.lazy[idx].unwrap() != T::default() {\n            self.propagation(idx, &element_range, T::default());\n        }\n        let mid = element_range.start + (element_range.end - element_range.start) / 2;\n        self.update_recursive(idx * 2, element_range.start..mid, target_range, val);\n        self.update_recursive(idx * 2 + 1, mid..element_range.end, target_range, val);\n        self.tree[idx] = (self.merge)(self.tree[idx * 2], self.tree[idx * 2 + 1]);\n        self.lazy[idx] = Some(T::default());\n    }\n\n    fn propagation(&mut self, idx: usize, element_range: &Range<usize>, parent_lazy: T) {\n        if element_range.end - element_range.start == 1 {\n            self.tree[idx] += parent_lazy;\n            return;\n        }\n\n        let lazy = self.lazy[idx].unwrap_or_default();\n        self.lazy[idx] = None;\n\n        let mid = element_range.start + (element_range.end - element_range.start) / 2;\n        self.propagation(idx * 2, &(element_range.start..mid), parent_lazy + lazy);\n        self.propagation(idx * 2 + 1, &(mid..element_range.end), parent_lazy + lazy);\n        self.tree[idx] = (self.merge)(self.tree[idx * 2], self.tree[idx * 2 + 1]);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use quickcheck::TestResult;\n    use quickcheck_macros::quickcheck;\n    use std::cmp::{max, min};\n\n    #[test]\n    fn test_min_segments() {\n        let vec = vec![-30, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8];\n        let mut min_seg_tree = LazySegmentTree::from_vec(&vec, min);\n        // [-30, 2, -4, 7, (3, -5, 6), 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(-5), min_seg_tree.query(4..7));\n        // [(-30, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8)]\n        assert_eq!(Some(-30), min_seg_tree.query(0..vec.len()));\n        // [(-30, 2), -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(-30), min_seg_tree.query(0..2));\n        // [-30, (2, -4), 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(-4), min_seg_tree.query(1..3));\n        // [-30, (2, -4, 7, 3, -5, 6), 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(-5), min_seg_tree.query(1..7));\n    }\n\n    #[test]\n    fn test_max_segments() {\n        let vec = vec![-30, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8];\n        let mut max_seg_tree = LazySegmentTree::from_vec(&vec, max);\n        // [-30, 2, -4, 7, (3, -5, 6), 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(6), max_seg_tree.query(4..7));\n        // [(-30, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8)]\n        assert_eq!(Some(15), max_seg_tree.query(0..vec.len()));\n        // [(-30, 2), -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(2), max_seg_tree.query(0..2));\n        // [-30, (2, -4), 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(2), max_seg_tree.query(1..3));\n        // [-30, (2, -4, 7, 3, -5, 6), 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(7), max_seg_tree.query(1..7));\n    }\n\n    #[test]\n    fn test_sum_segments() {\n        let vec = vec![-30, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8];\n        let mut max_seg_tree = LazySegmentTree::from_vec(&vec, |x, y| x + y);\n        // [-30, 2, -4, 7, (3, -5, 6), 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(4), max_seg_tree.query(4..7));\n        // [(-30, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8)]\n        assert_eq!(Some(7), max_seg_tree.query(0..vec.len()));\n        // [(-30, 2), -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(-28), max_seg_tree.query(0..2));\n        // [-30, (2, -4), 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(-2), max_seg_tree.query(1..3));\n        // [-30, (2, -4, 7, 3, -5, 6), 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(9), max_seg_tree.query(1..7));\n    }\n\n    #[test]\n    fn test_update_segments_tiny() {\n        let vec = vec![0, 0, 0, 0, 0];\n        let mut update_seg_tree = LazySegmentTree::from_vec(&vec, |x, y| x + y);\n        update_seg_tree.update(0..3, 3);\n        update_seg_tree.update(2..5, 3);\n        assert_eq!(Some(3), update_seg_tree.query(0..1));\n        assert_eq!(Some(3), update_seg_tree.query(1..2));\n        assert_eq!(Some(6), update_seg_tree.query(2..3));\n        assert_eq!(Some(3), update_seg_tree.query(3..4));\n        assert_eq!(Some(3), update_seg_tree.query(4..5));\n    }\n\n    #[test]\n    fn test_update_segments() {\n        let vec = vec![-30, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8];\n        let mut update_seg_tree = LazySegmentTree::from_vec(&vec, |x, y| x + y);\n        // -> [-30, (5, -1, 10, 6), -5, 6, 11, -20, 9, 14, 15, 5, 2, -8]\n        update_seg_tree.update(1..5, 3);\n\n        // [-30, 5, -1, 10, (6 -5, 6), 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(7), update_seg_tree.query(4..7));\n        // [(-30, 5, -1, 10, 6 , -5, 6, 11, -20, 9, 14, 15, 5, 2, -8)]\n        assert_eq!(Some(19), update_seg_tree.query(0..vec.len()));\n        // [(-30, 5), -1, 10, 6, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(-25), update_seg_tree.query(0..2));\n        // [-30, (5, -1), 10, 6, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(4), update_seg_tree.query(1..3));\n        // [-30, (5, -1, 10, 6, -5, 6), 11, -20, 9, 14, 15, 5, 2, -8]\n        assert_eq!(Some(21), update_seg_tree.query(1..7));\n    }\n\n    // Some properties over segment trees:\n    //  When asking for the range of the overall array, return the same as iter().min() or iter().max(), etc.\n    //  When asking for an interval containing a single value, return this value, no matter the merge function\n\n    #[quickcheck]\n    fn check_overall_interval_min(array: Vec<i32>) -> TestResult {\n        let mut seg_tree = LazySegmentTree::from_vec(&array, min);\n        TestResult::from_bool(array.iter().min().copied() == seg_tree.query(0..array.len()))\n    }\n\n    #[quickcheck]\n    fn check_overall_interval_max(array: Vec<i32>) -> TestResult {\n        let mut seg_tree = LazySegmentTree::from_vec(&array, max);\n        TestResult::from_bool(array.iter().max().copied() == seg_tree.query(0..array.len()))\n    }\n\n    #[quickcheck]\n    fn check_overall_interval_sum(array: Vec<i32>) -> TestResult {\n        let mut seg_tree = LazySegmentTree::from_vec(&array, max);\n        TestResult::from_bool(array.iter().max().copied() == seg_tree.query(0..array.len()))\n    }\n\n    #[quickcheck]\n    fn check_single_interval_min(array: Vec<i32>) -> TestResult {\n        let mut seg_tree = LazySegmentTree::from_vec(&array, min);\n        for (i, value) in array.into_iter().enumerate() {\n            let res = seg_tree.query(Range {\n                start: i,\n                end: i + 1,\n            });\n            if res != Some(value) {\n                return TestResult::error(format!(\"Expected {:?}, got {:?}\", Some(value), res));\n            }\n        }\n        TestResult::passed()\n    }\n\n    #[quickcheck]\n    fn check_single_interval_max(array: Vec<i32>) -> TestResult {\n        let mut seg_tree = LazySegmentTree::from_vec(&array, max);\n        for (i, value) in array.into_iter().enumerate() {\n            let res = seg_tree.query(Range {\n                start: i,\n                end: i + 1,\n            });\n            if res != Some(value) {\n                return TestResult::error(format!(\"Expected {:?}, got {:?}\", Some(value), res));\n            }\n        }\n        TestResult::passed()\n    }\n\n    #[quickcheck]\n    fn check_single_interval_sum(array: Vec<i32>) -> TestResult {\n        let mut seg_tree = LazySegmentTree::from_vec(&array, max);\n        for (i, value) in array.into_iter().enumerate() {\n            let res = seg_tree.query(Range {\n                start: i,\n                end: i + 1,\n            });\n            if res != Some(value) {\n                return TestResult::error(format!(\"Expected {:?}, got {:?}\", Some(value), res));\n            }\n        }\n        TestResult::passed()\n    }\n}\n"
  },
  {
    "path": "src/data_structures/linked_list.rs",
    "content": "use std::fmt::{self, Display, Formatter};\nuse std::marker::PhantomData;\nuse std::ptr::NonNull;\n\npub struct Node<T> {\n    pub val: T,\n    pub next: Option<NonNull<Node<T>>>,\n    prev: Option<NonNull<Node<T>>>,\n}\n\nimpl<T> Node<T> {\n    fn new(t: T) -> Node<T> {\n        Node {\n            val: t,\n            prev: None,\n            next: None,\n        }\n    }\n}\n\npub struct LinkedList<T> {\n    pub length: u32,\n    pub head: Option<NonNull<Node<T>>>,\n    pub tail: Option<NonNull<Node<T>>>,\n    // Act like we own boxed nodes since we construct and leak them\n    marker: PhantomData<Box<Node<T>>>,\n}\n\nimpl<T> Default for LinkedList<T> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<T> LinkedList<T> {\n    pub fn new() -> Self {\n        Self {\n            length: 0,\n            head: None,\n            tail: None,\n            marker: PhantomData,\n        }\n    }\n\n    pub fn insert_at_head(&mut self, obj: T) {\n        let mut node = Box::new(Node::new(obj));\n        node.next = self.head;\n        node.prev = None;\n        let node_ptr = NonNull::new(Box::into_raw(node));\n        match self.head {\n            None => self.tail = node_ptr,\n            Some(head_ptr) => unsafe { (*head_ptr.as_ptr()).prev = node_ptr },\n        }\n        self.head = node_ptr;\n        self.length += 1;\n    }\n\n    pub fn insert_at_tail(&mut self, obj: T) {\n        let mut node = Box::new(Node::new(obj));\n        node.next = None;\n        node.prev = self.tail;\n        let node_ptr = NonNull::new(Box::into_raw(node));\n        match self.tail {\n            None => self.head = node_ptr,\n            Some(tail_ptr) => unsafe { (*tail_ptr.as_ptr()).next = node_ptr },\n        }\n        self.tail = node_ptr;\n        self.length += 1;\n    }\n\n    pub fn insert_at_ith(&mut self, index: u32, obj: T) {\n        if self.length < index {\n            panic!(\"Index out of bounds\");\n        }\n\n        if index == 0 || self.head.is_none() {\n            self.insert_at_head(obj);\n            return;\n        }\n\n        if self.length == index {\n            self.insert_at_tail(obj);\n            return;\n        }\n\n        if let Some(mut ith_node) = self.head {\n            for _ in 0..index {\n                unsafe {\n                    match (*ith_node.as_ptr()).next {\n                        None => panic!(\"Index out of bounds\"),\n                        Some(next_ptr) => ith_node = next_ptr,\n                    }\n                }\n            }\n\n            let mut node = Box::new(Node::new(obj));\n            unsafe {\n                node.prev = (*ith_node.as_ptr()).prev;\n                node.next = Some(ith_node);\n                if let Some(p) = (*ith_node.as_ptr()).prev {\n                    let node_ptr = NonNull::new(Box::into_raw(node));\n                    println!(\"{:?}\", (*p.as_ptr()).next);\n                    (*p.as_ptr()).next = node_ptr;\n                    (*ith_node.as_ptr()).prev = node_ptr;\n                    self.length += 1;\n                }\n            }\n        }\n    }\n\n    pub fn delete_head(&mut self) -> Option<T> {\n        // Safety: head_ptr points to a leaked boxed node managed by this list\n        // We reassign pointers that pointed to the head node\n        if self.length == 0 {\n            return None;\n        }\n\n        self.head.map(|head_ptr| unsafe {\n            let old_head = Box::from_raw(head_ptr.as_ptr());\n            match old_head.next {\n                Some(mut next_ptr) => next_ptr.as_mut().prev = None,\n                None => self.tail = None,\n            }\n            self.head = old_head.next;\n            self.length = self.length.checked_add_signed(-1).unwrap_or(0);\n            old_head.val\n        })\n        // None\n    }\n\n    pub fn delete_tail(&mut self) -> Option<T> {\n        // Safety: tail_ptr points to a leaked boxed node managed by this list\n        // We reassign pointers that pointed to the tail node\n        self.tail.map(|tail_ptr| unsafe {\n            let old_tail = Box::from_raw(tail_ptr.as_ptr());\n            match old_tail.prev {\n                Some(mut prev) => prev.as_mut().next = None,\n                None => self.head = None,\n            }\n            self.tail = old_tail.prev;\n            self.length -= 1;\n            old_tail.val\n        })\n    }\n\n    pub fn delete_ith(&mut self, index: u32) -> Option<T> {\n        if self.length <= index {\n            panic!(\"Index out of bounds\");\n        }\n\n        if index == 0 || self.head.is_none() {\n            return self.delete_head();\n        }\n\n        if self.length - 1 == index {\n            return self.delete_tail();\n        }\n\n        if let Some(mut ith_node) = self.head {\n            for _ in 0..index {\n                unsafe {\n                    match (*ith_node.as_ptr()).next {\n                        None => panic!(\"Index out of bounds\"),\n                        Some(next_ptr) => ith_node = next_ptr,\n                    }\n                }\n            }\n\n            unsafe {\n                let old_ith = Box::from_raw(ith_node.as_ptr());\n                if let Some(mut prev) = old_ith.prev {\n                    prev.as_mut().next = old_ith.next;\n                }\n                if let Some(mut next) = old_ith.next {\n                    next.as_mut().prev = old_ith.prev;\n                }\n\n                self.length -= 1;\n                Some(old_ith.val)\n            }\n        } else {\n            None\n        }\n    }\n\n    pub fn get(&self, index: i32) -> Option<&T> {\n        Self::get_ith_node(self.head, index).map(|ptr| unsafe { &(*ptr.as_ptr()).val })\n    }\n\n    fn get_ith_node(node: Option<NonNull<Node<T>>>, index: i32) -> Option<NonNull<Node<T>>> {\n        match node {\n            None => None,\n            Some(next_ptr) => match index {\n                0 => Some(next_ptr),\n                _ => Self::get_ith_node(unsafe { (*next_ptr.as_ptr()).next }, index - 1),\n            },\n        }\n    }\n}\n\nimpl<T> Drop for LinkedList<T> {\n    fn drop(&mut self) {\n        // Pop items until there are none left\n        while self.delete_head().is_some() {}\n    }\n}\n\nimpl<T> Display for LinkedList<T>\nwhere\n    T: Display,\n{\n    fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n        match self.head {\n            Some(node) => write!(f, \"{}\", unsafe { node.as_ref() }),\n            None => Ok(()),\n        }\n    }\n}\n\nimpl<T> Display for Node<T>\nwhere\n    T: Display,\n{\n    fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n        match self.next {\n            Some(node) => write!(f, \"{}, {}\", self.val, unsafe { node.as_ref() }),\n            None => write!(f, \"{}\", self.val),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::convert::TryInto;\n\n    use super::LinkedList;\n\n    #[test]\n    fn insert_at_tail_works() {\n        let mut list = LinkedList::<i32>::new();\n        let second_value = 2;\n        list.insert_at_tail(1);\n        list.insert_at_tail(second_value);\n        println!(\"Linked List is {list}\");\n        match list.get(1) {\n            Some(val) => assert_eq!(*val, second_value),\n            None => panic!(\"Expected to find {second_value} at index 1\"),\n        }\n    }\n    #[test]\n    fn insert_at_head_works() {\n        let mut list = LinkedList::<i32>::new();\n        let second_value = 2;\n        list.insert_at_head(1);\n        list.insert_at_head(second_value);\n        println!(\"Linked List is {list}\");\n        match list.get(0) {\n            Some(val) => assert_eq!(*val, second_value),\n            None => panic!(\"Expected to find {second_value} at index 0\"),\n        }\n    }\n\n    #[test]\n    fn insert_at_ith_can_add_to_tail() {\n        let mut list = LinkedList::<i32>::new();\n        let second_value = 2;\n        list.insert_at_ith(0, 0);\n        list.insert_at_ith(1, second_value);\n        println!(\"Linked List is {list}\");\n        match list.get(1) {\n            Some(val) => assert_eq!(*val, second_value),\n            None => panic!(\"Expected to find {second_value} at index 1\"),\n        }\n    }\n\n    #[test]\n    fn insert_at_ith_can_add_to_head() {\n        let mut list = LinkedList::<i32>::new();\n        let second_value = 2;\n        list.insert_at_ith(0, 1);\n        list.insert_at_ith(0, second_value);\n        println!(\"Linked List is {list}\");\n        match list.get(0) {\n            Some(val) => assert_eq!(*val, second_value),\n            None => panic!(\"Expected to find {second_value} at index 0\"),\n        }\n    }\n\n    #[test]\n    fn insert_at_ith_can_add_to_middle() {\n        let mut list = LinkedList::<i32>::new();\n        let second_value = 2;\n        let third_value = 3;\n        list.insert_at_ith(0, 1);\n        list.insert_at_ith(1, second_value);\n        list.insert_at_ith(1, third_value);\n        println!(\"Linked List is {list}\");\n        match list.get(1) {\n            Some(val) => assert_eq!(*val, third_value),\n            None => panic!(\"Expected to find {third_value} at index 1\"),\n        }\n\n        match list.get(2) {\n            Some(val) => assert_eq!(*val, second_value),\n            None => panic!(\"Expected to find {second_value} at index 1\"),\n        }\n    }\n\n    #[test]\n    fn insert_at_ith_and_delete_at_ith_in_the_middle() {\n        // Insert and delete in the middle of the list to ensure pointers are updated correctly\n        let mut list = LinkedList::<i32>::new();\n        let first_value = 0;\n        let second_value = 1;\n        let third_value = 2;\n        let fourth_value = 3;\n\n        list.insert_at_ith(0, first_value);\n        list.insert_at_ith(1, fourth_value);\n        list.insert_at_ith(1, third_value);\n        list.insert_at_ith(1, second_value);\n\n        list.delete_ith(2);\n        list.insert_at_ith(2, third_value);\n\n        for (i, expected) in [\n            (0, first_value),\n            (1, second_value),\n            (2, third_value),\n            (3, fourth_value),\n        ] {\n            match list.get(i) {\n                Some(val) => assert_eq!(*val, expected),\n                None => panic!(\"Expected to find {expected} at index {i}\"),\n            }\n        }\n    }\n\n    #[test]\n    fn insert_at_ith_and_delete_ith_work_over_many_iterations() {\n        let mut list = LinkedList::<i32>::new();\n        for i in 0..100 {\n            list.insert_at_ith(i, i.try_into().unwrap());\n        }\n\n        // Pop even numbers to 50\n        for i in 0..50 {\n            println!(\"list.length {}\", list.length);\n            if i % 2 == 0 {\n                list.delete_ith(i);\n            }\n        }\n\n        assert_eq!(list.length, 75);\n\n        // Insert even numbers back\n        for i in 0..50 {\n            if i % 2 == 0 {\n                list.insert_at_ith(i, i.try_into().unwrap());\n            }\n        }\n\n        assert_eq!(list.length, 100);\n\n        // Ensure numbers were adderd back and we're able to traverse nodes\n        if let Some(val) = list.get(78) {\n            assert_eq!(*val, 78);\n        } else {\n            panic!(\"Expected to find 78 at index 78\");\n        }\n    }\n\n    #[test]\n    fn delete_tail_works() {\n        let mut list = LinkedList::<i32>::new();\n        let first_value = 1;\n        let second_value = 2;\n        list.insert_at_tail(first_value);\n        list.insert_at_tail(second_value);\n        match list.delete_tail() {\n            Some(val) => assert_eq!(val, 2),\n            None => panic!(\"Expected to remove {second_value} at tail\"),\n        }\n\n        println!(\"Linked List is {list}\");\n        match list.get(0) {\n            Some(val) => assert_eq!(*val, first_value),\n            None => panic!(\"Expected to find {first_value} at index 0\"),\n        }\n    }\n\n    #[test]\n    fn delete_head_works() {\n        let mut list = LinkedList::<i32>::new();\n        let first_value = 1;\n        let second_value = 2;\n        list.insert_at_tail(first_value);\n        list.insert_at_tail(second_value);\n        match list.delete_head() {\n            Some(val) => assert_eq!(val, 1),\n            None => panic!(\"Expected to remove {first_value} at head\"),\n        }\n\n        println!(\"Linked List is {list}\");\n        match list.get(0) {\n            Some(val) => assert_eq!(*val, second_value),\n            None => panic!(\"Expected to find {second_value} at index 0\"),\n        }\n    }\n\n    #[test]\n    fn delete_ith_can_delete_at_tail() {\n        let mut list = LinkedList::<i32>::new();\n        let first_value = 1;\n        let second_value = 2;\n        list.insert_at_tail(first_value);\n        list.insert_at_tail(second_value);\n        match list.delete_ith(1) {\n            Some(val) => assert_eq!(val, 2),\n            None => panic!(\"Expected to remove {second_value} at tail\"),\n        }\n\n        assert_eq!(list.length, 1);\n    }\n\n    #[test]\n    fn delete_ith_can_delete_at_head() {\n        let mut list = LinkedList::<i32>::new();\n        let first_value = 1;\n        let second_value = 2;\n        list.insert_at_tail(first_value);\n        list.insert_at_tail(second_value);\n        match list.delete_ith(0) {\n            Some(val) => assert_eq!(val, 1),\n            None => panic!(\"Expected to remove {first_value} at tail\"),\n        }\n\n        assert_eq!(list.length, 1);\n    }\n\n    #[test]\n    fn delete_ith_can_delete_in_middle() {\n        let mut list = LinkedList::<i32>::new();\n        let first_value = 1;\n        let second_value = 2;\n        let third_value = 3;\n        list.insert_at_tail(first_value);\n        list.insert_at_tail(second_value);\n        list.insert_at_tail(third_value);\n        match list.delete_ith(1) {\n            Some(val) => assert_eq!(val, 2),\n            None => panic!(\"Expected to remove {second_value} at tail\"),\n        }\n\n        match list.get(1) {\n            Some(val) => assert_eq!(*val, third_value),\n            None => panic!(\"Expected to find {third_value} at index 1\"),\n        }\n    }\n\n    #[test]\n    fn create_numeric_list() {\n        let mut list = LinkedList::<i32>::new();\n        list.insert_at_tail(1);\n        list.insert_at_tail(2);\n        list.insert_at_tail(3);\n        println!(\"Linked List is {list}\");\n        assert_eq!(3, list.length);\n    }\n\n    #[test]\n    fn create_string_list() {\n        let mut list_str = LinkedList::<String>::new();\n        list_str.insert_at_tail(\"A\".to_string());\n        list_str.insert_at_tail(\"B\".to_string());\n        list_str.insert_at_tail(\"C\".to_string());\n        println!(\"Linked List is {list_str}\");\n        assert_eq!(3, list_str.length);\n    }\n\n    #[test]\n    fn get_by_index_in_numeric_list() {\n        let mut list = LinkedList::<i32>::new();\n        list.insert_at_tail(1);\n        list.insert_at_tail(2);\n        println!(\"Linked List is {list}\");\n        let retrived_item = list.get(1);\n        assert!(retrived_item.is_some());\n        assert_eq!(2, *retrived_item.unwrap());\n    }\n\n    #[test]\n    fn get_by_index_in_string_list() {\n        let mut list_str = LinkedList::<String>::new();\n        list_str.insert_at_tail(\"A\".to_string());\n        list_str.insert_at_tail(\"B\".to_string());\n        println!(\"Linked List is {list_str}\");\n        let retrived_item = list_str.get(1);\n        assert!(retrived_item.is_some());\n        assert_eq!(\"B\", *retrived_item.unwrap());\n    }\n\n    #[test]\n    #[should_panic(expected = \"Index out of bounds\")]\n    fn delete_ith_panics_if_index_equals_length() {\n        let mut list = LinkedList::<i32>::new();\n        list.insert_at_tail(1);\n        list.insert_at_tail(2);\n        // length is 2, so index 2 is out of bounds\n        list.delete_ith(2);\n    }\n}\n"
  },
  {
    "path": "src/data_structures/mod.rs",
    "content": "mod avl_tree;\nmod b_tree;\nmod binary_search_tree;\nmod fenwick_tree;\nmod floyds_algorithm;\npub mod graph;\nmod hash_table;\nmod heap;\nmod lazy_segment_tree;\nmod linked_list;\nmod probabilistic;\nmod queue;\nmod range_minimum_query;\nmod rb_tree;\nmod segment_tree;\nmod segment_tree_recursive;\nmod skip_list;\nmod stack_using_singly_linked_list;\nmod treap;\nmod trie;\nmod union_find;\nmod veb_tree;\n\npub use self::avl_tree::AVLTree;\npub use self::b_tree::BTree;\npub use self::binary_search_tree::BinarySearchTree;\npub use self::fenwick_tree::FenwickTree;\npub use self::floyds_algorithm::{detect_cycle, has_cycle};\npub use self::graph::DirectedGraph;\npub use self::graph::UndirectedGraph;\npub use self::hash_table::HashTable;\npub use self::heap::Heap;\npub use self::lazy_segment_tree::LazySegmentTree;\npub use self::linked_list::LinkedList;\npub use self::probabilistic::bloom_filter;\npub use self::probabilistic::count_min_sketch;\npub use self::queue::Queue;\npub use self::range_minimum_query::RangeMinimumQuery;\npub use self::rb_tree::RBTree;\npub use self::segment_tree::SegmentTree;\npub use self::segment_tree_recursive::SegmentTree as SegmentTreeRecursive;\npub use self::skip_list::SkipList;\npub use self::stack_using_singly_linked_list::Stack;\npub use self::treap::Treap;\npub use self::trie::Trie;\npub use self::union_find::UnionFind;\npub use self::veb_tree::VebTree;\n"
  },
  {
    "path": "src/data_structures/probabilistic/bloom_filter.rs",
    "content": "use std::collections::hash_map::{DefaultHasher, RandomState};\nuse std::hash::{BuildHasher, Hash, Hasher};\n\n/// A Bloom Filter <https://en.wikipedia.org/wiki/Bloom_filter> is a probabilistic data structure testing whether an element belongs to a set or not\n/// Therefore, its contract looks very close to the one of a set, for example a `HashSet`\npub trait BloomFilter<Item: Hash> {\n    fn insert(&mut self, item: Item);\n    fn contains(&self, item: &Item) -> bool;\n}\n\n/// What is the point of using a Bloom Filter if it acts like a Set?\n/// Let's imagine we have a huge number of elements to store (like un unbounded data stream) a Set storing every element will most likely take up too much space, at some point.\n/// As other probabilistic data structures like Count-min Sketch, the goal of a Bloom Filter is to trade off exactitude for constant space.\n/// We won't have a strictly exact result of whether the value belongs to the set, but we'll use constant space instead\n\n/// Let's start with the basic idea behind the implementation\n/// Let's start by trying to make a `HashSet` with constant space:\n/// Instead of storing every element and grow the set infinitely, let's use a vector with constant capacity `CAPACITY`\n/// Each element of this vector will be a boolean.\n/// When a new element is inserted, we hash its value and set the index at index `hash(item) % CAPACITY` to `true`\n/// When looking for an item, we hash its value and retrieve the boolean at index `hash(item) % CAPACITY`\n/// If it's `false` it's absolutely sure the item isn't present\n/// If it's `true` the item may be present, or maybe another one produces the same hash\n#[allow(dead_code)]\n#[derive(Debug)]\nstruct BasicBloomFilter<const CAPACITY: usize> {\n    vec: [bool; CAPACITY],\n}\n\nimpl<const CAPACITY: usize> Default for BasicBloomFilter<CAPACITY> {\n    fn default() -> Self {\n        Self {\n            vec: [false; CAPACITY],\n        }\n    }\n}\n\nimpl<Item: Hash, const CAPACITY: usize> BloomFilter<Item> for BasicBloomFilter<CAPACITY> {\n    fn insert(&mut self, item: Item) {\n        let mut hasher = DefaultHasher::new();\n        item.hash(&mut hasher);\n        let idx = (hasher.finish() % CAPACITY as u64) as usize;\n        self.vec[idx] = true;\n    }\n\n    fn contains(&self, item: &Item) -> bool {\n        let mut hasher = DefaultHasher::new();\n        item.hash(&mut hasher);\n        let idx = (hasher.finish() % CAPACITY as u64) as usize;\n        self.vec[idx]\n    }\n}\n\n/// Can we improve it? Certainly, in different ways.\n/// One pattern you may have identified here is that we use a \"binary array\" (a vector of binary values)\n/// For instance, we might have `[0,1,0,0,1,0]`, which is actually the binary representation of 9\n/// This means we can immediately replace our `Vec<bool>` by an actual number\n/// What would it mean to set a `1` at index `i`?\n/// Imagine a `CAPACITY` of `6`. The initial value for our mask is `000000`.\n/// We want to store `\"Bloom\"`. Its hash modulo `CAPACITY` is `5`. Which means we need to set `1` at the last index.\n/// It can be performed by doing `000000 | 000001`\n/// Meaning we can hash the item value, use a modulo to find the index, and do a binary `or` between the current number and the index\n#[allow(dead_code)]\n#[derive(Debug, Default)]\nstruct SingleBinaryBloomFilter {\n    fingerprint: u128, // let's use 128 bits, the equivalent of using CAPACITY=128 in the previous example\n}\n\n/// Given a value and a hash function, compute the hash and return the bit mask\nfn mask_128<T: Hash>(hasher: &mut DefaultHasher, item: T) -> u128 {\n    item.hash(hasher);\n    let idx = (hasher.finish() % 128) as u32;\n    // idx is where we want to put a 1, let's convert this into a proper binary mask\n    2_u128.pow(idx)\n}\n\nimpl<T: Hash> BloomFilter<T> for SingleBinaryBloomFilter {\n    fn insert(&mut self, item: T) {\n        self.fingerprint |= mask_128(&mut DefaultHasher::new(), &item);\n    }\n\n    fn contains(&self, item: &T) -> bool {\n        (self.fingerprint & mask_128(&mut DefaultHasher::new(), item)) > 0\n    }\n}\n\n/// We may have made some progress in term of CPU efficiency, using binary operators.\n/// But we might still run into a lot of collisions with a single 128-bits number.\n/// Can we use greater numbers then? Currently, our implementation is limited to 128 bits.\n///\n/// Should we go back to using an array, then?\n/// We could! But instead of using `Vec<bool>` we could use `Vec<u8>`.\n/// Each `u8` can act as a mask as we've done before, and is actually 1 byte in memory (same as a boolean!)\n/// That'd allow us to go over 128 bits, but would divide by 8 the memory footprint.\n/// That's one thing, and will involve dividing / shifting by 8 in different places.\n///\n/// But still, can we reduce the collisions furthermore?\n///\n/// As we did with count-min-sketch, we could use multiple hash function.\n/// When inserting a value, we compute its hash with every hash function (`hash_i`) and perform the same operation as above (the OR with `fingerprint`)\n/// Then when looking for a value, if **ANY** of the tests (`hash` then `AND`) returns 0 then this means the value is missing from the set, otherwise it would have returned 1\n/// If it returns `1`, it **may** be that the item is present, but could also be a collision\n/// This is what a Bloom Filter is about: returning `false` means the value is necessarily absent, and returning true means it may be present\npub struct MultiBinaryBloomFilter {\n    filter_size: usize,\n    bytes: Vec<u8>,\n    hash_builders: Vec<RandomState>,\n}\n\nimpl MultiBinaryBloomFilter {\n    pub fn with_dimensions(filter_size: usize, hash_count: usize) -> Self {\n        let bytes_count = filter_size / 8 + usize::from(!filter_size.is_multiple_of(8)); // we need 8 times less entries in the array, since we are using bytes. Careful that we have at least one element though\n        Self {\n            filter_size,\n            bytes: vec![0; bytes_count],\n            hash_builders: vec![RandomState::new(); hash_count],\n        }\n    }\n\n    pub fn from_estimate(\n        estimated_count_of_items: usize,\n        max_false_positive_probability: f64,\n    ) -> Self {\n        // Check Wikipedia for these formulae\n        let optimal_filter_size = (-(estimated_count_of_items as f64)\n            * max_false_positive_probability.ln()\n            / (2.0_f64.ln().powi(2)))\n        .ceil() as usize;\n        let optimal_hash_count = ((optimal_filter_size as f64 / estimated_count_of_items as f64)\n            * 2.0_f64.ln())\n        .ceil() as usize;\n        Self::with_dimensions(optimal_filter_size, optimal_hash_count)\n    }\n}\n\nimpl<Item: Hash> BloomFilter<Item> for MultiBinaryBloomFilter {\n    fn insert(&mut self, item: Item) {\n        for builder in &self.hash_builders {\n            let mut hasher = builder.build_hasher();\n            item.hash(&mut hasher);\n            let hash = builder.hash_one(&item);\n            let index = hash % self.filter_size as u64;\n            let byte_index = index as usize / 8; // this is this byte that we need to modify\n            let bit_index = (index % 8) as u8; // we cannot only OR with value 1 this time, since we have 8 bits\n            self.bytes[byte_index] |= 1 << bit_index;\n        }\n    }\n\n    fn contains(&self, item: &Item) -> bool {\n        for builder in &self.hash_builders {\n            let mut hasher = builder.build_hasher();\n            item.hash(&mut hasher);\n            let hash = builder.hash_one(item);\n            let index = hash % self.filter_size as u64;\n            let byte_index = index as usize / 8; // this is this byte that we need to modify\n            let bit_index = (index % 8) as u8; // we cannot only OR with value 1 this time, since we have 8 bits\n            if self.bytes[byte_index] & (1 << bit_index) == 0 {\n                return false;\n            }\n        }\n        true\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::data_structures::probabilistic::bloom_filter::{\n        BasicBloomFilter, BloomFilter, MultiBinaryBloomFilter, SingleBinaryBloomFilter,\n    };\n    use quickcheck::{Arbitrary, Gen};\n    use quickcheck_macros::quickcheck;\n    use std::collections::HashSet;\n\n    #[derive(Debug, Clone)]\n    struct TestSet {\n        to_insert: HashSet<i32>,\n        to_test: Vec<i32>,\n    }\n\n    impl Arbitrary for TestSet {\n        fn arbitrary(g: &mut Gen) -> Self {\n            let mut qty = usize::arbitrary(g) % 5_000;\n            if qty < 50 {\n                qty += 50; // won't be perfectly uniformly distributed\n            }\n            let mut to_insert = HashSet::with_capacity(qty);\n            let mut to_test = Vec::with_capacity(qty);\n            for _ in 0..(qty) {\n                to_insert.insert(i32::arbitrary(g));\n                to_test.push(i32::arbitrary(g));\n            }\n            TestSet { to_insert, to_test }\n        }\n    }\n\n    #[quickcheck]\n    fn basic_filter_must_not_return_false_negative(TestSet { to_insert, to_test }: TestSet) {\n        let mut basic_filter = BasicBloomFilter::<10_000>::default();\n        for item in &to_insert {\n            basic_filter.insert(*item);\n        }\n        for other in to_test {\n            if !basic_filter.contains(&other) {\n                assert!(!to_insert.contains(&other))\n            }\n        }\n    }\n\n    #[quickcheck]\n    fn binary_filter_must_not_return_false_negative(TestSet { to_insert, to_test }: TestSet) {\n        let mut binary_filter = SingleBinaryBloomFilter::default();\n        for item in &to_insert {\n            binary_filter.insert(*item);\n        }\n        for other in to_test {\n            if !binary_filter.contains(&other) {\n                assert!(!to_insert.contains(&other))\n            }\n        }\n    }\n\n    #[quickcheck]\n    fn a_basic_filter_of_capacity_128_is_the_same_as_a_binary_filter(\n        TestSet { to_insert, to_test }: TestSet,\n    ) {\n        let mut basic_filter = BasicBloomFilter::<128>::default(); // change 32 to anything else here, and the test won't pass\n        let mut binary_filter = SingleBinaryBloomFilter::default();\n        for item in &to_insert {\n            basic_filter.insert(*item);\n            binary_filter.insert(*item);\n        }\n        for other in to_test {\n            // Since we use the same DefaultHasher::new(), and both have size 32, we should have exactly the same results\n            assert_eq!(\n                basic_filter.contains(&other),\n                binary_filter.contains(&other)\n            );\n        }\n    }\n\n    const FALSE_POSITIVE_MAX: f64 = 0.05;\n\n    #[quickcheck]\n    fn a_multi_binary_bloom_filter_must_not_return_false_negatives(\n        TestSet { to_insert, to_test }: TestSet,\n    ) {\n        let n = to_insert.len();\n        if n == 0 {\n            // avoid dividing by 0 when adjusting the size\n            return;\n        }\n        // See Wikipedia for those formula\n        let mut binary_filter = MultiBinaryBloomFilter::from_estimate(n, FALSE_POSITIVE_MAX);\n        for item in &to_insert {\n            binary_filter.insert(*item);\n        }\n        let tests = to_test.len();\n        let mut false_positives = 0;\n        for other in to_test {\n            if !binary_filter.contains(&other) {\n                assert!(!to_insert.contains(&other))\n            } else if !to_insert.contains(&other) {\n                // false positive\n                false_positives += 1;\n            }\n        }\n        let fp_rate = false_positives as f64 / tests as f64;\n        assert!(fp_rate < 1.0); // This isn't really a test, but so that you have the `fp_rate` variable to print out, or evaluate\n    }\n}\n"
  },
  {
    "path": "src/data_structures/probabilistic/count_min_sketch.rs",
    "content": "use std::collections::hash_map::RandomState;\nuse std::fmt::{Debug, Formatter};\nuse std::hash::{BuildHasher, Hash};\n\n/// A probabilistic data structure holding an approximate count for diverse items efficiently (using constant space)\n///\n/// Let's imagine we want to count items from an incoming (unbounded) data stream\n/// One way to do this would be to hold a frequency hashmap, counting element hashes\n/// This works extremely well, but unfortunately would require a lot of memory if we have a huge diversity of incoming items in the data stream\n///\n/// CountMinSketch aims at solving this problem, trading off the exact count for an approximate one, but getting from potentially unbounded space complexity to constant complexity\n/// See the implementation below for more details\n///\n/// Here is the definition of the different allowed operations on a CountMinSketch:\n///     * increment the count of an item\n///     * retrieve the count of an item\npub trait CountMinSketch {\n    type Item;\n\n    fn increment(&mut self, item: Self::Item);\n    fn increment_by(&mut self, item: Self::Item, count: usize);\n    fn get_count(&self, item: Self::Item) -> usize;\n}\n\n/// The common implementation of a CountMinSketch\n/// Holding a DEPTH x WIDTH matrix of counts\n///\n/// The idea behind the implementation is the following:\n/// Let's start from our problem statement above. We have a frequency map of counts, and want to go reduce its space complexity\n/// The immediate way to do this would be to use a Vector with a fixed size, let this size be `WIDTH`\n/// We will be holding the count of each item `item` in the Vector, at index `i = hash(item) % WIDTH` where `hash` is a hash function: `item -> usize`\n/// We now have constant space.\n///\n/// The problem though is that we'll potentially run into a lot of collisions.\n/// Taking an extreme example, if `WIDTH = 1`, all items will have the same count, which is the sum of counts of every items\n/// We could reduce the amount of collisions by using a bigger `WIDTH` but this wouldn't be way more efficient than the \"big\" frequency map\n/// How do we improve the solution, but still keeping constant space?\n///\n/// The idea is to use not just one vector, but multiple (`DEPTH`) ones and attach different `hash` functions to each vector\n/// This would lead to the following data structure:\n///             <- WIDTH = 5 ->\n///  D   hash1: [0, 0, 0, 0, 0]\n///  E   hash2: [0, 0, 0, 0, 0]\n///  P   hash3: [0, 0, 0, 0, 0]\n///  T   hash4: [0, 0, 0, 0, 0]\n///  H   hash5: [0, 0, 0, 0, 0]\n///  =   hash6: [0, 0, 0, 0, 0]\n///  7   hash7: [0, 0, 0, 0, 0]\n/// Every hash function must return a different value for the same item.\n/// Let's say we hash \"TEST\" and:\n///     hash1(\"TEST\") = 42 => idx = 2\n///     hash2(\"TEST\") = 26 => idx = 1\n///     hash3(\"TEST\") = 10 => idx = 0\n///     hash4(\"TEST\") = 33 => idx = 3\n///     hash5(\"TEST\") = 54 => idx = 4\n///     hash6(\"TEST\") = 11 => idx = 1\n///     hash7(\"TEST\") = 50 => idx = 0\n/// This would lead our structure to become:\n///             <- WIDTH = 5 ->\n///  D   hash1: [0, 0, 1, 0, 0]\n///  E   hash2: [0, 1, 0, 0, 0]\n///  P   hash3: [1, 0, 0, 0, 0]\n///  T   hash4: [0, 0, 0, 1, 0]\n///  H   hash5: [0, 0, 0, 0, 1]\n///  =   hash6: [0, 1, 0, 0, 0]\n///  7   hash7: [1, 0, 0, 0, 0]\n///\n/// Now say we hash \"OTHER\" and:\n///     hash1(\"OTHER\") = 23 => idx = 3\n///     hash2(\"OTHER\") = 11 => idx = 1\n///     hash3(\"OTHER\") = 52 => idx = 2\n///     hash4(\"OTHER\") = 25 => idx = 0\n///     hash5(\"OTHER\") = 31 => idx = 1\n///     hash6(\"OTHER\") = 24 => idx = 4\n///     hash7(\"OTHER\") = 30 => idx = 0\n/// Leading our data structure to become:\n///             <- WIDTH = 5 ->\n///  D   hash1: [0, 0, 1, 1, 0]\n///  E   hash2: [0, 2, 0, 0, 0]\n///  P   hash3: [1, 0, 1, 0, 0]\n///  T   hash4: [1, 0, 0, 1, 0]\n///  H   hash5: [0, 1, 0, 0, 1]\n///  =   hash6: [0, 1, 0, 0, 1]\n///  7   hash7: [2, 0, 0, 0, 0]\n///\n/// We actually can witness some collisions (invalid counts of `2` above in some rows).\n/// This means that if we have to return the count for \"TEST\", we'd actually fetch counts from every row and return the minimum value\n///\n/// This could potentially be overestimated if we have a huge number of entries and a lot of collisions.\n/// But an interesting property is that the count we return for \"TEST\" cannot be underestimated\npub struct HashCountMinSketch<Item: Hash, const WIDTH: usize, const DEPTH: usize> {\n    phantom: std::marker::PhantomData<Item>, // just a marker for Item to be used\n    counts: [[usize; WIDTH]; DEPTH],\n    hashers: [RandomState; DEPTH],\n}\n\nimpl<Item: Hash, const WIDTH: usize, const DEPTH: usize> Debug\n    for HashCountMinSketch<Item, WIDTH, DEPTH>\n{\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"Item\").field(\"vecs\", &self.counts).finish()\n    }\n}\n\nimpl<T: Hash, const WIDTH: usize, const DEPTH: usize> Default\n    for HashCountMinSketch<T, WIDTH, DEPTH>\n{\n    fn default() -> Self {\n        let hashers = std::array::from_fn(|_| RandomState::new());\n\n        Self {\n            phantom: std::marker::PhantomData,\n            counts: [[0; WIDTH]; DEPTH],\n            hashers,\n        }\n    }\n}\n\nimpl<Item: Hash, const WIDTH: usize, const DEPTH: usize> CountMinSketch\n    for HashCountMinSketch<Item, WIDTH, DEPTH>\n{\n    type Item = Item;\n\n    fn increment(&mut self, item: Self::Item) {\n        self.increment_by(item, 1)\n    }\n\n    fn increment_by(&mut self, item: Self::Item, count: usize) {\n        for (row, r) in self.hashers.iter_mut().enumerate() {\n            let mut h = r.build_hasher();\n            item.hash(&mut h);\n            let hashed = r.hash_one(&item);\n            let col = (hashed % WIDTH as u64) as usize;\n            self.counts[row][col] += count;\n        }\n    }\n\n    fn get_count(&self, item: Self::Item) -> usize {\n        self.hashers\n            .iter()\n            .enumerate()\n            .map(|(row, r)| {\n                let mut h = r.build_hasher();\n                item.hash(&mut h);\n                let hashed = r.hash_one(&item);\n                let col = (hashed % WIDTH as u64) as usize;\n                self.counts[row][col]\n            })\n            .min()\n            .unwrap()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::data_structures::probabilistic::count_min_sketch::{\n        CountMinSketch, HashCountMinSketch,\n    };\n    use quickcheck::{Arbitrary, Gen};\n    use std::collections::HashSet;\n\n    #[test]\n    fn hash_functions_should_hash_differently() {\n        let mut sketch: HashCountMinSketch<&str, 50, 50> = HashCountMinSketch::default(); // use a big DEPTH\n        sketch.increment(\"something\");\n        // We want to check that our hash functions actually produce different results, so we'll store the indices where we encounter a count=1 in a set\n        let mut indices_of_ones: HashSet<usize> = HashSet::default();\n        for counts in sketch.counts {\n            let ones = counts\n                .into_iter()\n                .enumerate()\n                .filter_map(|(idx, count)| (count == 1).then_some(idx))\n                .collect::<Vec<_>>();\n            assert_eq!(1, ones.len());\n            indices_of_ones.insert(ones[0]);\n        }\n        // Given the parameters (WIDTH = 50, DEPTH = 50) it's extremely unlikely that all hash functions hash to the same index\n        assert!(indices_of_ones.len() > 1); // but we want to avoid a bug where all hash functions would produce the same hash (or hash to the same index)\n    }\n\n    #[test]\n    fn inspect_counts() {\n        let mut sketch: HashCountMinSketch<&str, 5, 7> = HashCountMinSketch::default();\n        sketch.increment(\"test\");\n        // Inspect internal state:\n        for counts in sketch.counts {\n            let zeroes = counts.iter().filter(|count| **count == 0).count();\n            assert_eq!(4, zeroes);\n            let ones = counts.iter().filter(|count| **count == 1).count();\n            assert_eq!(1, ones);\n        }\n        sketch.increment(\"test\");\n        for counts in sketch.counts {\n            let zeroes = counts.iter().filter(|count| **count == 0).count();\n            assert_eq!(4, zeroes);\n            let twos = counts.iter().filter(|count| **count == 2).count();\n            assert_eq!(1, twos);\n        }\n\n        // This one is actually deterministic\n        assert_eq!(2, sketch.get_count(\"test\"));\n    }\n\n    #[derive(Debug, Clone, Eq, PartialEq, Hash)]\n    struct TestItem {\n        item: String,\n        count: usize,\n    }\n\n    const MAX_STR_LEN: u8 = 30;\n    const MAX_COUNT: usize = 20;\n\n    impl Arbitrary for TestItem {\n        fn arbitrary(g: &mut Gen) -> Self {\n            let str_len = u8::arbitrary(g) % MAX_STR_LEN;\n            let mut str = String::with_capacity(str_len as usize);\n            for _ in 0..str_len {\n                str.push(char::arbitrary(g));\n            }\n            let count = usize::arbitrary(g) % MAX_COUNT;\n            TestItem { item: str, count }\n        }\n    }\n\n    #[quickcheck_macros::quickcheck]\n    fn must_not_understimate_count(test_items: Vec<TestItem>) {\n        let test_items = test_items.into_iter().collect::<HashSet<_>>(); // remove duplicated (would lead to weird counts)\n        let n = test_items.len();\n        let mut sketch: HashCountMinSketch<String, 50, 10> = HashCountMinSketch::default();\n        let mut exact_count = 0;\n        for TestItem { item, count } in &test_items {\n            sketch.increment_by(item.clone(), *count);\n        }\n        for TestItem { item, count } in test_items {\n            let stored_count = sketch.get_count(item);\n            assert!(stored_count >= count);\n            if count == stored_count {\n                exact_count += 1;\n            }\n        }\n        if n > 20 {\n            // if n is too short, the stat isn't really relevant\n            let exact_ratio = exact_count as f64 / n as f64;\n            assert!(exact_ratio > 0.7); // the proof is quite hard, but this should be OK\n        }\n    }\n}\n"
  },
  {
    "path": "src/data_structures/probabilistic/mod.rs",
    "content": "pub mod bloom_filter;\npub mod count_min_sketch;\n"
  },
  {
    "path": "src/data_structures/queue.rs",
    "content": "//! This module provides a generic `Queue` data structure, implemented using\n//! Rust's `LinkedList` from the standard library. The queue follows the FIFO\n//! (First-In-First-Out) principle, where elements are added to the back of\n//! the queue and removed from the front.\n\nuse std::collections::LinkedList;\n\n#[derive(Debug)]\npub struct Queue<T> {\n    elements: LinkedList<T>,\n}\n\nimpl<T> Queue<T> {\n    // Creates a new empty Queue\n    pub fn new() -> Queue<T> {\n        Queue {\n            elements: LinkedList::new(),\n        }\n    }\n\n    // Adds an element to the back of the queue\n    pub fn enqueue(&mut self, value: T) {\n        self.elements.push_back(value)\n    }\n\n    // Removes and returns the front element from the queue, or None if empty\n    pub fn dequeue(&mut self) -> Option<T> {\n        self.elements.pop_front()\n    }\n\n    // Returns a reference to the front element of the queue, or None if empty\n    pub fn peek_front(&self) -> Option<&T> {\n        self.elements.front()\n    }\n\n    // Returns a reference to the back element of the queue, or None if empty\n    pub fn peek_back(&self) -> Option<&T> {\n        self.elements.back()\n    }\n\n    // Returns the number of elements in the queue\n    pub fn len(&self) -> usize {\n        self.elements.len()\n    }\n\n    // Checks if the queue is empty\n    pub fn is_empty(&self) -> bool {\n        self.elements.is_empty()\n    }\n\n    // Clears all elements from the queue\n    pub fn drain(&mut self) {\n        self.elements.clear();\n    }\n}\n\n// Implementing the Default trait for Queue\nimpl<T> Default for Queue<T> {\n    fn default() -> Queue<T> {\n        Queue::new()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::Queue;\n\n    #[test]\n    fn test_queue_functionality() {\n        let mut queue: Queue<usize> = Queue::default();\n\n        assert!(queue.is_empty());\n        queue.enqueue(8);\n        queue.enqueue(16);\n        assert!(!queue.is_empty());\n        assert_eq!(queue.len(), 2);\n\n        assert_eq!(queue.peek_front(), Some(&8));\n        assert_eq!(queue.peek_back(), Some(&16));\n\n        assert_eq!(queue.dequeue(), Some(8));\n        assert_eq!(queue.len(), 1);\n        assert_eq!(queue.peek_front(), Some(&16));\n        assert_eq!(queue.peek_back(), Some(&16));\n\n        queue.drain();\n        assert!(queue.is_empty());\n        assert_eq!(queue.len(), 0);\n        assert_eq!(queue.dequeue(), None);\n    }\n}\n"
  },
  {
    "path": "src/data_structures/range_minimum_query.rs",
    "content": "//! Range Minimum Query (RMQ) Implementation\n//!\n//! This module provides an efficient implementation of a Range Minimum Query data structure using a\n//! sparse table approach. It allows for quick retrieval of the minimum value within a specified subdata\n//! of a given data after an initial preprocessing phase.\n//!\n//! The RMQ is particularly useful in scenarios requiring multiple queries on static data, as it\n//! allows querying in constant time after an O(n log(n)) preprocessing time.\n//!\n//! References: [Wikipedia](https://en.wikipedia.org/wiki/Range_minimum_query)\n\nuse std::cmp::PartialOrd;\n\n/// Custom error type for invalid range queries.\n#[derive(Debug, PartialEq, Eq)]\npub enum RangeError {\n    /// Indicates that the provided range is invalid (start index is not less than end index).\n    InvalidRange,\n    /// Indicates that one or more indices are out of bounds for the data.\n    IndexOutOfBound,\n}\n\n/// A data structure for efficiently answering range minimum queries on static data.\npub struct RangeMinimumQuery<T: PartialOrd + Copy> {\n    /// The original input data on which range queries are performed.\n    data: Vec<T>,\n    /// The sparse table for storing preprocessed range minimum information. Each entry\n    /// contains the index of the minimum element in the range starting at `j` and having a length of `2^i`.\n    sparse_table: Vec<Vec<usize>>,\n}\n\nimpl<T: PartialOrd + Copy> RangeMinimumQuery<T> {\n    /// Creates a new `RangeMinimumQuery` instance with the provided input data.\n    ///\n    /// # Arguments\n    ///\n    /// * `input` - A slice of elements of type `T` that implement `PartialOrd` and `Copy`.\n    ///\n    /// # Returns\n    ///\n    /// A `RangeMinimumQuery` instance that can be used to perform range minimum queries.\n    pub fn new(input: &[T]) -> RangeMinimumQuery<T> {\n        RangeMinimumQuery {\n            data: input.to_vec(),\n            sparse_table: build_sparse_table(input),\n        }\n    }\n\n    /// Retrieves the minimum value in the specified range [start, end).\n    ///\n    /// # Arguments\n    ///\n    /// * `start` - The starting index of the range (inclusive).\n    /// * `end` - The ending index of the range (exclusive).\n    ///\n    /// # Returns\n    ///\n    /// * `Ok(T)` - The minimum value found in the specified range.\n    /// * `Err(RangeError)` - An error indicating the reason for failure, such as an invalid range\n    ///   or indices out of bounds.\n    pub fn get_range_min(&self, start: usize, end: usize) -> Result<T, RangeError> {\n        // Validate range\n        if start >= end {\n            return Err(RangeError::InvalidRange);\n        }\n        if start >= self.data.len() || end > self.data.len() {\n            return Err(RangeError::IndexOutOfBound);\n        }\n\n        // Calculate the log length and the index for the sparse table\n        let log_len = (end - start).ilog2() as usize;\n        let idx: usize = end - (1 << log_len);\n\n        // Retrieve the indices of the minimum values from the sparse table\n        let min_idx_start = self.sparse_table[log_len][start];\n        let min_idx_end = self.sparse_table[log_len][idx];\n\n        // Compare the values at the retrieved indices and return the minimum\n        if self.data[min_idx_start] < self.data[min_idx_end] {\n            Ok(self.data[min_idx_start])\n        } else {\n            Ok(self.data[min_idx_end])\n        }\n    }\n}\n\n/// Builds a sparse table for the provided data to support range minimum queries.\n///\n/// # Arguments\n///\n/// * `data` - A slice of elements of type `T` that implement `PartialOrd`.\n///\n/// # Returns\n///\n/// A 2D vector representing the sparse table, where each entry contains the index of the minimum\n/// element in the range defined by the starting index and the power of two lengths.\nfn build_sparse_table<T: PartialOrd>(data: &[T]) -> Vec<Vec<usize>> {\n    let mut sparse_table: Vec<Vec<usize>> = vec![(0..data.len()).collect()];\n    let len = data.len();\n\n    // Fill the sparse table\n    for log_len in 1..=len.ilog2() {\n        let mut row = Vec::new();\n        for idx in 0..=len - (1 << log_len) {\n            let min_idx_start = sparse_table[sparse_table.len() - 1][idx];\n            let min_idx_end = sparse_table[sparse_table.len() - 1][idx + (1 << (log_len - 1))];\n            if data[min_idx_start] < data[min_idx_end] {\n                row.push(min_idx_start);\n            } else {\n                row.push(min_idx_end);\n            }\n        }\n        sparse_table.push(row);\n    }\n\n    sparse_table\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_build_sparse_table {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (data, expected) = $inputs;\n                    assert_eq!(build_sparse_table(&data), expected);\n                }\n            )*\n        }\n    }\n\n    test_build_sparse_table! {\n        small: (\n            [1, 6, 3],\n            vec![\n                vec![0, 1, 2],\n                vec![0, 2]\n            ]\n        ),\n        medium: (\n            [1, 3, 6, 123, 7, 235, 3, -4, 6, 2],\n            vec![\n                vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n                vec![0, 1, 2, 4, 4, 6, 7, 7, 9],\n                vec![0, 1, 2, 6, 7, 7, 7],\n                vec![7, 7, 7]\n            ]\n        ),\n        large: (\n            [20, 13, -13, 2, 3634, -2, 56, 3, 67, 8, 23, 0, -23, 1, 5, 85, 3, 24, 5, -10, 3, 4, 20],\n            vec![\n                vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22],\n                vec![1, 2, 2, 3, 5, 5, 7, 7, 9, 9, 11, 12, 12, 13, 14, 16, 16, 18, 19, 19, 20, 21],\n                vec![2, 2, 2, 5, 5, 5, 7, 7, 11, 12, 12, 12, 12, 13, 16, 16, 19, 19, 19, 19],\n                vec![2, 2, 2, 5, 5, 12, 12, 12, 12, 12, 12, 12, 12, 19, 19, 19],\n                vec![12, 12, 12, 12, 12, 12, 12, 12]\n            ]\n        ),\n    }\n\n    #[test]\n    fn simple_query_tests() {\n        let rmq = RangeMinimumQuery::new(&[1, 3, 6, 123, 7, 235, 3, -4, 6, 2]);\n\n        assert_eq!(rmq.get_range_min(1, 6), Ok(3));\n        assert_eq!(rmq.get_range_min(0, 10), Ok(-4));\n        assert_eq!(rmq.get_range_min(8, 9), Ok(6));\n        assert_eq!(rmq.get_range_min(4, 3), Err(RangeError::InvalidRange));\n        assert_eq!(rmq.get_range_min(0, 1000), Err(RangeError::IndexOutOfBound));\n        assert_eq!(\n            rmq.get_range_min(1000, 1001),\n            Err(RangeError::IndexOutOfBound)\n        );\n    }\n\n    #[test]\n    fn float_query_tests() {\n        let rmq = RangeMinimumQuery::new(&[0.4, -2.3, 0.0, 234.22, 12.2, -3.0]);\n\n        assert_eq!(rmq.get_range_min(0, 6), Ok(-3.0));\n        assert_eq!(rmq.get_range_min(0, 4), Ok(-2.3));\n        assert_eq!(rmq.get_range_min(3, 5), Ok(12.2));\n        assert_eq!(rmq.get_range_min(2, 3), Ok(0.0));\n        assert_eq!(rmq.get_range_min(4, 3), Err(RangeError::InvalidRange));\n        assert_eq!(rmq.get_range_min(0, 1000), Err(RangeError::IndexOutOfBound));\n        assert_eq!(\n            rmq.get_range_min(1000, 1001),\n            Err(RangeError::IndexOutOfBound)\n        );\n    }\n}\n"
  },
  {
    "path": "src/data_structures/rb_tree.rs",
    "content": "use std::boxed::Box;\nuse std::cmp::{Ord, Ordering};\nuse std::iter::Iterator;\nuse std::ptr::null_mut;\n\n#[derive(Copy, Clone)]\nenum Color {\n    Red,\n    Black,\n}\n\npub struct RBNode<K: Ord, V> {\n    key: K,\n    value: V,\n    color: Color,\n    parent: *mut RBNode<K, V>,\n    left: *mut RBNode<K, V>,\n    right: *mut RBNode<K, V>,\n}\n\nimpl<K: Ord, V> RBNode<K, V> {\n    fn new(key: K, value: V) -> RBNode<K, V> {\n        RBNode {\n            key,\n            value,\n            color: Color::Red,\n            parent: null_mut(),\n            left: null_mut(),\n            right: null_mut(),\n        }\n    }\n}\n\npub struct RBTree<K: Ord, V> {\n    root: *mut RBNode<K, V>,\n}\n\nimpl<K: Ord, V> Default for RBTree<K, V> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<K: Ord, V> RBTree<K, V> {\n    pub fn new() -> RBTree<K, V> {\n        RBTree::<K, V> { root: null_mut() }\n    }\n\n    pub fn find(&self, key: &K) -> Option<&V> {\n        unsafe {\n            let mut node = self.root;\n            while !node.is_null() {\n                node = match (*node).key.cmp(key) {\n                    Ordering::Less => (*node).right,\n                    Ordering::Equal => return Some(&(*node).value),\n                    Ordering::Greater => (*node).left,\n                }\n            }\n        }\n        None\n    }\n\n    pub fn insert(&mut self, key: K, value: V) {\n        unsafe {\n            let mut parent = null_mut();\n            let mut node = self.root;\n            while !node.is_null() {\n                parent = node;\n                node = match (*node).key.cmp(&key) {\n                    Ordering::Less => (*node).right,\n                    Ordering::Equal => {\n                        (*node).value = value;\n                        return;\n                    }\n                    Ordering::Greater => (*node).left,\n                }\n            }\n            node = Box::into_raw(Box::new(RBNode::new(key, value)));\n            if parent.is_null() {\n                self.root = node;\n            } else if (*node).key < (*parent).key {\n                (*parent).left = node;\n            } else {\n                (*parent).right = node;\n            }\n            (*node).parent = parent;\n            insert_fixup(self, node);\n        }\n    }\n\n    pub fn delete(&mut self, key: &K) {\n        unsafe {\n            let mut parent = null_mut();\n            let mut node = self.root;\n            while !node.is_null() {\n                node = match (*node).key.cmp(key) {\n                    Ordering::Less => {\n                        parent = node;\n                        (*node).right\n                    }\n                    Ordering::Equal => break,\n                    Ordering::Greater => {\n                        parent = node;\n                        (*node).left\n                    }\n                };\n            }\n\n            if node.is_null() {\n                return;\n            }\n\n            /* cl and cr denote left and right child of node, respectively. */\n            let cl = (*node).left;\n            let cr = (*node).right;\n            let mut deleted_color;\n\n            if cl.is_null() {\n                replace_node(self, parent, node, cr);\n                if cr.is_null() {\n                    /*\n                     * Case 1 - cl and cr are both NULL\n                     * (n could be either color here)\n                     *\n                     *     (n)             NULL\n                     *    /   \\    -->\n                     *  NULL  NULL\n                     */\n\n                    deleted_color = (*node).color;\n                } else {\n                    /*\n                     * Case 2 - cl is NULL and cr is not NULL\n                     *\n                     *     N             Cr\n                     *    / \\    -->    /  \\\n                     *  NULL cr       NULL NULL\n                     */\n\n                    (*cr).parent = parent;\n                    (*cr).color = Color::Black;\n                    deleted_color = Color::Red;\n                }\n            } else if cr.is_null() {\n                /*\n                 * Case 3 - cl is not NULL and cr is NULL\n                 *\n                 *     N             Cl\n                 *    / \\    -->    /  \\\n                 *  cl  NULL      NULL NULL\n                 */\n\n                replace_node(self, parent, node, cl);\n                (*cl).parent = parent;\n                (*cl).color = Color::Black;\n                deleted_color = Color::Red;\n            } else {\n                let mut victim = (*node).right;\n                while !(*victim).left.is_null() {\n                    victim = (*victim).left;\n                }\n                if victim == (*node).right {\n                    /* Case 4 - victim is the right child of node\n                     *\n                     *     N         N         n\n                     *    / \\       / \\       / \\\n                     *  (cl) cr   (cl) Cr    Cl  Cr\n                     *\n                     *     N         n\n                     *    / \\       / \\\n                     *  (cl) Cr    Cl  Cr\n                     *         \\         \\\n                     *         crr       crr\n                     */\n\n                    replace_node(self, parent, node, victim);\n                    (*victim).parent = parent;\n                    deleted_color = (*victim).color;\n                    (*victim).color = (*node).color;\n                    (*victim).left = cl;\n                    (*cl).parent = victim;\n                    if (*victim).right.is_null() {\n                        parent = victim;\n                    } else {\n                        deleted_color = Color::Red;\n                        (*(*victim).right).color = Color::Black;\n                    }\n                } else {\n                    /*\n                     * Case 5 - victim is not the right child of node\n                     */\n\n                    /* vp and vr denote parent and right child of victim, respectively. */\n                    let vp = (*victim).parent;\n                    let vr = (*victim).right;\n                    (*vp).left = vr;\n                    if vr.is_null() {\n                        deleted_color = (*victim).color;\n                    } else {\n                        deleted_color = Color::Red;\n                        (*vr).parent = vp;\n                        (*vr).color = Color::Black;\n                    }\n                    replace_node(self, parent, node, victim);\n                    (*victim).parent = parent;\n                    (*victim).color = (*node).color;\n                    (*victim).left = cl;\n                    (*victim).right = cr;\n                    (*cl).parent = victim;\n                    (*cr).parent = victim;\n                    parent = vp;\n                }\n            }\n\n            /* release resource */\n            drop(Box::from_raw(node));\n            if matches!(deleted_color, Color::Black) {\n                delete_fixup(self, parent);\n            }\n        }\n    }\n\n    pub fn iter<'a>(&self) -> RBTreeIterator<'a, K, V> {\n        let mut iterator = RBTreeIterator { stack: Vec::new() };\n        let mut node = self.root;\n        unsafe {\n            while !node.is_null() {\n                iterator.stack.push(&*node);\n                node = (*node).left;\n            }\n        }\n        iterator\n    }\n}\n\n#[inline]\nunsafe fn insert_fixup<K: Ord, V>(tree: &mut RBTree<K, V>, mut node: *mut RBNode<K, V>) {\n    let mut parent: *mut RBNode<K, V> = (*node).parent;\n    let mut gparent: *mut RBNode<K, V>;\n    let mut tmp: *mut RBNode<K, V>;\n\n    loop {\n        /*\n         * Loop invariant:\n         * - node is red\n         */\n\n        if parent.is_null() {\n            (*node).color = Color::Black;\n            break;\n        }\n\n        if matches!((*parent).color, Color::Black) {\n            break;\n        }\n\n        gparent = (*parent).parent;\n        tmp = (*gparent).right;\n        if parent == tmp {\n            /* parent = (*gparent).right */\n            tmp = (*gparent).left;\n            if !tmp.is_null() && matches!((*tmp).color, Color::Red) {\n                /*\n                 * Case 1 - color flips and recurse at g\n                 *    G               g\n                 *   / \\             / \\\n                 *  u   p    -->    U   P\n                 *       \\               \\\n                 *        n               n\n                 */\n\n                (*parent).color = Color::Black;\n                (*tmp).color = Color::Black;\n                (*gparent).color = Color::Red;\n                node = gparent;\n                parent = (*node).parent;\n                continue;\n            }\n            tmp = (*parent).left;\n            if node == tmp {\n                /*\n                 * Case 2 - right rotate at p (then Case 3)\n                 *\n                 *       G             G\n                 *      / \\           / \\\n                 *     U   p   -->   U   n\n                 *        /               \\\n                 *       n                 p\n                 */\n\n                right_rotate(tree, parent);\n                parent = node;\n            }\n            /*\n             * Case 3 - left rotate at g\n             *\n             *       G             P\n             *      / \\           / \\\n             *     U   p   -->   g   n\n             *          \\       /\n             *           n     U\n             */\n\n            (*parent).color = Color::Black;\n            (*gparent).color = Color::Red;\n            left_rotate(tree, gparent);\n        } else {\n            /* parent = (*gparent).left */\n            if !tmp.is_null() && matches!((*tmp).color, Color::Red) {\n                /*\n                 * Case 1 - color flips and recurse at g\n                 *\n                 *      G               g\n                 *     / \\             / \\\n                 *    p   u    -->    P   U\n                 *   /               /\n                 *  n               n\n                 */\n\n                (*parent).color = Color::Black;\n                (*tmp).color = Color::Black;\n                (*gparent).color = Color::Red;\n                node = gparent;\n                parent = (*node).parent;\n                continue;\n            }\n            tmp = (*parent).right;\n            if node == tmp {\n                /* node = (*parent).right */\n                /*\n                 * Case 2 - left rotate at p (then Case 3)\n                 *\n                 *    G               G\n                 *   / \\             / \\\n                 *  p   U    -->    n   U\n                 *   \\             /\n                 *    n           p\n                 */\n\n                left_rotate(tree, parent);\n                parent = node;\n            }\n            /*\n             * Case 3 - right rotate at g\n             *\n             *      G               P\n             *     / \\             / \\\n             *    p   U    -->    n   g\n             *   /                     \\\n             *  n                       U\n             */\n\n            (*parent).color = Color::Black;\n            (*gparent).color = Color::Red;\n            right_rotate(tree, gparent);\n        }\n        break;\n    }\n}\n\n#[inline]\nunsafe fn delete_fixup<K: Ord, V>(tree: &mut RBTree<K, V>, mut parent: *mut RBNode<K, V>) {\n    let mut node: *mut RBNode<K, V> = null_mut();\n    let mut sibling: *mut RBNode<K, V>;\n    /* sl and sr denote left and right child of sibling, respectively. */\n    let mut sl: *mut RBNode<K, V>;\n    let mut sr: *mut RBNode<K, V>;\n\n    loop {\n        // rb-tree will keep color balance up to root,\n        // if parent is null, we are done.\n        if parent.is_null() {\n            break;\n        }\n\n        /*\n         * Loop invariants:\n         * - node is black (or null on first iteration)\n         * - node is not the root (so parent is not null)\n         * - All leaf paths going through parent and node have a\n         *   black node count that is 1 lower than other leaf paths.\n         */\n        sibling = (*parent).right;\n        if node == sibling {\n            /* node = (*parent).right */\n            sibling = (*parent).left;\n            if matches!((*sibling).color, Color::Red) {\n                /*\n                 * Case 1 - right rotate at parent\n                 */\n\n                right_rotate(tree, parent);\n                (*parent).color = Color::Red;\n                (*sibling).color = Color::Black;\n                sibling = (*parent).right;\n            }\n            sl = (*sibling).left;\n            sr = (*sibling).right;\n\n            if !sr.is_null() && matches!((*sr).color, Color::Red) {\n                /*\n                 * Case 2 - left rotate at sibling and then right rotate at parent\n                 */\n\n                (*sr).color = (*parent).color;\n                (*parent).color = Color::Black;\n                left_rotate(tree, sibling);\n                right_rotate(tree, parent);\n            } else if !sl.is_null() && matches!((*sl).color, Color::Red) {\n                /*\n                 * Case 3 - right rotate at parent\n                 */\n\n                (*sl).color = (*parent).color;\n                right_rotate(tree, parent);\n            } else {\n                /*\n                 * Case 4 - color flip\n                 */\n\n                (*sibling).color = Color::Red;\n                if matches!((*parent).color, Color::Black) {\n                    node = parent;\n                    parent = (*node).parent;\n                    continue;\n                }\n                (*parent).color = Color::Black;\n            }\n        } else {\n            /* node = (*parent).left */\n            if matches!((*sibling).color, Color::Red) {\n                /*\n                 * Case 1 - left rotate at parent\n                 *\n                 *    P               S\n                 *   / \\             / \\\n                 *  N   s    -->    p   Sr\n                 *     / \\         / \\\n                 *    Sl  Sr      N  Sl\n                 */\n\n                left_rotate(tree, parent);\n                (*parent).color = Color::Red;\n                (*sibling).color = Color::Black;\n                sibling = (*parent).right;\n            }\n            sl = (*sibling).left;\n            sr = (*sibling).right;\n\n            if !sl.is_null() && matches!((*sl).color, Color::Red) {\n                /*\n                 * Case 2 - right rotate at sibling and then left rotate at parent\n                 * (p and sr could be either color here)\n                 *\n                 *   (p)             (p)              (sl)\n                 *   / \\             / \\              / \\\n                 *  N   S    -->    N   sl    -->    P   S\n                 *     / \\                \\         /     \\\n                 *    sl (sr)              S       N      (sr)\n                 *                          \\\n                 *                          (sr)\n                 */\n\n                (*sl).color = (*parent).color;\n                (*parent).color = Color::Black;\n                right_rotate(tree, sibling);\n                left_rotate(tree, parent);\n            } else if !sr.is_null() && matches!((*sr).color, Color::Red) {\n                /*\n                 * Case 3 - left rotate at parent\n                 * (p could be either color here)\n                 *\n                 *   (p)               S\n                 *   / \\              / \\\n                 *  N   S    -->    (p) (sr)\n                 *     / \\          / \\\n                 *    Sl  sr       N   Sl\n                 */\n\n                (*sr).color = (*parent).color;\n                left_rotate(tree, parent);\n            } else {\n                /*\n                 * Case 4 - color clip\n                 * (p could be either color here)\n                 *\n                 *   (p)             (p)\n                 *   / \\             / \\\n                 *  N   S    -->    N   s\n                 *     / \\             / \\\n                 *    Sl  Sr          Sl  Sr\n                 */\n\n                (*sibling).color = Color::Red;\n                if matches!((*parent).color, Color::Black) {\n                    node = parent;\n                    parent = (*node).parent;\n                    continue;\n                }\n                (*parent).color = Color::Black;\n            }\n        }\n        break;\n    }\n}\n\n#[inline]\nunsafe fn left_rotate<K: Ord, V>(tree: &mut RBTree<K, V>, x: *mut RBNode<K, V>) {\n    /*\n     * Left rotate at x\n     * (x could also be the left child of p)\n     *\n     *  p           p\n     *   \\           \\\n     *    x    -->    y\n     *   / \\         / \\\n     *      y       x\n     *     / \\     / \\\n     *    c           c\n     */\n\n    let p = (*x).parent;\n    let y = (*x).right;\n    let c = (*y).left;\n\n    (*y).left = x;\n    (*x).parent = y;\n    (*x).right = c;\n    if !c.is_null() {\n        (*c).parent = x;\n    }\n    if p.is_null() {\n        tree.root = y;\n    } else if (*p).left == x {\n        (*p).left = y;\n    } else {\n        (*p).right = y;\n    }\n    (*y).parent = p;\n}\n\n#[inline]\nunsafe fn right_rotate<K: Ord, V>(tree: &mut RBTree<K, V>, x: *mut RBNode<K, V>) {\n    /*\n     * Right rotate at x\n     * (x could also be the left child of p)\n     *\n     *  p           p\n     *   \\           \\\n     *    x    -->    y\n     *   / \\         / \\\n     *  y               x\n     * / \\             / \\\n     *    c           c\n     */\n\n    let p = (*x).parent;\n    let y = (*x).left;\n    let c = (*y).right;\n\n    (*y).right = x;\n    (*x).parent = y;\n    (*x).left = c;\n    if !c.is_null() {\n        (*c).parent = x;\n    }\n    if p.is_null() {\n        tree.root = y;\n    } else if (*p).left == x {\n        (*p).left = y;\n    } else {\n        (*p).right = y;\n    }\n    (*y).parent = p;\n}\n\n#[inline]\nunsafe fn replace_node<K: Ord, V>(\n    tree: &mut RBTree<K, V>,\n    parent: *mut RBNode<K, V>,\n    node: *mut RBNode<K, V>,\n    new: *mut RBNode<K, V>,\n) {\n    if parent.is_null() {\n        tree.root = new;\n    } else if (*parent).left == node {\n        (*parent).left = new;\n    } else {\n        (*parent).right = new;\n    }\n}\n\npub struct RBTreeIterator<'a, K: Ord, V> {\n    stack: Vec<&'a RBNode<K, V>>,\n}\n\nimpl<'a, K: Ord, V> Iterator for RBTreeIterator<'a, K, V> {\n    type Item = &'a RBNode<K, V>;\n    fn next(&mut self) -> Option<Self::Item> {\n        match self.stack.pop() {\n            Some(node) => {\n                let mut next = node.right;\n                unsafe {\n                    while !next.is_null() {\n                        self.stack.push(&*next);\n                        next = (*next).left;\n                    }\n                }\n                Some(node)\n            }\n            None => None,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::RBTree;\n\n    #[test]\n    fn find() {\n        let mut tree = RBTree::<usize, char>::new();\n        for (k, v) in \"hello, world!\".chars().enumerate() {\n            tree.insert(k, v);\n        }\n        assert_eq!(*tree.find(&3).unwrap_or(&'*'), 'l');\n        assert_eq!(*tree.find(&6).unwrap_or(&'*'), ' ');\n        assert_eq!(*tree.find(&8).unwrap_or(&'*'), 'o');\n        assert_eq!(*tree.find(&12).unwrap_or(&'*'), '!');\n    }\n\n    #[test]\n    fn insert() {\n        let mut tree = RBTree::<usize, char>::new();\n        for (k, v) in \"hello, world!\".chars().enumerate() {\n            tree.insert(k, v);\n        }\n        let s: String = tree.iter().map(|x| x.value).collect();\n        assert_eq!(s, \"hello, world!\");\n    }\n\n    #[test]\n    fn delete() {\n        let mut tree = RBTree::<usize, char>::new();\n        for (k, v) in \"hello, world!\".chars().enumerate() {\n            tree.insert(k, v);\n        }\n        tree.delete(&1);\n        tree.delete(&3);\n        tree.delete(&5);\n        tree.delete(&7);\n        tree.delete(&11);\n        let s: String = tree.iter().map(|x| x.value).collect();\n        assert_eq!(s, \"hlo orl!\");\n    }\n\n    #[test]\n    fn delete_edge_case_null_pointer_guard() {\n        let mut tree = RBTree::<i8, i8>::new();\n        tree.insert(4, 4);\n        tree.insert(2, 2);\n        tree.insert(5, 5);\n        tree.insert(0, 0);\n        tree.insert(3, 3);\n        tree.insert(-1, -1);\n        tree.insert(1, 1);\n        tree.insert(-2, -2);\n        tree.insert(6, 6);\n        tree.insert(7, 7);\n        tree.insert(8, 8);\n        tree.delete(&1);\n        tree.delete(&3);\n        tree.delete(&-1);\n    }\n}\n"
  },
  {
    "path": "src/data_structures/segment_tree.rs",
    "content": "//! A module providing a Segment Tree data structure for efficient range queries\n//! and updates. It supports operations like finding the minimum, maximum,\n//! and sum of segments in an array.\n\nuse std::fmt::Debug;\nuse std::ops::Range;\n\n/// Custom error types representing possible errors that can occur during operations on the `SegmentTree`.\n#[derive(Debug, PartialEq, Eq)]\npub enum SegmentTreeError {\n    /// Error indicating that an index is out of bounds.\n    IndexOutOfBounds,\n    /// Error indicating that a range provided for a query is invalid.\n    InvalidRange,\n}\n\n/// A structure representing a Segment Tree. This tree can be used to efficiently\n/// perform range queries and updates on an array of elements.\npub struct SegmentTree<T, F>\nwhere\n    T: Debug + Default + Ord + Copy,\n    F: Fn(T, T) -> T,\n{\n    /// The length of the input array for which the segment tree is built.\n    size: usize,\n    /// A vector representing the segment tree.\n    nodes: Vec<T>,\n    /// A merging function defined as a closure or callable type.\n    merge_fn: F,\n}\n\nimpl<T, F> SegmentTree<T, F>\nwhere\n    T: Debug + Default + Ord + Copy,\n    F: Fn(T, T) -> T,\n{\n    /// Creates a new `SegmentTree` from the provided slice of elements.\n    ///\n    /// # Arguments\n    ///\n    /// * `arr`: A slice of elements of type `T` to initialize the segment tree.\n    /// * `merge`: A merging function that defines how to merge two elements of type `T`.\n    ///\n    /// # Returns\n    ///\n    /// A new `SegmentTree` instance populated with the given elements.\n    pub fn from_vec(arr: &[T], merge: F) -> Self {\n        let size = arr.len();\n        let mut buffer: Vec<T> = vec![T::default(); 2 * size];\n\n        // Populate the leaves of the tree\n        buffer[size..(2 * size)].clone_from_slice(arr);\n        for idx in (1..size).rev() {\n            buffer[idx] = merge(buffer[2 * idx], buffer[2 * idx + 1]);\n        }\n\n        SegmentTree {\n            size,\n            nodes: buffer,\n            merge_fn: merge,\n        }\n    }\n\n    /// Queries the segment tree for the result of merging the elements in the given range.\n    ///\n    /// # Arguments\n    ///\n    /// * `range`: A range specified as `Range<usize>`, indicating the start (inclusive)\n    ///   and end (exclusive) indices of the segment to query.\n    ///\n    /// # Returns\n    ///\n    /// * `Ok(Some(result))` if the query was successful and there are elements in the range,\n    /// * `Ok(None)` if the range is empty,\n    /// * `Err(SegmentTreeError::InvalidRange)` if the provided range is invalid.\n    pub fn query(&self, range: Range<usize>) -> Result<Option<T>, SegmentTreeError> {\n        if range.start >= self.size || range.end > self.size {\n            return Err(SegmentTreeError::InvalidRange);\n        }\n\n        let mut left = range.start + self.size;\n        let mut right = range.end + self.size;\n        let mut result = None;\n\n        // Iterate through the segment tree to accumulate results\n        while left < right {\n            if left % 2 == 1 {\n                result = Some(match result {\n                    None => self.nodes[left],\n                    Some(old) => (self.merge_fn)(old, self.nodes[left]),\n                });\n                left += 1;\n            }\n            if right % 2 == 1 {\n                right -= 1;\n                result = Some(match result {\n                    None => self.nodes[right],\n                    Some(old) => (self.merge_fn)(old, self.nodes[right]),\n                });\n            }\n            left /= 2;\n            right /= 2;\n        }\n\n        Ok(result)\n    }\n\n    /// Updates the value at the specified index in the segment tree.\n    ///\n    /// # Arguments\n    ///\n    /// * `idx`: The index (0-based) of the element to update.\n    /// * `val`: The new value of type `T` to set at the specified index.\n    ///\n    /// # Returns\n    ///\n    /// * `Ok(())` if the update was successful,\n    /// * `Err(SegmentTreeError::IndexOutOfBounds)` if the index is out of bounds.\n    pub fn update(&mut self, idx: usize, val: T) -> Result<(), SegmentTreeError> {\n        if idx >= self.size {\n            return Err(SegmentTreeError::IndexOutOfBounds);\n        }\n\n        let mut index = idx + self.size;\n        if self.nodes[index] == val {\n            return Ok(());\n        }\n\n        self.nodes[index] = val;\n        while index > 1 {\n            index /= 2;\n            self.nodes[index] = (self.merge_fn)(self.nodes[2 * index], self.nodes[2 * index + 1]);\n        }\n\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::cmp::{max, min};\n\n    #[test]\n    fn test_min_segments() {\n        let vec = vec![-30, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8];\n        let mut min_seg_tree = SegmentTree::from_vec(&vec, min);\n        assert_eq!(min_seg_tree.query(4..7), Ok(Some(-5)));\n        assert_eq!(min_seg_tree.query(0..vec.len()), Ok(Some(-30)));\n        assert_eq!(min_seg_tree.query(0..2), Ok(Some(-30)));\n        assert_eq!(min_seg_tree.query(1..3), Ok(Some(-4)));\n        assert_eq!(min_seg_tree.query(1..7), Ok(Some(-5)));\n        assert_eq!(min_seg_tree.update(5, 10), Ok(()));\n        assert_eq!(min_seg_tree.update(14, -8), Ok(()));\n        assert_eq!(min_seg_tree.query(4..7), Ok(Some(3)));\n        assert_eq!(\n            min_seg_tree.update(15, 100),\n            Err(SegmentTreeError::IndexOutOfBounds)\n        );\n        assert_eq!(min_seg_tree.query(5..5), Ok(None));\n        assert_eq!(\n            min_seg_tree.query(10..16),\n            Err(SegmentTreeError::InvalidRange)\n        );\n        assert_eq!(\n            min_seg_tree.query(15..20),\n            Err(SegmentTreeError::InvalidRange)\n        );\n    }\n\n    #[test]\n    fn test_max_segments() {\n        let vec = vec![1, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8];\n        let mut max_seg_tree = SegmentTree::from_vec(&vec, max);\n        assert_eq!(max_seg_tree.query(0..vec.len()), Ok(Some(15)));\n        assert_eq!(max_seg_tree.query(3..5), Ok(Some(7)));\n        assert_eq!(max_seg_tree.query(4..8), Ok(Some(11)));\n        assert_eq!(max_seg_tree.query(8..10), Ok(Some(9)));\n        assert_eq!(max_seg_tree.query(9..12), Ok(Some(15)));\n        assert_eq!(max_seg_tree.update(4, 10), Ok(()));\n        assert_eq!(max_seg_tree.update(14, -8), Ok(()));\n        assert_eq!(max_seg_tree.query(3..5), Ok(Some(10)));\n        assert_eq!(\n            max_seg_tree.update(15, 100),\n            Err(SegmentTreeError::IndexOutOfBounds)\n        );\n        assert_eq!(max_seg_tree.query(5..5), Ok(None));\n        assert_eq!(\n            max_seg_tree.query(10..16),\n            Err(SegmentTreeError::InvalidRange)\n        );\n        assert_eq!(\n            max_seg_tree.query(15..20),\n            Err(SegmentTreeError::InvalidRange)\n        );\n    }\n\n    #[test]\n    fn test_sum_segments() {\n        let vec = vec![1, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8];\n        let mut sum_seg_tree = SegmentTree::from_vec(&vec, |a, b| a + b);\n        assert_eq!(sum_seg_tree.query(0..vec.len()), Ok(Some(38)));\n        assert_eq!(sum_seg_tree.query(1..4), Ok(Some(5)));\n        assert_eq!(sum_seg_tree.query(4..7), Ok(Some(4)));\n        assert_eq!(sum_seg_tree.query(6..9), Ok(Some(-3)));\n        assert_eq!(sum_seg_tree.query(9..vec.len()), Ok(Some(37)));\n        assert_eq!(sum_seg_tree.update(5, 10), Ok(()));\n        assert_eq!(sum_seg_tree.update(14, -8), Ok(()));\n        assert_eq!(sum_seg_tree.query(4..7), Ok(Some(19)));\n        assert_eq!(\n            sum_seg_tree.update(15, 100),\n            Err(SegmentTreeError::IndexOutOfBounds)\n        );\n        assert_eq!(sum_seg_tree.query(5..5), Ok(None));\n        assert_eq!(\n            sum_seg_tree.query(10..16),\n            Err(SegmentTreeError::InvalidRange)\n        );\n        assert_eq!(\n            sum_seg_tree.query(15..20),\n            Err(SegmentTreeError::InvalidRange)\n        );\n    }\n}\n"
  },
  {
    "path": "src/data_structures/segment_tree_recursive.rs",
    "content": "use std::fmt::Debug;\nuse std::ops::Range;\n\n/// Custom error types representing possible errors that can occur during operations on the `SegmentTree`.\n#[derive(Debug, PartialEq, Eq)]\npub enum SegmentTreeError {\n    /// Error indicating that an index is out of bounds.\n    IndexOutOfBounds,\n    /// Error indicating that a range provided for a query is invalid.\n    InvalidRange,\n}\n\n/// A data structure representing a Segment Tree. Which is used for efficient\n/// range queries and updates on an array of elements.\npub struct SegmentTree<T, F>\nwhere\n    T: Debug + Default + Ord + Copy,\n    F: Fn(T, T) -> T,\n{\n    /// The number of elements in the original input array for which the segment tree is built.\n    size: usize,\n    /// A vector representing the nodes of the segment tree.\n    nodes: Vec<T>,\n    /// A function that merges two elements of type `T`.\n    merge_fn: F,\n}\n\nimpl<T, F> SegmentTree<T, F>\nwhere\n    T: Debug + Default + Ord + Copy,\n    F: Fn(T, T) -> T,\n{\n    /// Creates a new `SegmentTree` from the provided slice of elements.\n    ///\n    /// # Arguments\n    ///\n    /// * `arr`: A slice of elements of type `T` that initializes the segment tree.\n    /// * `merge_fn`: A merging function that specifies how to combine two elements of type `T`.\n    ///\n    /// # Returns\n    ///\n    /// A new `SegmentTree` instance initialized with the given elements.\n    pub fn from_vec(arr: &[T], merge_fn: F) -> Self {\n        let size = arr.len();\n        let mut seg_tree = SegmentTree {\n            size,\n            nodes: vec![T::default(); 4 * size],\n            merge_fn,\n        };\n        if size != 0 {\n            seg_tree.build_recursive(arr, 1, 0..size);\n        }\n        seg_tree\n    }\n\n    /// Recursively builds the segment tree from the provided array.\n    ///\n    /// # Parameters\n    ///\n    /// * `arr` - The original array of values.\n    /// * `node_idx` - The index of the current node in the segment tree.\n    /// * `node_range` - The range of elements in the original array that the current node covers.\n    fn build_recursive(&mut self, arr: &[T], node_idx: usize, node_range: Range<usize>) {\n        if node_range.end - node_range.start == 1 {\n            self.nodes[node_idx] = arr[node_range.start];\n        } else {\n            let mid = node_range.start + (node_range.end - node_range.start) / 2;\n            self.build_recursive(arr, 2 * node_idx, node_range.start..mid);\n            self.build_recursive(arr, 2 * node_idx + 1, mid..node_range.end);\n            self.nodes[node_idx] =\n                (self.merge_fn)(self.nodes[2 * node_idx], self.nodes[2 * node_idx + 1]);\n        }\n    }\n\n    /// Queries the segment tree for the result of merging the elements in the specified range.\n    ///\n    /// # Arguments\n    ///\n    /// * `target_range`: A range specified as `Range<usize>`, indicating the start (inclusive)\n    ///   and end (exclusive) indices of the segment to query.\n    ///\n    /// # Returns\n    ///\n    /// * `Ok(Some(result))` if the query is successful and there are elements in the range,\n    /// * `Ok(None)` if the range is empty,\n    /// * `Err(SegmentTreeError::InvalidRange)` if the provided range is invalid.\n    pub fn query(&self, target_range: Range<usize>) -> Result<Option<T>, SegmentTreeError> {\n        if target_range.start >= self.size || target_range.end > self.size {\n            return Err(SegmentTreeError::InvalidRange);\n        }\n        Ok(self.query_recursive(1, 0..self.size, &target_range))\n    }\n\n    /// Recursively performs a range query to find the merged result of the specified range.\n    ///\n    /// # Parameters\n    ///\n    /// * `node_idx` - The index of the current node in the segment tree.\n    /// * `tree_range` - The range of elements covered by the current node.\n    /// * `target_range` - The range for which the query is being performed.\n    ///\n    /// # Returns\n    ///\n    /// An `Option<T>` containing the result of the merge operation on the range if within bounds,\n    /// or `None` if the range is outside the covered range.\n    fn query_recursive(\n        &self,\n        node_idx: usize,\n        tree_range: Range<usize>,\n        target_range: &Range<usize>,\n    ) -> Option<T> {\n        if tree_range.start >= target_range.end || tree_range.end <= target_range.start {\n            return None;\n        }\n        if tree_range.start >= target_range.start && tree_range.end <= target_range.end {\n            return Some(self.nodes[node_idx]);\n        }\n        let mid = tree_range.start + (tree_range.end - tree_range.start) / 2;\n        let left_res = self.query_recursive(node_idx * 2, tree_range.start..mid, target_range);\n        let right_res = self.query_recursive(node_idx * 2 + 1, mid..tree_range.end, target_range);\n        match (left_res, right_res) {\n            (None, None) => None,\n            (None, Some(r)) => Some(r),\n            (Some(l), None) => Some(l),\n            (Some(l), Some(r)) => Some((self.merge_fn)(l, r)),\n        }\n    }\n\n    /// Updates the value at the specified index in the segment tree.\n    ///\n    /// # Arguments\n    ///\n    /// * `target_idx`: The index (0-based) of the element to update.\n    /// * `val`: The new value of type `T` to set at the specified index.\n    ///\n    /// # Returns\n    ///\n    /// * `Ok(())` if the update was successful,\n    /// * `Err(SegmentTreeError::IndexOutOfBounds)` if the index is out of bounds.\n    pub fn update(&mut self, target_idx: usize, val: T) -> Result<(), SegmentTreeError> {\n        if target_idx >= self.size {\n            return Err(SegmentTreeError::IndexOutOfBounds);\n        }\n        self.update_recursive(1, 0..self.size, target_idx, val);\n        Ok(())\n    }\n\n    /// Recursively updates the segment tree for a specific index with a new value.\n    ///\n    /// # Parameters\n    ///\n    /// * `node_idx` - The index of the current node in the segment tree.\n    /// * `tree_range` - The range of elements covered by the current node.\n    /// * `target_idx` - The index in the original array to update.\n    /// * `val` - The new value to set at `target_idx`.\n    fn update_recursive(\n        &mut self,\n        node_idx: usize,\n        tree_range: Range<usize>,\n        target_idx: usize,\n        val: T,\n    ) {\n        if tree_range.start > target_idx || tree_range.end <= target_idx {\n            return;\n        }\n        if tree_range.end - tree_range.start <= 1 && tree_range.start == target_idx {\n            self.nodes[node_idx] = val;\n            return;\n        }\n        let mid = tree_range.start + (tree_range.end - tree_range.start) / 2;\n        self.update_recursive(node_idx * 2, tree_range.start..mid, target_idx, val);\n        self.update_recursive(node_idx * 2 + 1, mid..tree_range.end, target_idx, val);\n        self.nodes[node_idx] =\n            (self.merge_fn)(self.nodes[node_idx * 2], self.nodes[node_idx * 2 + 1]);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::cmp::{max, min};\n\n    #[test]\n    fn test_min_segments() {\n        let vec = vec![-30, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8];\n        let mut min_seg_tree = SegmentTree::from_vec(&vec, min);\n        assert_eq!(min_seg_tree.query(4..7), Ok(Some(-5)));\n        assert_eq!(min_seg_tree.query(0..vec.len()), Ok(Some(-30)));\n        assert_eq!(min_seg_tree.query(0..2), Ok(Some(-30)));\n        assert_eq!(min_seg_tree.query(1..3), Ok(Some(-4)));\n        assert_eq!(min_seg_tree.query(1..7), Ok(Some(-5)));\n        assert_eq!(min_seg_tree.update(5, 10), Ok(()));\n        assert_eq!(min_seg_tree.update(14, -8), Ok(()));\n        assert_eq!(min_seg_tree.query(4..7), Ok(Some(3)));\n        assert_eq!(\n            min_seg_tree.update(15, 100),\n            Err(SegmentTreeError::IndexOutOfBounds)\n        );\n        assert_eq!(min_seg_tree.query(5..5), Ok(None));\n        assert_eq!(\n            min_seg_tree.query(10..16),\n            Err(SegmentTreeError::InvalidRange)\n        );\n        assert_eq!(\n            min_seg_tree.query(15..20),\n            Err(SegmentTreeError::InvalidRange)\n        );\n    }\n\n    #[test]\n    fn test_max_segments() {\n        let vec = vec![1, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8];\n        let mut max_seg_tree = SegmentTree::from_vec(&vec, max);\n        assert_eq!(max_seg_tree.query(0..vec.len()), Ok(Some(15)));\n        assert_eq!(max_seg_tree.query(3..5), Ok(Some(7)));\n        assert_eq!(max_seg_tree.query(4..8), Ok(Some(11)));\n        assert_eq!(max_seg_tree.query(8..10), Ok(Some(9)));\n        assert_eq!(max_seg_tree.query(9..12), Ok(Some(15)));\n        assert_eq!(max_seg_tree.update(4, 10), Ok(()));\n        assert_eq!(max_seg_tree.update(14, -8), Ok(()));\n        assert_eq!(max_seg_tree.query(3..5), Ok(Some(10)));\n        assert_eq!(\n            max_seg_tree.update(15, 100),\n            Err(SegmentTreeError::IndexOutOfBounds)\n        );\n        assert_eq!(max_seg_tree.query(5..5), Ok(None));\n        assert_eq!(\n            max_seg_tree.query(10..16),\n            Err(SegmentTreeError::InvalidRange)\n        );\n        assert_eq!(\n            max_seg_tree.query(15..20),\n            Err(SegmentTreeError::InvalidRange)\n        );\n    }\n\n    #[test]\n    fn test_sum_segments() {\n        let vec = vec![1, 2, -4, 7, 3, -5, 6, 11, -20, 9, 14, 15, 5, 2, -8];\n        let mut sum_seg_tree = SegmentTree::from_vec(&vec, |a, b| a + b);\n        assert_eq!(sum_seg_tree.query(0..vec.len()), Ok(Some(38)));\n        assert_eq!(sum_seg_tree.query(1..4), Ok(Some(5)));\n        assert_eq!(sum_seg_tree.query(4..7), Ok(Some(4)));\n        assert_eq!(sum_seg_tree.query(6..9), Ok(Some(-3)));\n        assert_eq!(sum_seg_tree.query(9..vec.len()), Ok(Some(37)));\n        assert_eq!(sum_seg_tree.update(5, 10), Ok(()));\n        assert_eq!(sum_seg_tree.update(14, -8), Ok(()));\n        assert_eq!(sum_seg_tree.query(4..7), Ok(Some(19)));\n        assert_eq!(\n            sum_seg_tree.update(15, 100),\n            Err(SegmentTreeError::IndexOutOfBounds)\n        );\n        assert_eq!(sum_seg_tree.query(5..5), Ok(None));\n        assert_eq!(\n            sum_seg_tree.query(10..16),\n            Err(SegmentTreeError::InvalidRange)\n        );\n        assert_eq!(\n            sum_seg_tree.query(15..20),\n            Err(SegmentTreeError::InvalidRange)\n        );\n    }\n}\n"
  },
  {
    "path": "src/data_structures/skip_list.rs",
    "content": "use rand::random_range;\nuse std::{cmp::Ordering, marker::PhantomData, ptr::null_mut};\n\nstruct Node<K: Ord, V> {\n    key: Option<K>,\n    value: Option<V>,\n    forward: Vec<*mut Node<K, V>>,\n}\n\nimpl<K: Ord, V> Node<K, V> {\n    pub fn new() -> Self {\n        let mut forward = Vec::with_capacity(4);\n        forward.resize(4, null_mut());\n        Node {\n            key: None,\n            value: None,\n            forward,\n        }\n    }\n\n    pub fn make_node(capacity: usize, key: K, value: V) -> Self {\n        let mut new_node = Self::new();\n        new_node.key = Some(key);\n        new_node.value = Some(value);\n        new_node.forward = Vec::<*mut Node<K, V>>::with_capacity(capacity);\n        new_node.forward.resize(capacity, null_mut());\n        new_node\n    }\n}\n\n/// A probabilistic data structure that maintains a sorted collection of key-value pairs.\n///\n/// A skip list is a data structure that allows O(log n) search, insertion, and deletion\n/// on average by maintaining multiple levels of linked lists with probabilistic balancing.\npub struct SkipList<K: Ord, V> {\n    header: *mut Node<K, V>,\n    level: usize,\n    max_level: usize,\n    marker: PhantomData<Node<K, V>>,\n}\n\nimpl<K: Ord, V> SkipList<K, V> {\n    pub fn new(max_level: usize) -> Self {\n        let mut node = Box::new(Node::<K, V>::new());\n        node.forward = Vec::with_capacity(max_level);\n        node.forward.resize(max_level, null_mut());\n\n        SkipList {\n            header: Box::into_raw(node),\n            level: 0,\n            max_level,\n            marker: PhantomData,\n        }\n    }\n\n    pub fn search(&self, searched_key: K) -> Option<&V> {\n        let mut x = self.header;\n\n        unsafe {\n            'outer: for i in (0..self.level).rev() {\n                loop {\n                    let forward_i = (&*x).forward[i];\n                    if forward_i.is_null() {\n                        continue 'outer;\n                    }\n\n                    let forward_i_key = (*forward_i).key.as_ref();\n                    match forward_i_key.cmp(&Some(&searched_key)) {\n                        Ordering::Less => {\n                            x = forward_i;\n                        }\n                        _ => {\n                            break;\n                        }\n                    }\n                }\n            }\n\n            x = (&*x).forward[0];\n            if x.is_null() {\n                return None;\n            }\n\n            match (*x).key.as_ref().cmp(&Some(&searched_key)) {\n                Ordering::Equal => {\n                    return (*x).value.as_ref();\n                }\n                _ => {\n                    return None;\n                }\n            }\n        }\n    }\n\n    pub fn insert(&mut self, searched_key: K, new_value: V) -> bool {\n        let mut update = Vec::<*mut Node<K, V>>::with_capacity(self.max_level);\n        update.resize(self.max_level, null_mut());\n\n        let mut x = self.header;\n\n        unsafe {\n            for i in (0..self.level).rev() {\n                loop {\n                    let x_forward_i = (&*x).forward[i];\n                    if x_forward_i.is_null() {\n                        break;\n                    }\n\n                    let x_forward_i_key = (*x_forward_i).key.as_ref();\n                    match x_forward_i_key.cmp(&Some(&searched_key)) {\n                        Ordering::Less => {\n                            x = x_forward_i;\n                        }\n                        _ => {\n                            break;\n                        }\n                    }\n                }\n                let update_i = &mut update[i];\n                *update_i = x;\n            }\n\n            let x_forward_i = (&*x).forward[0];\n            x = x_forward_i;\n            if x.is_null() || (*x).key.as_ref().cmp(&Some(&searched_key)) != Ordering::Equal {\n                let v = random_value(self.max_level);\n                if v > self.level {\n                    for update_i in update.iter_mut().take(v).skip(self.level) {\n                        *update_i = self.header;\n                    }\n                    self.level = v;\n                }\n                let new_node = Node::make_node(v, searched_key, new_value);\n                x = Box::into_raw(Box::new(new_node));\n\n                for (i, t) in update.iter_mut().enumerate().take(self.level) {\n                    let x_forward_i = (&mut *x).forward.get_mut(i);\n                    if x_forward_i.is_none() {\n                        break;\n                    }\n                    let x_forward_i = x_forward_i.unwrap();\n                    let update_i = t;\n                    let update_i_forward_i = &mut (&mut **update_i).forward[i];\n                    *x_forward_i = *update_i_forward_i;\n                    *update_i_forward_i = x;\n                }\n                return true;\n            }\n            (*x).value.replace(new_value);\n            return true;\n        }\n    }\n\n    pub fn delete(&mut self, searched_key: K) -> bool {\n        let mut update = Vec::<*mut Node<K, V>>::with_capacity(self.max_level);\n        update.resize(self.max_level, null_mut());\n\n        let mut x = self.header;\n\n        unsafe {\n            for i in (0..self.level).rev() {\n                loop {\n                    let x_forward_i = (&*x).forward[i];\n                    if x_forward_i.is_null() {\n                        break;\n                    }\n\n                    let x_forward_i_key = (*x_forward_i).key.as_ref();\n                    match x_forward_i_key.cmp(&Some(&searched_key)) {\n                        Ordering::Less => {\n                            x = x_forward_i;\n                        }\n                        _ => {\n                            break;\n                        }\n                    }\n                }\n                let update_i = &mut update[i];\n                *update_i = x;\n            }\n\n            let x_forward_i = *((&*x).forward.first().unwrap());\n            x = x_forward_i;\n\n            if x.is_null() {\n                return false;\n            }\n\n            match (*x).key.as_ref().cmp(&Some(&searched_key)) {\n                Ordering::Equal => {\n                    for (i, update_i) in update.iter_mut().enumerate().take(self.level) {\n                        let update_i_forward_i = &mut (&mut **update_i).forward[i];\n                        if update_i_forward_i.is_null() {\n                            break;\n                        }\n\n                        let x_forward_i = (&mut *x).forward.get_mut(i);\n                        if x_forward_i.is_none() {\n                            break;\n                        }\n                        let x_forward_i = x_forward_i.unwrap();\n                        *update_i_forward_i = *x_forward_i;\n                    }\n\n                    let _v = Box::from_raw(x);\n\n                    loop {\n                        if self.level == 0 {\n                            break;\n                        }\n\n                        let header_forward_level = &(&*self.header).forward[self.level - 1];\n                        if header_forward_level.is_null() {\n                            self.level -= 1;\n                        } else {\n                            break;\n                        }\n                    }\n                    return true;\n                }\n                _ => {\n                    return false;\n                }\n            }\n        }\n    }\n\n    pub fn iter(&self) -> Iter<'_, K, V> {\n        Iter::new(self)\n    }\n}\n\nimpl<K: Ord, V> Drop for SkipList<K, V> {\n    fn drop(&mut self) {\n        let mut node = unsafe { Box::from_raw(self.header) };\n        loop {\n            let node_forward_0 = node.forward.first().unwrap();\n            if node_forward_0.is_null() {\n                break;\n            }\n            node = unsafe { Box::from_raw(*node_forward_0) };\n        }\n    }\n}\n\nfn random_value(max: usize) -> usize {\n    let mut v = 1usize;\n    loop {\n        if random_range(1usize..10usize) > 5 && v < max {\n            v += 1;\n        } else {\n            break;\n        }\n    }\n    v\n}\n\npub struct Iter<'a, K: Ord, V> {\n    current_node: *mut Node<K, V>,\n    _marker: PhantomData<&'a SkipList<K, V>>,\n}\n\nimpl<'a, K: Ord, V> Iter<'a, K, V> {\n    pub fn new(skip_list: &'a SkipList<K, V>) -> Self {\n        Iter {\n            current_node: skip_list.header,\n            _marker: PhantomData,\n        }\n    }\n}\n\nimpl<'a, K: Ord, V> Iterator for Iter<'a, K, V> {\n    type Item = (&'a K, &'a V);\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe {\n            let forward_0 = (&*self.current_node).forward.first();\n            forward_0?;\n            let forward_0 = *forward_0.unwrap();\n            if forward_0.is_null() {\n                return None;\n            }\n            self.current_node = forward_0;\n            return match ((*forward_0).key.as_ref(), (*forward_0).value.as_ref()) {\n                (Some(key), Some(value)) => Some((key, value)),\n                _ => None,\n            };\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    #[test]\n    fn insert_and_delete() {\n        let mut skip_list = super::SkipList::<&'static str, i32>::new(8);\n        skip_list.insert(\"a\", 10);\n        skip_list.insert(\"b\", 12);\n\n        {\n            let result = skip_list.search(\"b\");\n            assert!(result.is_some());\n            assert_eq!(result, Some(&12));\n        }\n\n        {\n            skip_list.delete(\"b\");\n            let result = skip_list.search(\"b\");\n            assert!(result.is_none());\n        }\n\n        skip_list.delete(\"a\");\n    }\n\n    #[test]\n    fn iterator() {\n        let mut skip_list = super::SkipList::<&'static str, i32>::new(8);\n        skip_list.insert(\"h\", 22);\n        skip_list.insert(\"a\", 12);\n        skip_list.insert(\"c\", 11);\n\n        let result: Vec<(&&'static str, &i32)> = skip_list.iter().collect();\n        assert_eq!(result, vec![(&\"a\", &12), (&\"c\", &11), (&\"h\", &22)]);\n    }\n\n    #[test]\n    fn cannot_search() {\n        let mut skip_list = super::SkipList::<&'static str, i32>::new(8);\n\n        {\n            let result = skip_list.search(\"h\");\n            assert!(result.is_none());\n        }\n\n        skip_list.insert(\"h\", 10);\n\n        {\n            let result = skip_list.search(\"a\");\n            assert!(result.is_none());\n        }\n    }\n\n    #[test]\n    fn delete_unsuccessfully() {\n        let mut skip_list = super::SkipList::<&'static str, i32>::new(8);\n\n        {\n            let result = skip_list.delete(\"a\");\n            assert!(!result);\n        }\n\n        skip_list.insert(\"a\", 10);\n\n        {\n            let result = skip_list.delete(\"b\");\n            assert!(!result);\n        }\n    }\n\n    #[test]\n    fn update_value_with_insert_operation() {\n        let mut skip_list = super::SkipList::<&'static str, i32>::new(8);\n        skip_list.insert(\"a\", 10);\n\n        {\n            let result = skip_list.search(\"a\");\n            assert_eq!(result, Some(&10));\n        }\n\n        skip_list.insert(\"a\", 100);\n\n        {\n            let result = skip_list.search(\"a\");\n            assert_eq!(result, Some(&100));\n        }\n    }\n}\n"
  },
  {
    "path": "src/data_structures/stack_using_singly_linked_list.rs",
    "content": "// The public struct can hide the implementation detail\npub struct Stack<T> {\n    head: Link<T>,\n}\n\ntype Link<T> = Option<Box<Node<T>>>;\n\nstruct Node<T> {\n    elem: T,\n    next: Link<T>,\n}\n\nimpl<T> Stack<T> {\n    // Self is an alias for Stack\n    // We implement associated function name new for single-linked-list\n    pub fn new() -> Self {\n        // for new function we need to return a new instance\n        Self {\n            // we refer to variants of an enum using :: the namespacing operator\n            head: None,\n        } // we need to return the variant, so there without the ;\n    }\n\n    // Here are the primary forms that self can take are: self, &mut self and &self.\n    // Since push will modify the linked list, we need a mutable reference `&mut`.\n    // The push method which the signature's first parameter is self\n    pub fn push(&mut self, elem: T) {\n        let new_node = Box::new(Node {\n            elem,\n            next: self.head.take(),\n        });\n        // don't forget replace the head with new node for stack\n        self.head = Some(new_node);\n    }\n\n    /// The pop function removes the head and returns its value.\n    ///\n    /// To do so, we'll need to match the `head` of the list, which is of enum type `Option<T>`.\\\n    /// It has two variants: `Some(T)` and `None`.\n    /// * `None` - the list is empty:\n    ///   * return an enum `Result` of variant `Err()`, as there is nothing to pop.\n    /// * `Some(node)` - the list is not empty:\n    ///   * remove the head of the list,\n    ///   * relink the list's head `head` to its following node `next`,\n    ///   * return `Ok(elem)`.\n    pub fn pop(&mut self) -> Result<T, &str> {\n        match self.head.take() {\n            None => Err(\"Stack is empty\"),\n            Some(node) => {\n                self.head = node.next;\n                Ok(node.elem)\n            }\n        }\n    }\n\n    pub fn is_empty(&self) -> bool {\n        // Returns true if head is of variant `None`.\n        self.head.is_none()\n    }\n\n    pub fn peek(&self) -> Option<&T> {\n        // Converts from &Option<T> to Option<&T>.\n        match self.head.as_ref() {\n            None => None,\n            Some(node) => Some(&node.elem),\n        }\n    }\n\n    pub fn peek_mut(&mut self) -> Option<&mut T> {\n        match self.head.as_mut() {\n            None => None,\n            Some(node) => Some(&mut node.elem),\n        }\n    }\n\n    pub fn into_iter_for_stack(self) -> IntoIter<T> {\n        IntoIter(self)\n    }\n    pub fn iter(&self) -> Iter<'_, T> {\n        Iter {\n            next: self.head.as_deref(),\n        }\n    }\n    // '_ is the \"explicitly elided lifetime\" syntax of Rust\n    pub fn iter_mut(&mut self) -> IterMut<'_, T> {\n        IterMut {\n            next: self.head.as_deref_mut(),\n        }\n    }\n}\n\nimpl<T> Default for Stack<T> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n/// The drop method of singly linked list.\n///\n/// Here's a question: *Do we need to worry about cleaning up our list?*\\\n/// With the help of the ownership mechanism, the type `List` will be cleaned up automatically (dropped) after it goes out of scope.\\\n/// The Rust Compiler does so automacally. In other words, the `Drop` trait is implemented automatically.\\\n///\n/// The `Drop` trait is implemented for our type `List` with the following order: `List->Link->Box<Node>->Node`.\\\n/// The `.drop()` method is tail recursive and will clean the element one by one, this recursion will stop at `Box<Node>`\\\n/// <https://rust-unofficial.github.io/too-many-lists/first-drop.html>\n///\n/// We wouldn't be able to drop the contents contained by the box after deallocating, so we need to manually write the iterative drop.\nimpl<T> Drop for Stack<T> {\n    fn drop(&mut self) {\n        let mut cur_link = self.head.take();\n        while let Some(mut boxed_node) = cur_link {\n            cur_link = boxed_node.next.take();\n            // boxed_node goes out of scope and gets dropped here;\n            // but its Node's `next` field has been set to None\n            // so no unbound recursion occurs.\n        }\n    }\n}\n\n// Rust has nothing like a yield statement, and there are actually 3 different iterator traits to be implemented\n\n// Collections are iterated in Rust using the Iterator trait, we define a struct implement Iterator\npub struct IntoIter<T>(Stack<T>);\n\nimpl<T> Iterator for IntoIter<T> {\n    // This is declaring that every implementation of iterator has an associated type called Item\n    type Item = T;\n    // the reason iterator yield Option<self::Item> is because the interface coalesces the `has_next` and `get_next` concepts\n    fn next(&mut self) -> Option<Self::Item> {\n        self.0.pop().ok()\n    }\n}\n\npub struct Iter<'a, T> {\n    next: Option<&'a Node<T>>,\n}\n\nimpl<'a, T> Iterator for Iter<'a, T> {\n    type Item = &'a T;\n    fn next(&mut self) -> Option<Self::Item> {\n        self.next.map(|node| {\n            // as_deref: Converts from Option<T> (or &Option<T>) to Option<&T::Target>.\n            self.next = node.next.as_deref();\n            &node.elem\n        })\n    }\n}\n\npub struct IterMut<'a, T> {\n    next: Option<&'a mut Node<T>>,\n}\n\nimpl<'a, T> Iterator for IterMut<'a, T> {\n    type Item = &'a mut T;\n    fn next(&mut self) -> Option<Self::Item> {\n        // we add take() here due to &mut self isn't Copy(& and Option<&> is Copy)\n        self.next.take().map(|node| {\n            self.next = node.next.as_deref_mut();\n            &mut node.elem\n        })\n    }\n}\n\n#[cfg(test)]\nmod test_stack {\n\n    use super::*;\n\n    #[test]\n    fn basics() {\n        let mut list = Stack::new();\n        assert_eq!(list.pop(), Err(\"Stack is empty\"));\n\n        list.push(1);\n        list.push(2);\n        list.push(3);\n\n        assert_eq!(list.pop(), Ok(3));\n        assert_eq!(list.pop(), Ok(2));\n\n        list.push(4);\n        list.push(5);\n\n        assert!(!list.is_empty());\n\n        assert_eq!(list.pop(), Ok(5));\n        assert_eq!(list.pop(), Ok(4));\n\n        assert_eq!(list.pop(), Ok(1));\n        assert_eq!(list.pop(), Err(\"Stack is empty\"));\n\n        assert!(list.is_empty());\n    }\n\n    #[test]\n    fn peek() {\n        let mut list = Stack::new();\n        assert_eq!(list.peek(), None);\n        list.push(1);\n        list.push(2);\n        list.push(3);\n\n        assert_eq!(list.peek(), Some(&3));\n        assert_eq!(list.peek_mut(), Some(&mut 3));\n\n        match list.peek_mut() {\n            None => (),\n            Some(value) => *value = 42,\n        };\n\n        assert_eq!(list.peek(), Some(&42));\n        assert_eq!(list.pop(), Ok(42));\n    }\n\n    #[test]\n    fn into_iter() {\n        let mut list = Stack::new();\n        list.push(1);\n        list.push(2);\n        list.push(3);\n\n        let mut iter = list.into_iter_for_stack();\n        assert_eq!(iter.next(), Some(3));\n        assert_eq!(iter.next(), Some(2));\n        assert_eq!(iter.next(), Some(1));\n        assert_eq!(iter.next(), None);\n    }\n\n    #[test]\n    fn iter() {\n        let mut list = Stack::new();\n        list.push(1);\n        list.push(2);\n        list.push(3);\n\n        let mut iter = list.iter();\n        assert_eq!(iter.next(), Some(&3));\n        assert_eq!(iter.next(), Some(&2));\n        assert_eq!(iter.next(), Some(&1));\n    }\n\n    #[test]\n    fn iter_mut() {\n        let mut list = Stack::new();\n        list.push(1);\n        list.push(2);\n        list.push(3);\n\n        let mut iter = list.iter_mut();\n        assert_eq!(iter.next(), Some(&mut 3));\n        assert_eq!(iter.next(), Some(&mut 2));\n        assert_eq!(iter.next(), Some(&mut 1));\n    }\n}\n"
  },
  {
    "path": "src/data_structures/treap.rs",
    "content": "use std::{\n    cmp::Ordering,\n    iter::FromIterator,\n    mem,\n    ops::Not,\n    time::{SystemTime, UNIX_EPOCH},\n};\n\n/// An internal node of an `Treap`.\nstruct TreapNode<T: Ord> {\n    value: T,\n    priority: usize,\n    left: Option<Box<TreapNode<T>>>,\n    right: Option<Box<TreapNode<T>>>,\n}\n\n/// A set based on a Treap (Randomized Binary Search Tree).\n///\n/// A Treap is a self-balancing binary search tree. It matains a priority value for each node, such\n/// that for every node, its children will have lower priority than itself. So, by just looking at\n/// the priority, it is like a heap, and this is where the name, Treap, comes from, Tree + Heap.\npub struct Treap<T: Ord> {\n    root: Option<Box<TreapNode<T>>>,\n    length: usize,\n}\n\n/// Refers to the left or right subtree of a `Treap`.\n#[derive(Clone, Copy)]\nenum Side {\n    Left,\n    Right,\n}\n\nimpl<T: Ord> Treap<T> {\n    pub fn new() -> Treap<T> {\n        Treap {\n            root: None,\n            length: 0,\n        }\n    }\n\n    /// Returns `true` if the tree contains a value.\n    pub fn contains(&self, value: &T) -> bool {\n        let mut current = &self.root;\n        while let Some(node) = current {\n            current = match value.cmp(&node.value) {\n                Ordering::Equal => return true,\n                Ordering::Less => &node.left,\n                Ordering::Greater => &node.right,\n            }\n        }\n        false\n    }\n\n    /// Adds a value to the tree\n    ///\n    /// Returns `true` if the tree did not yet contain the value.\n    pub fn insert(&mut self, value: T) -> bool {\n        let inserted = insert(&mut self.root, value);\n        if inserted {\n            self.length += 1;\n        }\n        inserted\n    }\n\n    /// Removes a value from the tree.\n    ///\n    /// Returns `true` if the tree contained the value.\n    pub fn remove(&mut self, value: &T) -> bool {\n        let removed = remove(&mut self.root, value);\n        if removed {\n            self.length -= 1;\n        }\n        removed\n    }\n\n    /// Returns the number of values in the tree.\n    pub fn len(&self) -> usize {\n        self.length\n    }\n\n    /// Returns `true` if the tree contains no values.\n    pub fn is_empty(&self) -> bool {\n        self.length == 0\n    }\n\n    /// Returns an iterator that visits the nodes in the tree in order.\n    fn node_iter(&self) -> NodeIter<'_, T> {\n        let mut node_iter = NodeIter { stack: Vec::new() };\n        // Initialize stack with path to leftmost child\n        let mut child = &self.root;\n        while let Some(node) = child {\n            node_iter.stack.push(node.as_ref());\n            child = &node.left;\n        }\n        node_iter\n    }\n\n    /// Returns an iterator that visits the values in the tree in ascending order.\n    pub fn iter(&self) -> Iter<'_, T> {\n        Iter {\n            node_iter: self.node_iter(),\n        }\n    }\n}\n\n/// Generating random number, should use rand::Rng if possible.\nfn rand() -> usize {\n    SystemTime::now()\n        .duration_since(UNIX_EPOCH)\n        .unwrap()\n        .subsec_nanos() as usize\n}\n\n/// Recursive helper function for `Treap` insertion.\nfn insert<T: Ord>(tree: &mut Option<Box<TreapNode<T>>>, value: T) -> bool {\n    if let Some(node) = tree {\n        let inserted = match value.cmp(&node.value) {\n            Ordering::Equal => false,\n            Ordering::Less => insert(&mut node.left, value),\n            Ordering::Greater => insert(&mut node.right, value),\n        };\n        if inserted {\n            node.rebalance();\n        }\n        inserted\n    } else {\n        *tree = Some(Box::new(TreapNode {\n            value,\n            priority: rand(),\n            left: None,\n            right: None,\n        }));\n        true\n    }\n}\n\n/// Recursive helper function for `Treap` deletion\nfn remove<T: Ord>(tree: &mut Option<Box<TreapNode<T>>>, value: &T) -> bool {\n    if let Some(node) = tree {\n        let removed = match value.cmp(&node.value) {\n            Ordering::Less => remove(&mut node.left, value),\n            Ordering::Greater => remove(&mut node.right, value),\n            Ordering::Equal => {\n                *tree = match (node.left.take(), node.right.take()) {\n                    (None, None) => None,\n                    (Some(b), None) | (None, Some(b)) => Some(b),\n                    (Some(left), Some(right)) => {\n                        let side = match left.priority.cmp(&right.priority) {\n                            Ordering::Greater => Side::Right,\n                            _ => Side::Left,\n                        };\n                        node.left = Some(left);\n                        node.right = Some(right);\n                        node.rotate(side);\n                        remove(node.child_mut(side), value);\n                        Some(tree.take().unwrap())\n                    }\n                };\n                return true;\n            }\n        };\n        if removed {\n            node.rebalance();\n        }\n        removed\n    } else {\n        false\n    }\n}\n\nimpl<T: Ord> TreapNode<T> {\n    /// Returns a reference to the left or right child.\n    fn child(&self, side: Side) -> &Option<Box<TreapNode<T>>> {\n        match side {\n            Side::Left => &self.left,\n            Side::Right => &self.right,\n        }\n    }\n\n    /// Returns a mutable reference to the left or right child.\n    fn child_mut(&mut self, side: Side) -> &mut Option<Box<TreapNode<T>>> {\n        match side {\n            Side::Left => &mut self.left,\n            Side::Right => &mut self.right,\n        }\n    }\n\n    /// Returns the priority of the left or right subtree.\n    fn priority(&self, side: Side) -> usize {\n        self.child(side).as_ref().map_or(0, |n| n.priority)\n    }\n\n    /// Performs a left or right rotation\n    fn rotate(&mut self, side: Side) {\n        if self.child_mut(!side).is_none() {\n            return;\n        }\n\n        let mut subtree = self.child_mut(!side).take().unwrap();\n        *self.child_mut(!side) = subtree.child_mut(side).take();\n        // Swap root and child nodes in memory\n        mem::swap(self, subtree.as_mut());\n        // Set old root (subtree) as child of new root (self)\n        *self.child_mut(side) = Some(subtree);\n    }\n\n    /// Performs left or right tree rotations to balance this node.\n    fn rebalance(&mut self) {\n        match (\n            self.priority,\n            self.priority(Side::Left),\n            self.priority(Side::Right),\n        ) {\n            (v, p, q) if p >= q && p > v => self.rotate(Side::Right),\n            (v, p, q) if p < q && q > v => self.rotate(Side::Left),\n            _ => (),\n        };\n    }\n\n    #[cfg(test)]\n    fn is_valid(&self) -> bool {\n        self.priority >= self.priority(Side::Left) && self.priority >= self.priority(Side::Right)\n    }\n}\n\nimpl<T: Ord> Default for Treap<T> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl Not for Side {\n    type Output = Side;\n\n    fn not(self) -> Self::Output {\n        match self {\n            Side::Left => Side::Right,\n            Side::Right => Side::Left,\n        }\n    }\n}\n\nimpl<T: Ord> FromIterator<T> for Treap<T> {\n    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {\n        let mut tree = Treap::new();\n        for value in iter {\n            tree.insert(value);\n        }\n        tree\n    }\n}\n\n/// An iterator over the nodes of an `Treap`.\n///\n/// This struct is created by the `node_iter` method of `Treap`.\nstruct NodeIter<'a, T: Ord> {\n    stack: Vec<&'a TreapNode<T>>,\n}\n\nimpl<'a, T: Ord> Iterator for NodeIter<'a, T> {\n    type Item = &'a TreapNode<T>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        if let Some(node) = self.stack.pop() {\n            // Push left path of right subtree to stack\n            let mut child = &node.right;\n            while let Some(subtree) = child {\n                self.stack.push(subtree.as_ref());\n                child = &subtree.left;\n            }\n            Some(node)\n        } else {\n            None\n        }\n    }\n}\n\n/// An iterator over the items of an `Treap`.\n///\n/// This struct is created by the `iter` method of `Treap`.\npub struct Iter<'a, T: Ord> {\n    node_iter: NodeIter<'a, T>,\n}\n\nimpl<'a, T: Ord> Iterator for Iter<'a, T> {\n    type Item = &'a T;\n\n    fn next(&mut self) -> Option<&'a T> {\n        match self.node_iter.next() {\n            Some(node) => Some(&node.value),\n            None => None,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::Treap;\n\n    /// Returns `true` if all nodes in the tree are valid.\n    fn is_valid<T: Ord>(tree: &Treap<T>) -> bool {\n        tree.node_iter().all(|n| n.is_valid())\n    }\n\n    #[test]\n    fn len() {\n        let tree: Treap<_> = (1..4).collect();\n        assert_eq!(tree.len(), 3);\n    }\n\n    #[test]\n    fn contains() {\n        let tree: Treap<_> = (1..4).collect();\n        assert!(tree.contains(&1));\n        assert!(!tree.contains(&4));\n    }\n\n    #[test]\n    fn insert() {\n        let mut tree = Treap::new();\n        // First insert succeeds\n        assert!(tree.insert(1));\n        // Second insert fails\n        assert!(!tree.insert(1));\n    }\n\n    #[test]\n    fn remove() {\n        let mut tree: Treap<_> = (1..8).collect();\n        // First remove succeeds\n        assert!(tree.remove(&4));\n        // Second remove fails\n        assert!(!tree.remove(&4));\n    }\n\n    #[test]\n    fn sorted() {\n        let tree: Treap<_> = (1..8).rev().collect();\n        assert!((1..8).eq(tree.iter().copied()));\n    }\n\n    #[test]\n    fn valid() {\n        let mut tree: Treap<_> = (1..8).collect();\n        assert!(is_valid(&tree));\n        for x in 1..8 {\n            tree.remove(&x);\n            assert!(is_valid(&tree));\n        }\n    }\n}\n"
  },
  {
    "path": "src/data_structures/trie.rs",
    "content": "//! This module provides a generic implementation of a Trie (prefix tree).\n//! A Trie is a tree-like data structure that is commonly used to store sequences of keys\n//! (such as strings, integers, or other iterable types) where each node represents one element\n//! of the key, and values can be associated with full sequences.\n\nuse std::collections::HashMap;\nuse std::hash::Hash;\n\n/// A single node in the Trie structure, representing a key and an optional value.\n#[derive(Debug, Default)]\nstruct Node<Key: Default, Type: Default> {\n    /// A map of children nodes where each key maps to another `Node`.\n    children: HashMap<Key, Node<Key, Type>>,\n    /// The value associated with this node, if any.\n    value: Option<Type>,\n}\n\n/// A generic Trie (prefix tree) data structure that allows insertion and lookup\n/// based on a sequence of keys.\n#[derive(Debug, Default)]\npub struct Trie<Key, Type>\nwhere\n    Key: Default + Eq + Hash,\n    Type: Default,\n{\n    /// The root node of the Trie, which does not hold a value itself.\n    root: Node<Key, Type>,\n}\n\nimpl<Key, Type> Trie<Key, Type>\nwhere\n    Key: Default + Eq + Hash,\n    Type: Default,\n{\n    /// Creates a new, empty `Trie`.\n    ///\n    /// # Returns\n    /// A `Trie` instance with an empty root node.\n    pub fn new() -> Self {\n        Self {\n            root: Node::default(),\n        }\n    }\n\n    /// Inserts a value into the Trie, associating it with a sequence of keys.\n    ///\n    /// # Arguments\n    /// - `key`: An iterable sequence of keys (e.g., characters in a string or integers in a vector).\n    /// - `value`: The value to associate with the sequence of keys.\n    pub fn insert(&mut self, key: impl IntoIterator<Item = Key>, value: Type)\n    where\n        Key: Eq + Hash,\n    {\n        let mut node = &mut self.root;\n        for c in key {\n            node = node.children.entry(c).or_default();\n        }\n        node.value = Some(value);\n    }\n\n    /// Retrieves a reference to the value associated with a sequence of keys, if it exists.\n    ///\n    /// # Arguments\n    /// - `key`: An iterable sequence of keys (e.g., characters in a string or integers in a vector).\n    ///\n    /// # Returns\n    /// An `Option` containing a reference to the value if the sequence of keys exists in the Trie,\n    /// or `None` if it does not.\n    pub fn get(&self, key: impl IntoIterator<Item = Key>) -> Option<&Type>\n    where\n        Key: Eq + Hash,\n    {\n        let mut node = &self.root;\n        for c in key {\n            node = node.children.get(&c)?;\n        }\n        node.value.as_ref()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_insertion_and_retrieval_with_strings() {\n        let mut trie = Trie::new();\n\n        trie.insert(\"foo\".chars(), 1);\n        assert_eq!(trie.get(\"foo\".chars()), Some(&1));\n        trie.insert(\"foobar\".chars(), 2);\n        assert_eq!(trie.get(\"foobar\".chars()), Some(&2));\n        assert_eq!(trie.get(\"foo\".chars()), Some(&1));\n        trie.insert(\"bar\".chars(), 3);\n        assert_eq!(trie.get(\"bar\".chars()), Some(&3));\n        assert_eq!(trie.get(\"baz\".chars()), None);\n        assert_eq!(trie.get(\"foobarbaz\".chars()), None);\n    }\n\n    #[test]\n    fn test_insertion_and_retrieval_with_integers() {\n        let mut trie = Trie::new();\n\n        trie.insert(vec![1, 2, 3], 1);\n        assert_eq!(trie.get(vec![1, 2, 3]), Some(&1));\n        trie.insert(vec![1, 2, 3, 4, 5], 2);\n        assert_eq!(trie.get(vec![1, 2, 3, 4, 5]), Some(&2));\n        assert_eq!(trie.get(vec![1, 2, 3]), Some(&1));\n        trie.insert(vec![10, 20, 30], 3);\n        assert_eq!(trie.get(vec![10, 20, 30]), Some(&3));\n        assert_eq!(trie.get(vec![4, 5, 6]), None);\n        assert_eq!(trie.get(vec![1, 2, 3, 4, 5, 6]), None);\n    }\n\n    #[test]\n    fn test_empty_trie() {\n        let trie: Trie<char, i32> = Trie::new();\n\n        assert_eq!(trie.get(\"foo\".chars()), None);\n        assert_eq!(trie.get(\"\".chars()), None);\n    }\n\n    #[test]\n    fn test_insert_empty_key() {\n        let mut trie: Trie<char, i32> = Trie::new();\n\n        trie.insert(\"\".chars(), 42);\n        assert_eq!(trie.get(\"\".chars()), Some(&42));\n        assert_eq!(trie.get(\"foo\".chars()), None);\n    }\n\n    #[test]\n    fn test_overlapping_keys() {\n        let mut trie = Trie::new();\n\n        trie.insert(\"car\".chars(), 1);\n        trie.insert(\"cart\".chars(), 2);\n        trie.insert(\"carter\".chars(), 3);\n        assert_eq!(trie.get(\"car\".chars()), Some(&1));\n        assert_eq!(trie.get(\"cart\".chars()), Some(&2));\n        assert_eq!(trie.get(\"carter\".chars()), Some(&3));\n        assert_eq!(trie.get(\"care\".chars()), None);\n    }\n\n    #[test]\n    fn test_partial_match() {\n        let mut trie = Trie::new();\n\n        trie.insert(\"apple\".chars(), 10);\n        assert_eq!(trie.get(\"app\".chars()), None);\n        assert_eq!(trie.get(\"appl\".chars()), None);\n        assert_eq!(trie.get(\"apple\".chars()), Some(&10));\n        assert_eq!(trie.get(\"applepie\".chars()), None);\n    }\n}\n"
  },
  {
    "path": "src/data_structures/union_find.rs",
    "content": "//! A Union-Find (Disjoint Set) data structure implementation in Rust.\n//!\n//! The Union-Find data structure keeps track of elements partitioned into\n//! disjoint (non-overlapping) sets.\n//! It provides near-constant-time operations to add new sets, to find the\n//! representative of a set, and to merge sets.\n\nuse std::cmp::Ordering;\nuse std::collections::HashMap;\nuse std::fmt::Debug;\nuse std::hash::Hash;\n\n#[derive(Debug)]\npub struct UnionFind<T: Debug + Eq + Hash> {\n    payloads: HashMap<T, usize>, // Maps values to their indices in the parent_links array.\n    parent_links: Vec<usize>,    // Holds the parent pointers; root elements are their own parents.\n    sizes: Vec<usize>,           // Holds the sizes of the sets.\n    count: usize,                // Number of disjoint sets.\n}\n\nimpl<T: Debug + Eq + Hash> UnionFind<T> {\n    /// Creates an empty Union-Find structure with a specified capacity.\n    pub fn with_capacity(capacity: usize) -> Self {\n        Self {\n            parent_links: Vec::with_capacity(capacity),\n            sizes: Vec::with_capacity(capacity),\n            payloads: HashMap::with_capacity(capacity),\n            count: 0,\n        }\n    }\n\n    /// Inserts a new item (disjoint set) into the data structure.\n    pub fn insert(&mut self, item: T) {\n        let key = self.payloads.len();\n        self.parent_links.push(key);\n        self.sizes.push(1);\n        self.payloads.insert(item, key);\n        self.count += 1;\n    }\n\n    /// Returns the root index of the set containing the given value, or `None` if it doesn't exist.\n    pub fn find(&mut self, value: &T) -> Option<usize> {\n        self.payloads\n            .get(value)\n            .copied()\n            .map(|key| self.find_by_key(key))\n    }\n\n    /// Unites the sets containing the two given values. Returns:\n    /// - `None` if either value hasn't been inserted,\n    /// - `Some(true)` if two disjoint sets have been merged,\n    /// - `Some(false)` if both elements were already in the same set.\n    pub fn union(&mut self, first_item: &T, sec_item: &T) -> Option<bool> {\n        let (first_root, sec_root) = (self.find(first_item), self.find(sec_item));\n        match (first_root, sec_root) {\n            (Some(first_root), Some(sec_root)) => Some(self.union_by_key(first_root, sec_root)),\n            _ => None,\n        }\n    }\n\n    /// Finds the root of the set containing the element with the given index.\n    fn find_by_key(&mut self, key: usize) -> usize {\n        if self.parent_links[key] != key {\n            self.parent_links[key] = self.find_by_key(self.parent_links[key]);\n        }\n        self.parent_links[key]\n    }\n\n    /// Unites the sets containing the two elements identified by their indices.\n    fn union_by_key(&mut self, first_key: usize, sec_key: usize) -> bool {\n        let (first_root, sec_root) = (self.find_by_key(first_key), self.find_by_key(sec_key));\n\n        if first_root == sec_root {\n            return false;\n        }\n\n        match self.sizes[first_root].cmp(&self.sizes[sec_root]) {\n            Ordering::Less => {\n                self.parent_links[first_root] = sec_root;\n                self.sizes[sec_root] += self.sizes[first_root];\n            }\n            _ => {\n                self.parent_links[sec_root] = first_root;\n                self.sizes[first_root] += self.sizes[sec_root];\n            }\n        }\n\n        self.count -= 1;\n        true\n    }\n\n    /// Checks if two items belong to the same set.\n    pub fn is_same_set(&mut self, first_item: &T, sec_item: &T) -> bool {\n        matches!((self.find(first_item), self.find(sec_item)), (Some(first_root), Some(sec_root)) if first_root == sec_root)\n    }\n\n    /// Returns the number of disjoint sets.\n    pub fn count(&self) -> usize {\n        self.count\n    }\n}\n\nimpl<T: Debug + Eq + Hash> Default for UnionFind<T> {\n    fn default() -> Self {\n        Self {\n            parent_links: Vec::default(),\n            sizes: Vec::default(),\n            payloads: HashMap::default(),\n            count: 0,\n        }\n    }\n}\n\nimpl<T: Debug + Eq + Hash> FromIterator<T> for UnionFind<T> {\n    /// Creates a new UnionFind data structure from an iterable of disjoint elements.\n    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {\n        let mut uf = UnionFind::default();\n        for item in iter {\n            uf.insert(item);\n        }\n        uf\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_union_find() {\n        let mut uf = (0..10).collect::<UnionFind<_>>();\n        assert_eq!(uf.find(&0), Some(0));\n        assert_eq!(uf.find(&1), Some(1));\n        assert_eq!(uf.find(&2), Some(2));\n        assert_eq!(uf.find(&3), Some(3));\n        assert_eq!(uf.find(&4), Some(4));\n        assert_eq!(uf.find(&5), Some(5));\n        assert_eq!(uf.find(&6), Some(6));\n        assert_eq!(uf.find(&7), Some(7));\n        assert_eq!(uf.find(&8), Some(8));\n        assert_eq!(uf.find(&9), Some(9));\n\n        assert!(!uf.is_same_set(&0, &1));\n        assert!(!uf.is_same_set(&2, &9));\n        assert_eq!(uf.count(), 10);\n\n        assert_eq!(uf.union(&0, &1), Some(true));\n        assert_eq!(uf.union(&1, &2), Some(true));\n        assert_eq!(uf.union(&2, &3), Some(true));\n        assert_eq!(uf.union(&0, &2), Some(false));\n        assert_eq!(uf.union(&4, &5), Some(true));\n        assert_eq!(uf.union(&5, &6), Some(true));\n        assert_eq!(uf.union(&6, &7), Some(true));\n        assert_eq!(uf.union(&7, &8), Some(true));\n        assert_eq!(uf.union(&8, &9), Some(true));\n        assert_eq!(uf.union(&7, &9), Some(false));\n\n        assert_ne!(uf.find(&0), uf.find(&9));\n        assert_eq!(uf.find(&0), uf.find(&3));\n        assert_eq!(uf.find(&4), uf.find(&9));\n        assert!(uf.is_same_set(&0, &3));\n        assert!(uf.is_same_set(&4, &9));\n        assert!(!uf.is_same_set(&0, &9));\n        assert_eq!(uf.count(), 2);\n\n        assert_eq!(Some(true), uf.union(&3, &4));\n        assert_eq!(uf.find(&0), uf.find(&9));\n        assert_eq!(uf.count(), 1);\n        assert!(uf.is_same_set(&0, &9));\n\n        assert_eq!(None, uf.union(&0, &11));\n    }\n\n    #[test]\n    fn test_spanning_tree() {\n        let mut uf = UnionFind::from_iter([\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\"]);\n        uf.union(&\"A\", &\"B\");\n        uf.union(&\"B\", &\"C\");\n        uf.union(&\"A\", &\"D\");\n        uf.union(&\"F\", &\"G\");\n\n        assert_eq!(None, uf.union(&\"A\", &\"W\"));\n\n        assert_eq!(uf.find(&\"A\"), uf.find(&\"B\"));\n        assert_eq!(uf.find(&\"A\"), uf.find(&\"C\"));\n        assert_eq!(uf.find(&\"B\"), uf.find(&\"D\"));\n        assert_ne!(uf.find(&\"A\"), uf.find(&\"E\"));\n        assert_ne!(uf.find(&\"A\"), uf.find(&\"F\"));\n        assert_eq!(uf.find(&\"G\"), uf.find(&\"F\"));\n        assert_ne!(uf.find(&\"G\"), uf.find(&\"E\"));\n\n        assert!(uf.is_same_set(&\"A\", &\"B\"));\n        assert!(uf.is_same_set(&\"A\", &\"C\"));\n        assert!(uf.is_same_set(&\"B\", &\"D\"));\n        assert!(!uf.is_same_set(&\"B\", &\"F\"));\n        assert!(!uf.is_same_set(&\"E\", &\"A\"));\n        assert!(!uf.is_same_set(&\"E\", &\"G\"));\n        assert_eq!(uf.count(), 3);\n    }\n\n    #[test]\n    fn test_with_capacity() {\n        let mut uf: UnionFind<i32> = UnionFind::with_capacity(5);\n        uf.insert(0);\n        uf.insert(1);\n        uf.insert(2);\n        uf.insert(3);\n        uf.insert(4);\n\n        assert_eq!(uf.count(), 5);\n\n        assert_eq!(uf.union(&0, &1), Some(true));\n        assert!(uf.is_same_set(&0, &1));\n        assert_eq!(uf.count(), 4);\n\n        assert_eq!(uf.union(&2, &3), Some(true));\n        assert!(uf.is_same_set(&2, &3));\n        assert_eq!(uf.count(), 3);\n\n        assert_eq!(uf.union(&0, &2), Some(true));\n        assert!(uf.is_same_set(&0, &1));\n        assert!(uf.is_same_set(&2, &3));\n        assert!(uf.is_same_set(&0, &3));\n        assert_eq!(uf.count(), 2);\n\n        assert_eq!(None, uf.union(&0, &10));\n    }\n}\n"
  },
  {
    "path": "src/data_structures/veb_tree.rs",
    "content": "// This struct implements Van Emde Boas tree (VEB tree). It stores integers in range [0, U), where\n// O is any integer that is a power of 2. It supports operations such as insert, search,\n// predecessor, and successor in O(log(log(U))) time. The structure takes O(U) space.\npub struct VebTree {\n    size: u32,\n    child_size: u32, // Set to square root of size. Cache here to avoid recomputation.\n    min: u32,\n    max: u32,\n    summary: Option<Box<VebTree>>,\n    cluster: Vec<VebTree>,\n}\n\nimpl VebTree {\n    /// Create a new, empty VEB tree. The tree will contain number of elements equal to size\n    /// rounded up to the nearest power of two.\n    pub fn new(size: u32) -> VebTree {\n        let rounded_size = size.next_power_of_two();\n        let child_size = (size as f64).sqrt().ceil() as u32;\n\n        let mut cluster = Vec::new();\n        if rounded_size > 2 {\n            for _ in 0..rounded_size {\n                cluster.push(VebTree::new(child_size));\n            }\n        }\n\n        VebTree {\n            size: rounded_size,\n            child_size,\n            min: u32::MAX,\n            max: u32::MIN,\n            cluster,\n            summary: if rounded_size <= 2 {\n                None\n            } else {\n                Some(Box::new(VebTree::new(child_size)))\n            },\n        }\n    }\n\n    fn high(&self, value: u32) -> u32 {\n        value / self.child_size\n    }\n\n    fn low(&self, value: u32) -> u32 {\n        value % self.child_size\n    }\n\n    fn index(&self, cluster: u32, offset: u32) -> u32 {\n        cluster * self.child_size + offset\n    }\n\n    pub fn min(&self) -> u32 {\n        self.min\n    }\n\n    pub fn max(&self) -> u32 {\n        self.max\n    }\n\n    pub fn iter(&self) -> VebTreeIter<'_> {\n        VebTreeIter::new(self)\n    }\n\n    // A VEB tree is empty if the min is greater than the max.\n    pub fn empty(&self) -> bool {\n        self.min > self.max\n    }\n\n    // Returns true if value is in the tree, false otherwise.\n    pub fn search(&self, value: u32) -> bool {\n        if self.empty() {\n            return false;\n        } else if value == self.min || value == self.max {\n            return true;\n        } else if value < self.min || value > self.max {\n            return false;\n        }\n        self.cluster[self.high(value) as usize].search(self.low(value))\n    }\n\n    fn insert_empty(&mut self, value: u32) {\n        assert!(self.empty(), \"tree should be empty\");\n        self.min = value;\n        self.max = value;\n    }\n\n    // Inserts value into the tree.\n    pub fn insert(&mut self, mut value: u32) {\n        assert!(value < self.size);\n\n        if self.empty() {\n            self.insert_empty(value);\n            return;\n        }\n\n        if value < self.min {\n            // If the new value is less than the current tree's min, set the min to the new value\n            // and insert the old min.\n            (value, self.min) = (self.min, value);\n        }\n\n        if self.size > 2 {\n            // Non base case. The checks for min/max will handle trees of size 2.\n            let high = self.high(value);\n            let low = self.low(value);\n            if self.cluster[high as usize].empty() {\n                // If the cluster tree for the value is empty, we set the min/max of the tree to\n                // value and record that the cluster tree has an elements in the summary.\n                self.cluster[high as usize].insert_empty(low);\n                if let Some(summary) = self.summary.as_mut() {\n                    summary.insert(high);\n                }\n            } else {\n                // If the cluster tree already has a value, the summary does not need to be\n                // updated. Recursively insert the value into the cluster tree.\n                self.cluster[high as usize].insert(low);\n            }\n        }\n\n        if value > self.max {\n            self.max = value;\n        }\n    }\n\n    // Returns the next greatest value(successor) in the tree after pred. Returns\n    // `None` if there is no successor.\n    pub fn succ(&self, pred: u32) -> Option<u32> {\n        if self.empty() {\n            return None;\n        }\n\n        if self.size == 2 {\n            // Base case. If pred is 0, and 1 exists in the tree (max is set to 1), the successor\n            // is 1.\n            return if pred == 0 && self.max == 1 {\n                Some(1)\n            } else {\n                None\n            };\n        }\n\n        if pred < self.min {\n            // If the predecessor is less than the minimum of this tree, the successor is the min.\n            return Some(self.min);\n        }\n\n        let low = self.low(pred);\n        let high = self.high(pred);\n\n        if !self.cluster[high as usize].empty() && low < self.cluster[high as usize].max {\n            // The successor is within the same cluster as the predecessor\n            return Some(self.index(high, self.cluster[high as usize].succ(low).unwrap()));\n        };\n\n        // If we reach this point, the successor exists in a different cluster. We use the summary\n        // to efficiently query which cluster the successor lives in. If there is no successor\n        // cluster, return None.\n        let succ_cluster = self.summary.as_ref().unwrap().succ(high);\n        succ_cluster\n            .map(|succ_cluster| self.index(succ_cluster, self.cluster[succ_cluster as usize].min))\n    }\n\n    // Returns the next smallest value(predecessor) in the tree after succ. Returns\n    // `None` if there is no predecessor. pred() is almost a mirror of succ().\n    // Differences are noted in comments.\n    pub fn pred(&self, succ: u32) -> Option<u32> {\n        if self.empty() {\n            return None;\n        }\n\n        // base case.\n        if self.size == 2 {\n            return if succ == 1 && self.min == 0 {\n                Some(0)\n            } else {\n                None\n            };\n        }\n\n        if succ > self.max {\n            return Some(self.max);\n        }\n\n        let low = self.low(succ);\n        let high = self.high(succ);\n\n        if !self.cluster[high as usize].empty() && low > self.cluster[high as usize].min {\n            return Some(self.index(high, self.cluster[high as usize].pred(low).unwrap()));\n        };\n\n        // Find the cluster that has the predecessor. The successor will be that cluster's max.\n        let succ_cluster = self.summary.as_ref().unwrap().pred(high);\n        match succ_cluster {\n            Some(succ_cluster) => {\n                Some(self.index(succ_cluster, self.cluster[succ_cluster as usize].max))\n            }\n            // Special case for pred() that does not exist in succ(). The current tree's min\n            // does not exist in a cluster. So if we cannot find a cluster that could have the\n            // predecessor, the predecessor could be the min of the current tree.\n            None => {\n                if succ > self.min {\n                    Some(self.min)\n                } else {\n                    None\n                }\n            }\n        }\n    }\n}\n\npub struct VebTreeIter<'a> {\n    tree: &'a VebTree,\n    curr: Option<u32>,\n}\n\nimpl<'a> VebTreeIter<'a> {\n    pub fn new(tree: &'a VebTree) -> VebTreeIter<'a> {\n        let curr = if tree.empty() { None } else { Some(tree.min) };\n        VebTreeIter { tree, curr }\n    }\n}\n\nimpl Iterator for VebTreeIter<'_> {\n    type Item = u32;\n\n    fn next(&mut self) -> Option<u32> {\n        let curr = self.curr;\n        curr?;\n        self.curr = self.tree.succ(curr.unwrap());\n        curr\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::VebTree;\n    use rand::{rngs::StdRng, RngExt, SeedableRng};\n\n    fn test_veb_tree(size: u32, mut elements: Vec<u32>, exclude: Vec<u32>) {\n        // Insert elements\n        let mut tree = VebTree::new(size);\n        for element in elements.iter() {\n            tree.insert(*element);\n        }\n\n        // Test search\n        for element in elements.iter() {\n            assert!(tree.search(*element));\n        }\n        for element in exclude {\n            assert!(!tree.search(element));\n        }\n\n        // Test iterator and successor, and predecessor\n        elements.sort();\n        elements.dedup();\n        for (i, element) in tree.iter().enumerate() {\n            assert!(elements[i] == element);\n        }\n        for i in 1..elements.len() {\n            assert!(tree.succ(elements[i - 1]) == Some(elements[i]));\n            assert!(tree.pred(elements[i]) == Some(elements[i - 1]));\n        }\n    }\n\n    #[test]\n    fn test_empty() {\n        test_veb_tree(16, Vec::new(), (0..16).collect());\n    }\n\n    #[test]\n    fn test_single() {\n        test_veb_tree(16, Vec::from([5]), (0..16).filter(|x| *x != 5).collect());\n    }\n\n    #[test]\n    fn test_two() {\n        test_veb_tree(\n            16,\n            Vec::from([4, 9]),\n            (0..16).filter(|x| *x != 4 && *x != 9).collect(),\n        );\n    }\n\n    #[test]\n    fn test_repeat_insert() {\n        let mut tree = VebTree::new(16);\n        for _ in 0..5 {\n            tree.insert(10);\n        }\n        assert!(tree.search(10));\n        let elements: Vec<u32> = (0..16).filter(|x| *x != 10).collect();\n        for element in elements {\n            assert!(!tree.search(element));\n        }\n    }\n\n    #[test]\n    fn test_linear() {\n        test_veb_tree(16, (0..10).collect(), (10..16).collect());\n    }\n\n    fn test_full(size: u32) {\n        test_veb_tree(size, (0..size).collect(), Vec::new());\n    }\n\n    #[test]\n    fn test_full_small() {\n        test_full(8);\n        test_full(10);\n        test_full(16);\n        test_full(20);\n        test_full(32);\n    }\n\n    #[test]\n    fn test_full_256() {\n        test_full(256);\n    }\n\n    #[test]\n    fn test_10_256() {\n        let mut rng = StdRng::seed_from_u64(0);\n        let elements: Vec<u32> = (0..10).map(|_| rng.random_range(0..255)).collect();\n        test_veb_tree(256, elements, Vec::new());\n    }\n\n    #[test]\n    fn test_100_256() {\n        let mut rng = StdRng::seed_from_u64(0);\n        let elements: Vec<u32> = (0..100).map(|_| rng.random_range(0..255)).collect();\n        test_veb_tree(256, elements, Vec::new());\n    }\n\n    #[test]\n    fn test_100_300() {\n        let mut rng = StdRng::seed_from_u64(0);\n        let elements: Vec<u32> = (0..100).map(|_| rng.random_range(0..255)).collect();\n        test_veb_tree(300, elements, Vec::new());\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/catalan_numbers.rs",
    "content": "//! Catalan Numbers using Dynamic Programming\n//!\n//! The Catalan numbers are a sequence of positive integers that appear in many\n//! counting problems in combinatorics. Such problems include counting:\n//! - The number of Dyck words of length 2n\n//! - The number of well-formed expressions with n pairs of parentheses\n//!   (e.g., `()()` is valid but `())(` is not)\n//! - The number of different ways n + 1 factors can be completely parenthesized\n//!   (e.g., for n = 2, C(n) = 2 and (ab)c and a(bc) are the two valid ways)\n//! - The number of full binary trees with n + 1 leaves\n//!\n//! A Catalan number satisfies the following recurrence relation:\n//! - C(0) = C(1) = 1\n//! - C(n) = sum(C(i) * C(n-i-1)), from i = 0 to n-1\n//!\n//! Sources:\n//! - [Brilliant.org](https://brilliant.org/wiki/catalan-numbers/)\n//! - [Wikipedia](https://en.wikipedia.org/wiki/Catalan_number)\n\n/// Computes the Catalan number sequence from 0 through `upper_limit`.\n///\n/// # Arguments\n///\n/// * `upper_limit` - The upper limit for the Catalan sequence (must be ≥ 0)\n///\n/// # Returns\n///\n/// A vector containing Catalan numbers from C(0) to C(upper_limit)\n///\n/// # Complexity\n///\n/// * Time complexity: O(n²)\n/// * Space complexity: O(n)\n///\n/// where `n` is the `upper_limit`.\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::dynamic_programming::catalan_numbers;\n///\n/// assert_eq!(catalan_numbers(5), vec![1, 1, 2, 5, 14, 42]);\n/// assert_eq!(catalan_numbers(2), vec![1, 1, 2]);\n/// assert_eq!(catalan_numbers(0), vec![1]);\n/// ```\n///\n/// # Warning\n///\n/// This will overflow the 64-bit unsigned integer for large values of `upper_limit`.\n/// For example, C(21) and beyond will cause overflow.\npub fn catalan_numbers(upper_limit: usize) -> Vec<u64> {\n    let mut catalan_list = vec![0u64; upper_limit + 1];\n\n    // Base case: C(0) = 1\n    catalan_list[0] = 1;\n\n    // Base case: C(1) = 1\n    if upper_limit > 0 {\n        catalan_list[1] = 1;\n    }\n\n    // Recurrence relation: C(i) = sum(C(j) * C(i-j-1)), from j = 0 to i-1\n    for i in 2..=upper_limit {\n        for j in 0..i {\n            catalan_list[i] += catalan_list[j] * catalan_list[i - j - 1];\n        }\n    }\n\n    catalan_list\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_catalan_numbers_basic() {\n        assert_eq!(catalan_numbers(5), vec![1, 1, 2, 5, 14, 42]);\n        assert_eq!(catalan_numbers(2), vec![1, 1, 2]);\n        assert_eq!(catalan_numbers(0), vec![1]);\n    }\n\n    #[test]\n    fn test_catalan_numbers_single() {\n        assert_eq!(catalan_numbers(1), vec![1, 1]);\n    }\n\n    #[test]\n    fn test_catalan_numbers_extended() {\n        let result = catalan_numbers(10);\n        assert_eq!(result.len(), 11);\n        assert_eq!(result[0], 1);\n        assert_eq!(result[1], 1);\n        assert_eq!(result[2], 2);\n        assert_eq!(result[3], 5);\n        assert_eq!(result[4], 14);\n        assert_eq!(result[5], 42);\n        assert_eq!(result[6], 132);\n        assert_eq!(result[7], 429);\n        assert_eq!(result[8], 1430);\n        assert_eq!(result[9], 4862);\n        assert_eq!(result[10], 16796);\n    }\n\n    #[test]\n    fn test_catalan_first_few() {\n        // Verify the first few Catalan numbers match known values\n        assert_eq!(catalan_numbers(3), vec![1, 1, 2, 5]);\n        assert_eq!(catalan_numbers(4), vec![1, 1, 2, 5, 14]);\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/coin_change.rs",
    "content": "//! This module provides a solution to the coin change problem using dynamic programming.\n//! The `coin_change` function calculates the fewest number of coins required to make up\n//! a given amount using a specified set of coin denominations.\n//!\n//! The implementation leverages dynamic programming to build up solutions for smaller\n//! amounts and combines them to solve for larger amounts. It ensures optimal substructure\n//! and overlapping subproblems are efficiently utilized to achieve the solution.\n\n//! # Complexity\n//! - Time complexity: O(amount * coins.length)\n//! - Space complexity: O(amount)\n\n/// Returns the fewest number of coins needed to make up the given amount using the provided coin denominations.\n/// If the amount cannot be made up by any combination of the coins, returns `None`.\n///\n/// # Arguments\n/// * `coins` - A slice of coin denominations.\n/// * `amount` - The total amount of money to be made up.\n///\n/// # Returns\n/// * `Option<usize>` - The minimum number of coins required to make up the amount, or `None` if it's not possible.\n///\n/// # Complexity\n/// * Time complexity: O(amount * coins.length)\n/// * Space complexity: O(amount)\npub fn coin_change(coins: &[usize], amount: usize) -> Option<usize> {\n    let mut min_coins = vec![None; amount + 1];\n    min_coins[0] = Some(0);\n\n    (0..=amount).for_each(|curr_amount| {\n        coins\n            .iter()\n            .filter(|&&coin| curr_amount >= coin)\n            .for_each(|&coin| {\n                if let Some(prev_min_coins) = min_coins[curr_amount - coin] {\n                    min_coins[curr_amount] = Some(\n                        min_coins[curr_amount].map_or(prev_min_coins + 1, |curr_min_coins| {\n                            curr_min_coins.min(prev_min_coins + 1)\n                        }),\n                    );\n                }\n            });\n    });\n\n    min_coins[amount]\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! coin_change_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (coins, amount, expected) = $test_case;\n                    assert_eq!(expected, coin_change(&coins, amount));\n                }\n            )*\n        }\n    }\n\n    coin_change_tests! {\n        test_basic_case: (vec![1, 2, 5], 11, Some(3)),\n        test_multiple_denominations: (vec![2, 3, 5, 7, 11], 119, Some(12)),\n        test_empty_coins: (vec![], 1, None),\n        test_zero_amount: (vec![1, 2, 3], 0, Some(0)),\n        test_no_solution_small_coin: (vec![2], 3, None),\n        test_no_solution_large_coin: (vec![10, 20, 50, 100], 5, None),\n        test_single_coin_large_amount: (vec![1], 100, Some(100)),\n        test_large_amount_multiple_coins: (vec![1, 2, 5], 10000, Some(2000)),\n        test_no_combination_possible: (vec![3, 7], 5, None),\n        test_exact_combination: (vec![1, 3, 4], 6, Some(2)),\n        test_large_denomination_multiple_coins: (vec![10, 50, 100], 1000, Some(10)),\n        test_small_amount_not_possible: (vec![5, 10], 1, None),\n        test_non_divisible_amount: (vec![2], 3, None),\n        test_all_multiples: (vec![1, 2, 4, 8], 15, Some(4)),\n        test_large_amount_mixed_coins: (vec![1, 5, 10, 25], 999, Some(45)),\n        test_prime_coins_and_amount: (vec![2, 3, 5, 7], 17, Some(3)),\n        test_coins_larger_than_amount: (vec![5, 10, 20], 1, None),\n        test_repeating_denominations: (vec![1, 1, 1, 5], 8, Some(4)),\n        test_non_standard_denominations: (vec![1, 4, 6, 9], 15, Some(2)),\n        test_very_large_denominations: (vec![1000, 2000, 5000], 1, None),\n        test_large_amount_performance: (vec![1, 5, 10, 25, 50, 100, 200, 500], 9999, Some(29)),\n        test_powers_of_two: (vec![1, 2, 4, 8, 16, 32, 64], 127, Some(7)),\n        test_fibonacci_sequence: (vec![1, 2, 3, 5, 8, 13, 21, 34], 55, Some(2)),\n        test_mixed_small_large: (vec![1, 100, 1000, 10000], 11001, Some(3)),\n        test_impossible_combinations: (vec![2, 4, 6, 8], 7, None),\n        test_greedy_approach_does_not_work: (vec![1, 12, 20], 24, Some(2)),\n        test_zero_denominations_no_solution: (vec![0], 1, None),\n        test_zero_denominations_solution: (vec![0], 0, Some(0)),\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/egg_dropping.rs",
    "content": "//! This module contains the `egg_drop` function, which determines the minimum number of egg droppings\n//! required to find the highest floor from which an egg can be dropped without breaking. It also includes\n//! tests for the function using various test cases, including edge cases.\n\n/// Returns the least number of egg droppings required to determine the highest floor from which an egg will not break upon dropping.\n///\n/// # Arguments\n///\n/// * `eggs` - The number of eggs available.\n/// * `floors` - The number of floors in the building.\n///\n/// # Returns\n///\n/// * `Some(usize)` - The minimum number of drops required if the number of eggs is greater than 0.\n/// * `None` - If the number of eggs is 0.\npub fn egg_drop(eggs: usize, floors: usize) -> Option<usize> {\n    if eggs == 0 {\n        return None;\n    }\n\n    if eggs == 1 || floors == 0 || floors == 1 {\n        return Some(floors);\n    }\n\n    // Create a 2D vector to store solutions to subproblems\n    let mut egg_drops: Vec<Vec<usize>> = vec![vec![0; floors + 1]; eggs + 1];\n\n    // Base cases: 0 floors -> 0 drops, 1 floor -> 1 drop\n    (1..=eggs).for_each(|i| {\n        egg_drops[i][1] = 1;\n    });\n\n    // Base case: 1 egg -> k drops for k floors\n    (1..=floors).for_each(|j| {\n        egg_drops[1][j] = j;\n    });\n\n    // Fill the table using the optimal substructure property\n    (2..=eggs).for_each(|i| {\n        (2..=floors).for_each(|j| {\n            egg_drops[i][j] = (1..=j)\n                .map(|k| 1 + std::cmp::max(egg_drops[i - 1][k - 1], egg_drops[i][j - k]))\n                .min()\n                .unwrap();\n        });\n    });\n\n    Some(egg_drops[eggs][floors])\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! egg_drop_tests {\n        ($($name:ident: $test_cases:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (eggs, floors, expected) = $test_cases;\n                    assert_eq!(egg_drop(eggs, floors), expected);\n                }\n            )*\n        }\n    }\n\n    egg_drop_tests! {\n        test_no_floors: (5, 0, Some(0)),\n        test_one_egg_multiple_floors: (1, 8, Some(8)),\n        test_multiple_eggs_one_floor: (5, 1, Some(1)),\n        test_two_eggs_two_floors: (2, 2, Some(2)),\n        test_three_eggs_five_floors: (3, 5, Some(3)),\n        test_two_eggs_ten_floors: (2, 10, Some(4)),\n        test_two_eggs_thirty_six_floors: (2, 36, Some(8)),\n        test_many_eggs_one_floor: (100, 1, Some(1)),\n        test_many_eggs_few_floors: (100, 5, Some(3)),\n        test_few_eggs_many_floors: (2, 1000, Some(45)),\n        test_zero_eggs: (0, 10, None::<usize>),\n        test_no_eggs_no_floors: (0, 0, None::<usize>),\n        test_one_egg_no_floors: (1, 0, Some(0)),\n        test_one_egg_one_floor: (1, 1, Some(1)),\n        test_maximum_floors_one_egg: (1, usize::MAX, Some(usize::MAX)),\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/fibonacci.rs",
    "content": "/// Fibonacci via Dynamic Programming\nuse std::collections::HashMap;\n\n/// fibonacci(n) returns the nth fibonacci number\n/// This function uses the definition of Fibonacci where:\n/// F(0) = F(1) = 1 and F(n+1) = F(n) + F(n-1) for n>0\n///\n/// Warning: This will overflow the 128-bit unsigned integer at n=186\npub fn fibonacci(n: u32) -> u128 {\n    // Use a and b to store the previous two values in the sequence\n    let mut a = 0;\n    let mut b = 1;\n    for _i in 0..n {\n        // As we iterate through, move b's value into a and the new computed\n        // value into b.\n        let c = a + b;\n        a = b;\n        b = c;\n    }\n    b\n}\n\n/// fibonacci(n) returns the nth fibonacci number\n/// This function uses the definition of Fibonacci where:\n/// F(0) = F(1) = 1 and F(n+1) = F(n) + F(n-1) for n>0\n///\n/// Warning: This will overflow the 128-bit unsigned integer at n=186\npub fn recursive_fibonacci(n: u32) -> u128 {\n    // Call the actual tail recursive implementation, with the extra\n    // arguments set up.\n    _recursive_fibonacci(n, 0, 1)\n}\n\nfn _recursive_fibonacci(n: u32, previous: u128, current: u128) -> u128 {\n    if n == 0 {\n        current\n    } else {\n        _recursive_fibonacci(n - 1, current, current + previous)\n    }\n}\n\n/// classical_fibonacci(n) returns the nth fibonacci number\n/// This function uses the definition of Fibonacci where:\n/// F(0) = 0, F(1) = 1 and F(n+1) = F(n) + F(n-1) for n>0\n///\n/// Warning: This will overflow the 128-bit unsigned integer at n=186\npub fn classical_fibonacci(n: u32) -> u128 {\n    match n {\n        0 => 0,\n        1 => 1,\n        _ => {\n            let k = n / 2;\n            let f1 = classical_fibonacci(k);\n            let f2 = classical_fibonacci(k - 1);\n\n            match n % 4 {\n                0 | 2 => f1 * (f1 + 2 * f2),\n                1 => (2 * f1 + f2) * (2 * f1 - f2) + 2,\n                _ => (2 * f1 + f2) * (2 * f1 - f2) - 2,\n            }\n        }\n    }\n}\n\n/// logarithmic_fibonacci(n) returns the nth fibonacci number\n/// This function uses the definition of Fibonacci where:\n/// F(0) = 0, F(1) = 1 and F(n+1) = F(n) + F(n-1) for n>0\n///\n/// Warning: This will overflow the 128-bit unsigned integer at n=186\npub fn logarithmic_fibonacci(n: u32) -> u128 {\n    // if it is the max value before overflow, use n-1 then get the second\n    // value in the tuple\n    if n == 186 {\n        let (_, second) = _logarithmic_fibonacci(185);\n        second\n    } else {\n        let (first, _) = _logarithmic_fibonacci(n);\n        first\n    }\n}\n\nfn _logarithmic_fibonacci(n: u32) -> (u128, u128) {\n    match n {\n        0 => (0, 1),\n        _ => {\n            let (current, next) = _logarithmic_fibonacci(n / 2);\n            let c = current * (next * 2 - current);\n            let d = current * current + next * next;\n\n            match n % 2 {\n                0 => (c, d),\n                _ => (d, c + d),\n            }\n        }\n    }\n}\n\n/// Memoized fibonacci.\npub fn memoized_fibonacci(n: u32) -> u128 {\n    let mut cache: HashMap<u32, u128> = HashMap::new();\n\n    _memoized_fibonacci(n, &mut cache)\n}\n\nfn _memoized_fibonacci(n: u32, cache: &mut HashMap<u32, u128>) -> u128 {\n    if n == 0 {\n        return 0;\n    }\n    if n == 1 {\n        return 1;\n    }\n\n    let f = match cache.get(&n) {\n        Some(f) => f,\n        None => {\n            let f1 = _memoized_fibonacci(n - 1, cache);\n            let f2 = _memoized_fibonacci(n - 2, cache);\n            cache.insert(n, f1 + f2);\n            cache.get(&n).unwrap()\n        }\n    };\n\n    *f\n}\n\n/// matrix_fibonacci(n) returns the nth fibonacci number\n/// This function uses the definition of Fibonacci where:\n/// F(0) = 0, F(1) = 1 and F(n+1) = F(n) + F(n-1) for n>0\n///\n/// Matrix formula:\n/// [F(n + 2)]  =  [1, 1] * [F(n + 1)]\n/// [F(n + 1)]     [1, 0]   [F(n)    ]\n///\n/// Warning: This will overflow the 128-bit unsigned integer at n=186\npub fn matrix_fibonacci(n: u32) -> u128 {\n    let multiplier: Vec<Vec<u128>> = vec![vec![1, 1], vec![1, 0]];\n\n    let multiplier = matrix_power(&multiplier, n);\n    let initial_fib_matrix: Vec<Vec<u128>> = vec![vec![1], vec![0]];\n\n    let res = matrix_multiply(&multiplier, &initial_fib_matrix);\n\n    res[1][0]\n}\n\nfn matrix_power(base: &Vec<Vec<u128>>, power: u32) -> Vec<Vec<u128>> {\n    let identity_matrix: Vec<Vec<u128>> = vec![vec![1, 0], vec![0, 1]];\n\n    vec![base; power as usize]\n        .iter()\n        .fold(identity_matrix, |acc, x| matrix_multiply(&acc, x))\n}\n\n// Copied from matrix_ops since u128 is required instead of i32\n#[allow(clippy::needless_range_loop)]\nfn matrix_multiply(multiplier: &[Vec<u128>], multiplicand: &[Vec<u128>]) -> Vec<Vec<u128>> {\n    // Multiply two matching matrices. The multiplier needs to have the same amount\n    // of columns as the multiplicand has rows.\n    let mut result: Vec<Vec<u128>> = vec![];\n    let mut temp;\n    // Using variable to compare lengths of rows in multiplicand later\n    let row_right_length = multiplicand[0].len();\n    for row_left in 0..multiplier.len() {\n        if multiplier[row_left].len() != multiplicand.len() {\n            panic!(\"Matrix dimensions do not match\");\n        }\n        result.push(vec![]);\n        for column_right in 0..multiplicand[0].len() {\n            temp = 0;\n            for row_right in 0..multiplicand.len() {\n                if row_right_length != multiplicand[row_right].len() {\n                    // If row is longer than a previous row cancel operation with error\n                    panic!(\"Matrix dimensions do not match\");\n                }\n                temp += multiplier[row_left][row_right] * multiplicand[row_right][column_right];\n            }\n            result[row_left].push(temp);\n        }\n    }\n    result\n}\n\n/// Binary lifting fibonacci\n///\n/// Following properties of F(n) could be deduced from the matrix formula above:\n///\n/// F(2n)   = F(n) * (2F(n+1) - F(n))\n/// F(2n+1) = F(n+1)^2 + F(n)^2\n///\n/// Therefore F(n) and F(n+1) can be derived from F(n>>1) and F(n>>1 + 1), which\n/// has a smaller constant in both time and space compared to matrix fibonacci.\npub fn binary_lifting_fibonacci(n: u32) -> u128 {\n    // the state always stores F(k), F(k+1) for some k, initially F(0), F(1)\n    let mut state = (0u128, 1u128);\n\n    for i in (0..u32::BITS - n.leading_zeros()).rev() {\n        // compute F(2k), F(2k+1) from F(k), F(k+1)\n        state = (\n            state.0 * (2 * state.1 - state.0),\n            state.0 * state.0 + state.1 * state.1,\n        );\n        if n & (1 << i) != 0 {\n            state = (state.1, state.0 + state.1);\n        }\n    }\n\n    state.0\n}\n\n/// nth_fibonacci_number_modulo_m(n, m) returns the nth fibonacci number modulo the specified m\n/// i.e. F(n) % m\npub fn nth_fibonacci_number_modulo_m(n: i64, m: i64) -> i128 {\n    let (length, pisano_sequence) = get_pisano_sequence_and_period(m);\n\n    let remainder = n % length as i64;\n    pisano_sequence[remainder as usize].to_owned()\n}\n\n/// get_pisano_sequence_and_period(m) returns the Pisano Sequence and period for the specified integer m.\n/// The pisano period is the period with which the sequence of Fibonacci numbers taken modulo m repeats.\n/// The pisano sequence is the numbers in pisano period.\nfn get_pisano_sequence_and_period(m: i64) -> (i128, Vec<i128>) {\n    let mut a = 0;\n    let mut b = 1;\n    let mut length: i128 = 0;\n    let mut pisano_sequence: Vec<i128> = vec![a, b];\n\n    // Iterating through all the fib numbers to get the sequence\n    for _i in 0..=(m * m) {\n        let c = (a + b) % m as i128;\n\n        // adding number into the sequence\n        pisano_sequence.push(c);\n\n        a = b;\n        b = c;\n\n        if a == 0 && b == 1 {\n            // Remove the last two elements from the sequence\n            // This is a less elegant way to do it.\n            pisano_sequence.pop();\n            pisano_sequence.pop();\n            length = pisano_sequence.len() as i128;\n            break;\n        }\n    }\n\n    (length, pisano_sequence)\n}\n\n/// last_digit_of_the_sum_of_nth_fibonacci_number(n) returns the last digit of the sum of n fibonacci numbers.\n/// The function uses the definition of Fibonacci where:\n/// F(0) = 0, F(1) = 1 and F(n+1) = F(n) + F(n-1) for n > 2\n///\n/// The sum of the Fibonacci numbers are:\n/// F(0) + F(1) + F(2) + ... + F(n)\npub fn last_digit_of_the_sum_of_nth_fibonacci_number(n: i64) -> i64 {\n    if n < 2 {\n        return n;\n    }\n\n    // the pisano period of mod 10 is 60\n    let n = ((n + 2) % 60) as usize;\n    let mut fib = vec![0; n + 1];\n    fib[0] = 0;\n    fib[1] = 1;\n\n    for i in 2..=n {\n        fib[i] = (fib[i - 1] % 10 + fib[i - 2] % 10) % 10;\n    }\n\n    if fib[n] == 0 {\n        return 9;\n    }\n\n    fib[n] % 10 - 1\n}\n\n#[cfg(test)]\nmod tests {\n    use super::binary_lifting_fibonacci;\n    use super::classical_fibonacci;\n    use super::fibonacci;\n    use super::last_digit_of_the_sum_of_nth_fibonacci_number;\n    use super::logarithmic_fibonacci;\n    use super::matrix_fibonacci;\n    use super::memoized_fibonacci;\n    use super::nth_fibonacci_number_modulo_m;\n    use super::recursive_fibonacci;\n\n    #[test]\n    fn test_fibonacci() {\n        assert_eq!(fibonacci(0), 1);\n        assert_eq!(fibonacci(1), 1);\n        assert_eq!(fibonacci(2), 2);\n        assert_eq!(fibonacci(3), 3);\n        assert_eq!(fibonacci(4), 5);\n        assert_eq!(fibonacci(5), 8);\n        assert_eq!(fibonacci(10), 89);\n        assert_eq!(fibonacci(20), 10946);\n        assert_eq!(fibonacci(100), 573147844013817084101);\n        assert_eq!(fibonacci(184), 205697230343233228174223751303346572685);\n    }\n\n    #[test]\n    fn test_recursive_fibonacci() {\n        assert_eq!(recursive_fibonacci(0), 1);\n        assert_eq!(recursive_fibonacci(1), 1);\n        assert_eq!(recursive_fibonacci(2), 2);\n        assert_eq!(recursive_fibonacci(3), 3);\n        assert_eq!(recursive_fibonacci(4), 5);\n        assert_eq!(recursive_fibonacci(5), 8);\n        assert_eq!(recursive_fibonacci(10), 89);\n        assert_eq!(recursive_fibonacci(20), 10946);\n        assert_eq!(recursive_fibonacci(100), 573147844013817084101);\n        assert_eq!(\n            recursive_fibonacci(184),\n            205697230343233228174223751303346572685\n        );\n    }\n\n    #[test]\n    fn test_classical_fibonacci() {\n        assert_eq!(classical_fibonacci(0), 0);\n        assert_eq!(classical_fibonacci(1), 1);\n        assert_eq!(classical_fibonacci(2), 1);\n        assert_eq!(classical_fibonacci(3), 2);\n        assert_eq!(classical_fibonacci(4), 3);\n        assert_eq!(classical_fibonacci(5), 5);\n        assert_eq!(classical_fibonacci(10), 55);\n        assert_eq!(classical_fibonacci(20), 6765);\n        assert_eq!(classical_fibonacci(21), 10946);\n        assert_eq!(classical_fibonacci(100), 354224848179261915075);\n        assert_eq!(\n            classical_fibonacci(184),\n            127127879743834334146972278486287885163\n        );\n    }\n\n    #[test]\n    fn test_logarithmic_fibonacci() {\n        assert_eq!(logarithmic_fibonacci(0), 0);\n        assert_eq!(logarithmic_fibonacci(1), 1);\n        assert_eq!(logarithmic_fibonacci(2), 1);\n        assert_eq!(logarithmic_fibonacci(3), 2);\n        assert_eq!(logarithmic_fibonacci(4), 3);\n        assert_eq!(logarithmic_fibonacci(5), 5);\n        assert_eq!(logarithmic_fibonacci(10), 55);\n        assert_eq!(logarithmic_fibonacci(20), 6765);\n        assert_eq!(logarithmic_fibonacci(21), 10946);\n        assert_eq!(logarithmic_fibonacci(100), 354224848179261915075);\n        assert_eq!(\n            logarithmic_fibonacci(184),\n            127127879743834334146972278486287885163\n        );\n    }\n\n    #[test]\n    /// Check that the iterative and recursive fibonacci\n    /// produce the same value. Both are combinatorial ( F(0) = F(1) = 1 )\n    fn test_iterative_and_recursive_equivalence() {\n        assert_eq!(fibonacci(0), recursive_fibonacci(0));\n        assert_eq!(fibonacci(1), recursive_fibonacci(1));\n        assert_eq!(fibonacci(2), recursive_fibonacci(2));\n        assert_eq!(fibonacci(3), recursive_fibonacci(3));\n        assert_eq!(fibonacci(4), recursive_fibonacci(4));\n        assert_eq!(fibonacci(5), recursive_fibonacci(5));\n        assert_eq!(fibonacci(10), recursive_fibonacci(10));\n        assert_eq!(fibonacci(20), recursive_fibonacci(20));\n        assert_eq!(fibonacci(100), recursive_fibonacci(100));\n        assert_eq!(fibonacci(184), recursive_fibonacci(184));\n    }\n\n    #[test]\n    /// Check that classical and combinatorial fibonacci produce the\n    /// same value when 'n' differs by 1.\n    /// classical fibonacci: ( F(0) = 0, F(1) = 1 )\n    /// combinatorial fibonacci: ( F(0) = F(1) = 1 )\n    fn test_classical_and_combinatorial_are_off_by_one() {\n        assert_eq!(classical_fibonacci(1), fibonacci(0));\n        assert_eq!(classical_fibonacci(2), fibonacci(1));\n        assert_eq!(classical_fibonacci(3), fibonacci(2));\n        assert_eq!(classical_fibonacci(4), fibonacci(3));\n        assert_eq!(classical_fibonacci(5), fibonacci(4));\n        assert_eq!(classical_fibonacci(6), fibonacci(5));\n        assert_eq!(classical_fibonacci(11), fibonacci(10));\n        assert_eq!(classical_fibonacci(20), fibonacci(19));\n        assert_eq!(classical_fibonacci(21), fibonacci(20));\n        assert_eq!(classical_fibonacci(101), fibonacci(100));\n        assert_eq!(classical_fibonacci(185), fibonacci(184));\n    }\n\n    #[test]\n    fn test_memoized_fibonacci() {\n        assert_eq!(memoized_fibonacci(0), 0);\n        assert_eq!(memoized_fibonacci(1), 1);\n        assert_eq!(memoized_fibonacci(2), 1);\n        assert_eq!(memoized_fibonacci(3), 2);\n        assert_eq!(memoized_fibonacci(4), 3);\n        assert_eq!(memoized_fibonacci(5), 5);\n        assert_eq!(memoized_fibonacci(10), 55);\n        assert_eq!(memoized_fibonacci(20), 6765);\n        assert_eq!(memoized_fibonacci(21), 10946);\n        assert_eq!(memoized_fibonacci(100), 354224848179261915075);\n        assert_eq!(\n            memoized_fibonacci(184),\n            127127879743834334146972278486287885163\n        );\n    }\n\n    #[test]\n    fn test_matrix_fibonacci() {\n        assert_eq!(matrix_fibonacci(0), 0);\n        assert_eq!(matrix_fibonacci(1), 1);\n        assert_eq!(matrix_fibonacci(2), 1);\n        assert_eq!(matrix_fibonacci(3), 2);\n        assert_eq!(matrix_fibonacci(4), 3);\n        assert_eq!(matrix_fibonacci(5), 5);\n        assert_eq!(matrix_fibonacci(10), 55);\n        assert_eq!(matrix_fibonacci(20), 6765);\n        assert_eq!(matrix_fibonacci(21), 10946);\n        assert_eq!(matrix_fibonacci(100), 354224848179261915075);\n        assert_eq!(\n            matrix_fibonacci(184),\n            127127879743834334146972278486287885163\n        );\n    }\n\n    #[test]\n    fn test_binary_lifting_fibonacci() {\n        assert_eq!(binary_lifting_fibonacci(0), 0);\n        assert_eq!(binary_lifting_fibonacci(1), 1);\n        assert_eq!(binary_lifting_fibonacci(2), 1);\n        assert_eq!(binary_lifting_fibonacci(3), 2);\n        assert_eq!(binary_lifting_fibonacci(4), 3);\n        assert_eq!(binary_lifting_fibonacci(5), 5);\n        assert_eq!(binary_lifting_fibonacci(10), 55);\n        assert_eq!(binary_lifting_fibonacci(20), 6765);\n        assert_eq!(binary_lifting_fibonacci(21), 10946);\n        assert_eq!(binary_lifting_fibonacci(100), 354224848179261915075);\n        assert_eq!(\n            binary_lifting_fibonacci(184),\n            127127879743834334146972278486287885163\n        );\n    }\n\n    #[test]\n    fn test_nth_fibonacci_number_modulo_m() {\n        assert_eq!(nth_fibonacci_number_modulo_m(5, 10), 5);\n        assert_eq!(nth_fibonacci_number_modulo_m(10, 7), 6);\n        assert_eq!(nth_fibonacci_number_modulo_m(20, 100), 65);\n        assert_eq!(nth_fibonacci_number_modulo_m(1, 5), 1);\n        assert_eq!(nth_fibonacci_number_modulo_m(0, 15), 0);\n        assert_eq!(nth_fibonacci_number_modulo_m(50, 1000), 25);\n        assert_eq!(nth_fibonacci_number_modulo_m(100, 37), 7);\n        assert_eq!(nth_fibonacci_number_modulo_m(15, 2), 0);\n        assert_eq!(nth_fibonacci_number_modulo_m(8, 1_000_000), 21);\n        assert_eq!(nth_fibonacci_number_modulo_m(1000, 997), 996);\n        assert_eq!(nth_fibonacci_number_modulo_m(200, 123), 0);\n    }\n\n    #[test]\n    fn test_last_digit_of_the_sum_of_nth_fibonacci_number() {\n        assert_eq!(last_digit_of_the_sum_of_nth_fibonacci_number(0), 0);\n        assert_eq!(last_digit_of_the_sum_of_nth_fibonacci_number(1), 1);\n        assert_eq!(last_digit_of_the_sum_of_nth_fibonacci_number(2), 2);\n        assert_eq!(last_digit_of_the_sum_of_nth_fibonacci_number(3), 4);\n        assert_eq!(last_digit_of_the_sum_of_nth_fibonacci_number(4), 7);\n        assert_eq!(last_digit_of_the_sum_of_nth_fibonacci_number(5), 2);\n        assert_eq!(last_digit_of_the_sum_of_nth_fibonacci_number(25), 7);\n        assert_eq!(last_digit_of_the_sum_of_nth_fibonacci_number(50), 8);\n        assert_eq!(last_digit_of_the_sum_of_nth_fibonacci_number(100), 5);\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/fractional_knapsack.rs",
    "content": "pub fn fractional_knapsack(mut capacity: f64, weights: Vec<f64>, values: Vec<f64>) -> f64 {\n    // vector of tuple of weights and their value/weight ratio\n    let mut weights: Vec<(f64, f64)> = weights\n        .iter()\n        .zip(values.iter())\n        .map(|(&w, &v)| (w, v / w))\n        .collect();\n\n    // sort in decreasing order by value/weight ratio\n    weights.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).expect(\"Encountered NaN\"));\n    dbg!(&weights);\n\n    // value to compute\n    let mut knapsack_value: f64 = 0.0;\n\n    // iterate through our vector.\n    for w in weights {\n        // w.0 is weight and w.1 value/weight ratio\n        if w.0 < capacity {\n            capacity -= w.0; // our sack is filling\n            knapsack_value += w.0 * w.1;\n            dbg!(&w.0, &knapsack_value);\n        } else {\n            // Multiply with capacity and not w.0\n            dbg!(&w.0, &knapsack_value);\n            knapsack_value += capacity * w.1;\n            break;\n        }\n    }\n\n    knapsack_value\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test() {\n        let capacity = 50.0;\n        let values = vec![60.0, 100.0, 120.0];\n        let weights = vec![10.0, 20.0, 30.0];\n        assert_eq!(fractional_knapsack(capacity, weights, values), 240.0);\n    }\n\n    #[test]\n    fn test2() {\n        let capacity = 60.0;\n        let values = vec![280.0, 100.0, 120.0, 120.0];\n        let weights = vec![40.0, 10.0, 20.0, 24.0];\n        assert_eq!(fractional_knapsack(capacity, weights, values), 440.0);\n    }\n\n    #[test]\n    fn test3() {\n        let capacity = 50.0;\n        let values = vec![60.0, 100.0, 120.0];\n        let weights = vec![20.0, 50.0, 30.0];\n        assert_eq!(fractional_knapsack(capacity, weights, values), 180.0);\n    }\n\n    #[test]\n    fn test4() {\n        let capacity = 60.0;\n        let values = vec![30.0, 40.0, 45.0, 77.0, 90.0];\n        let weights = vec![5.0, 10.0, 15.0, 22.0, 25.0];\n        assert_eq!(fractional_knapsack(capacity, weights, values), 230.0);\n    }\n\n    #[test]\n    fn test5() {\n        let capacity = 10.0;\n        let values = vec![500.0];\n        let weights = vec![30.0];\n        assert_eq!(\n            format!(\"{:.2}\", fractional_knapsack(capacity, weights, values)),\n            String::from(\"166.67\")\n        );\n    }\n\n    #[test]\n    fn test6() {\n        let capacity = 36.0;\n        let values = vec![25.0, 25.0, 25.0, 6.0, 2.0];\n        let weights = vec![10.0, 10.0, 10.0, 4.0, 2.0];\n        assert_eq!(fractional_knapsack(capacity, weights, values), 83.0);\n    }\n\n    #[test]\n    #[should_panic]\n    fn test_nan() {\n        let capacity = 36.0;\n        // 2nd element is NaN\n        let values = vec![25.0, f64::NAN, 25.0, 6.0, 2.0];\n        let weights = vec![10.0, 10.0, 10.0, 4.0, 2.0];\n        assert_eq!(fractional_knapsack(capacity, weights, values), 83.0);\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/integer_partition.rs",
    "content": "//! Integer partition using dynamic programming\n//!\n//! The number of partitions of a number n into at least k parts equals the number of\n//! partitions into exactly k parts plus the number of partitions into at least k-1 parts.\n//! Subtracting 1 from each part of a partition of n into k parts gives a partition of n-k\n//! into k parts. These two facts together are used for this algorithm.\n//!\n//! More info:\n//! * <https://en.wikipedia.org/wiki/Partition_(number_theory)>\n//! * <https://en.wikipedia.org/wiki/Partition_function_(number_theory)>\n\n#![allow(clippy::large_stack_arrays)]\n\n/// Calculates the number of partitions of a positive integer using dynamic programming.\n///\n/// # Arguments\n///\n/// * `m` - A positive integer to find the number of partitions for\n///\n/// # Returns\n///\n/// The number of partitions of `m`\n///\n/// # Panics\n///\n/// Panics if `m` is not a positive integer (0 or negative)\n///\n/// # Examples\n///\n/// ```\n/// # use the_algorithms_rust::dynamic_programming::partition;\n/// assert_eq!(partition(5), 7);\n/// assert_eq!(partition(7), 15);\n/// assert_eq!(partition(100), 190569292);\n/// ```\n#[allow(clippy::large_stack_arrays)]\npub fn partition(m: i32) -> u128 {\n    // Validate input\n    assert!(m > 0, \"Input must be a positive integer greater than 0\");\n\n    let m = m as usize;\n\n    // Initialize memo table with zeros using iterative construction\n    // to avoid large stack allocations\n    let mut memo: Vec<Vec<u128>> = Vec::with_capacity(m + 1);\n    for _ in 0..=m {\n        memo.push(vec![0u128; m]);\n    }\n\n    // Base case: there's one way to partition into 0 parts (empty partition)\n    for i in 0..=m {\n        memo[i][0] = 1;\n    }\n\n    // Fill the memo table using dynamic programming\n    for n in 0..=m {\n        for k in 1..m {\n            // Add partitions from k-1 (partitions with at least k-1 parts)\n            memo[n][k] += memo[n][k - 1];\n\n            // Add partitions from n-k-1 with k parts (subtract 1 from each part)\n            if n > k {\n                memo[n][k] += memo[n - k - 1][k];\n            }\n        }\n    }\n\n    memo[m][m - 1]\n}\n\n#[cfg(test)]\n#[allow(clippy::large_stack_arrays)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_partition_5() {\n        assert_eq!(partition(5), 7);\n    }\n\n    #[test]\n    fn test_partition_7() {\n        assert_eq!(partition(7), 15);\n    }\n\n    #[test]\n    #[allow(clippy::large_stack_arrays)]\n    fn test_partition_100() {\n        assert_eq!(partition(100), 190569292);\n    }\n\n    #[test]\n    #[allow(clippy::large_stack_arrays)]\n    fn test_partition_1000() {\n        assert_eq!(partition(1000), 24061467864032622473692149727991);\n    }\n\n    #[test]\n    #[should_panic(expected = \"Input must be a positive integer greater than 0\")]\n    fn test_partition_negative() {\n        partition(-7);\n    }\n\n    #[test]\n    #[should_panic(expected = \"Input must be a positive integer greater than 0\")]\n    fn test_partition_zero() {\n        partition(0);\n    }\n\n    #[test]\n    fn test_partition_small_values() {\n        assert_eq!(partition(1), 1);\n        assert_eq!(partition(2), 2);\n        assert_eq!(partition(3), 3);\n        assert_eq!(partition(4), 5);\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/is_subsequence.rs",
    "content": "//! A module for checking if one string is a subsequence of another string.\n//!\n//! A subsequence is formed by deleting some (can be none) of the characters\n//! from the original string without disturbing the relative positions of the\n//! remaining characters. This module provides a function to determine if\n//! a given string is a subsequence of another string.\n\n/// Checks if `sub` is a subsequence of `main`.\n///\n/// # Arguments\n///\n/// * `sub` - A string slice that may be a subsequence.\n/// * `main` - A string slice that is checked against.\n///\n/// # Returns\n///\n/// Returns `true` if `sub` is a subsequence of `main`, otherwise returns `false`.\npub fn is_subsequence(sub: &str, main: &str) -> bool {\n    let mut sub_iter = sub.chars().peekable();\n    let mut main_iter = main.chars();\n\n    while let Some(&sub_char) = sub_iter.peek() {\n        match main_iter.next() {\n            Some(main_char) if main_char == sub_char => {\n                sub_iter.next();\n            }\n            None => return false,\n            _ => {}\n        }\n    }\n\n    true\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! subsequence_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (sub, main, expected) = $test_case;\n                    assert_eq!(is_subsequence(sub, main), expected);\n                }\n            )*\n        };\n    }\n\n    subsequence_tests! {\n        test_empty_subsequence: (\"\", \"ahbgdc\", true),\n        test_empty_strings: (\"\", \"\", true),\n        test_non_empty_sub_empty_main: (\"abc\", \"\", false),\n        test_subsequence_found: (\"abc\", \"ahbgdc\", true),\n        test_subsequence_not_found: (\"axc\", \"ahbgdc\", false),\n        test_longer_sub: (\"abcd\", \"abc\", false),\n        test_single_character_match: (\"a\", \"ahbgdc\", true),\n        test_single_character_not_match: (\"x\", \"ahbgdc\", false),\n        test_subsequence_at_start: (\"abc\", \"abchello\", true),\n        test_subsequence_at_end: (\"cde\", \"abcde\", true),\n        test_same_characters: (\"aaa\", \"aaaaa\", true),\n        test_interspersed_subsequence: (\"ace\", \"abcde\", true),\n        test_different_chars_in_subsequence: (\"aceg\", \"abcdef\", false),\n        test_single_character_in_main_not_match: (\"a\", \"b\", false),\n        test_single_character_in_main_match: (\"b\", \"b\", true),\n        test_subsequence_with_special_chars: (\"a1!c\", \"a1!bcd\", true),\n        test_case_sensitive: (\"aBc\", \"abc\", false),\n        test_subsequence_with_whitespace: (\"hello world\", \"h e l l o   w o r l d\", true),\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/knapsack.rs",
    "content": "//! This module provides functionality to solve the knapsack problem using dynamic programming.\n//! It includes structures for items and solutions, and functions to compute the optimal solution.\n\nuse std::cmp::Ordering;\n\n/// Represents an item with a weight and a value.\n#[derive(Debug, PartialEq, Eq)]\npub struct Item {\n    weight: usize,\n    value: usize,\n}\n\n/// Represents the solution to the knapsack problem.\n#[derive(Debug, PartialEq, Eq)]\npub struct KnapsackSolution {\n    /// The optimal profit obtained.\n    optimal_profit: usize,\n    /// The total weight of items included in the solution.\n    total_weight: usize,\n    /// The indices of items included in the solution. Indices might not be unique.\n    item_indices: Vec<usize>,\n}\n\n/// Solves the knapsack problem and returns the optimal profit, total weight, and indices of items included.\n///\n/// # Arguments:\n/// * `capacity` - The maximum weight capacity of the knapsack.\n/// * `items` - A vector of `Item` structs, each representing an item with weight and value.\n///\n/// # Returns:\n/// A `KnapsackSolution` struct containing:\n/// - `optimal_profit` - The maximum profit achievable with the given capacity and items.\n/// - `total_weight` - The total weight of items included in the solution.\n/// - `item_indices` - Indices of items included in the solution. Indices might not be unique.\n///\n/// # Note:\n/// The indices of items in the solution might not be unique.\n/// This function assumes that `items` is non-empty.\n///\n/// # Complexity:\n/// - Time complexity: O(num_items * capacity)\n/// - Space complexity: O(num_items * capacity)\n///\n/// where `num_items` is the number of items and `capacity` is the knapsack capacity.\npub fn knapsack(capacity: usize, items: Vec<Item>) -> KnapsackSolution {\n    let num_items = items.len();\n    let item_weights: Vec<usize> = items.iter().map(|item| item.weight).collect();\n    let item_values: Vec<usize> = items.iter().map(|item| item.value).collect();\n\n    let knapsack_matrix = generate_knapsack_matrix(capacity, &item_weights, &item_values);\n    let items_included =\n        retrieve_knapsack_items(&item_weights, &knapsack_matrix, num_items, capacity);\n\n    let total_weight = items_included\n        .iter()\n        .map(|&index| item_weights[index - 1])\n        .sum();\n\n    KnapsackSolution {\n        optimal_profit: knapsack_matrix[num_items][capacity],\n        total_weight,\n        item_indices: items_included,\n    }\n}\n\n/// Generates the knapsack matrix (`num_items`, `capacity`) with maximum values.\n///\n/// # Arguments:\n///   * `capacity` - knapsack capacity\n///   * `item_weights` - weights of each item\n///   * `item_values` - values of each item\nfn generate_knapsack_matrix(\n    capacity: usize,\n    item_weights: &[usize],\n    item_values: &[usize],\n) -> Vec<Vec<usize>> {\n    let num_items = item_weights.len();\n\n    (0..=num_items).fold(\n        vec![vec![0; capacity + 1]; num_items + 1],\n        |mut matrix, item_index| {\n            (0..=capacity).for_each(|current_capacity| {\n                matrix[item_index][current_capacity] = if item_index == 0 || current_capacity == 0 {\n                    0\n                } else if item_weights[item_index - 1] <= current_capacity {\n                    usize::max(\n                        item_values[item_index - 1]\n                            + matrix[item_index - 1]\n                                [current_capacity - item_weights[item_index - 1]],\n                        matrix[item_index - 1][current_capacity],\n                    )\n                } else {\n                    matrix[item_index - 1][current_capacity]\n                };\n            });\n            matrix\n        },\n    )\n}\n\n/// Retrieves the indices of items included in the optimal knapsack solution.\n///\n/// # Arguments:\n///   * `item_weights` - weights of each item\n///   * `knapsack_matrix` - knapsack matrix with maximum values\n///   * `item_index` - number of items to consider (initially the total number of items)\n///   * `remaining_capacity` - remaining capacity of the knapsack\n///\n/// # Returns\n/// A vector of item indices included in the optimal solution. The indices might not be unique.\nfn retrieve_knapsack_items(\n    item_weights: &[usize],\n    knapsack_matrix: &[Vec<usize>],\n    item_index: usize,\n    remaining_capacity: usize,\n) -> Vec<usize> {\n    match item_index {\n        0 => vec![],\n        _ => {\n            let current_value = knapsack_matrix[item_index][remaining_capacity];\n            let previous_value = knapsack_matrix[item_index - 1][remaining_capacity];\n\n            match current_value.cmp(&previous_value) {\n                Ordering::Greater => {\n                    let mut knap = retrieve_knapsack_items(\n                        item_weights,\n                        knapsack_matrix,\n                        item_index - 1,\n                        remaining_capacity - item_weights[item_index - 1],\n                    );\n                    knap.push(item_index);\n                    knap\n                }\n                Ordering::Equal | Ordering::Less => retrieve_knapsack_items(\n                    item_weights,\n                    knapsack_matrix,\n                    item_index - 1,\n                    remaining_capacity,\n                ),\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! knapsack_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (capacity, items, expected) = $test_case;\n                    assert_eq!(expected, knapsack(capacity, items));\n                }\n            )*\n        }\n    }\n\n    knapsack_tests! {\n        test_basic_knapsack_small: (\n            165,\n            vec![\n                Item { weight: 23, value: 92 },\n                Item { weight: 31, value: 57 },\n                Item { weight: 29, value: 49 },\n                Item { weight: 44, value: 68 },\n                Item { weight: 53, value: 60 },\n                Item { weight: 38, value: 43 },\n                Item { weight: 63, value: 67 },\n                Item { weight: 85, value: 84 },\n                Item { weight: 89, value: 87 },\n                Item { weight: 82, value: 72 }\n            ],\n            KnapsackSolution {\n                optimal_profit: 309,\n                total_weight: 165,\n                item_indices: vec![1, 2, 3, 4, 6]\n            }\n        ),\n        test_basic_knapsack_tiny: (\n            26,\n            vec![\n                Item { weight: 12, value: 24 },\n                Item { weight: 7, value: 13 },\n                Item { weight: 11, value: 23 },\n                Item { weight: 8, value: 15 },\n                Item { weight: 9, value: 16 }\n            ],\n            KnapsackSolution {\n                optimal_profit: 51,\n                total_weight: 26,\n                item_indices: vec![2, 3, 4]\n            }\n        ),\n        test_basic_knapsack_medium: (\n            190,\n            vec![\n                Item { weight: 56, value: 50 },\n                Item { weight: 59, value: 50 },\n                Item { weight: 80, value: 64 },\n                Item { weight: 64, value: 46 },\n                Item { weight: 75, value: 50 },\n                Item { weight: 17, value: 5 }\n            ],\n            KnapsackSolution {\n                optimal_profit: 150,\n                total_weight: 190,\n                item_indices: vec![1, 2, 5]\n            }\n        ),\n        test_diverse_weights_values_small: (\n            50,\n            vec![\n                Item { weight: 31, value: 70 },\n                Item { weight: 10, value: 20 },\n                Item { weight: 20, value: 39 },\n                Item { weight: 19, value: 37 },\n                Item { weight: 4, value: 7 },\n                Item { weight: 3, value: 5 },\n                Item { weight: 6, value: 10 }\n            ],\n            KnapsackSolution {\n                optimal_profit: 107,\n                total_weight: 50,\n                item_indices: vec![1, 4]\n            }\n        ),\n        test_diverse_weights_values_medium: (\n            104,\n            vec![\n                Item { weight: 25, value: 350 },\n                Item { weight: 35, value: 400 },\n                Item { weight: 45, value: 450 },\n                Item { weight: 5, value: 20 },\n                Item { weight: 25, value: 70 },\n                Item { weight: 3, value: 8 },\n                Item { weight: 2, value: 5 },\n                Item { weight: 2, value: 5 }\n            ],\n            KnapsackSolution {\n                optimal_profit: 900,\n                total_weight: 104,\n                item_indices: vec![1, 3, 4, 5, 7, 8]\n            }\n        ),\n        test_high_value_items: (\n            170,\n            vec![\n                Item { weight: 41, value: 442 },\n                Item { weight: 50, value: 525 },\n                Item { weight: 49, value: 511 },\n                Item { weight: 59, value: 593 },\n                Item { weight: 55, value: 546 },\n                Item { weight: 57, value: 564 },\n                Item { weight: 60, value: 617 }\n            ],\n            KnapsackSolution {\n                optimal_profit: 1735,\n                total_weight: 169,\n                item_indices: vec![2, 4, 7]\n            }\n        ),\n        test_large_knapsack: (\n            750,\n            vec![\n                Item { weight: 70, value: 135 },\n                Item { weight: 73, value: 139 },\n                Item { weight: 77, value: 149 },\n                Item { weight: 80, value: 150 },\n                Item { weight: 82, value: 156 },\n                Item { weight: 87, value: 163 },\n                Item { weight: 90, value: 173 },\n                Item { weight: 94, value: 184 },\n                Item { weight: 98, value: 192 },\n                Item { weight: 106, value: 201 },\n                Item { weight: 110, value: 210 },\n                Item { weight: 113, value: 214 },\n                Item { weight: 115, value: 221 },\n                Item { weight: 118, value: 229 },\n                Item { weight: 120, value: 240 }\n            ],\n            KnapsackSolution {\n                optimal_profit: 1458,\n                total_weight: 749,\n                item_indices: vec![1, 3, 5, 7, 8, 9, 14, 15]\n            }\n        ),\n        test_zero_capacity: (\n            0,\n            vec![\n                Item { weight: 1, value: 1 },\n                Item { weight: 2, value: 2 },\n                Item { weight: 3, value: 3 }\n            ],\n            KnapsackSolution {\n                optimal_profit: 0,\n                total_weight: 0,\n                item_indices: vec![]\n            }\n        ),\n        test_very_small_capacity: (\n            1,\n            vec![\n                Item { weight: 10, value: 1 },\n                Item { weight: 20, value: 2 },\n                Item { weight: 30, value: 3 }\n            ],\n            KnapsackSolution {\n                optimal_profit: 0,\n                total_weight: 0,\n                item_indices: vec![]\n            }\n        ),\n        test_no_items: (\n            1,\n            vec![],\n            KnapsackSolution {\n                optimal_profit: 0,\n                total_weight: 0,\n                item_indices: vec![]\n            }\n        ),\n        test_item_too_heavy: (\n            1,\n            vec![\n                Item { weight: 2, value: 100 }\n            ],\n            KnapsackSolution {\n                optimal_profit: 0,\n                total_weight: 0,\n                item_indices: vec![]\n            }\n        ),\n        test_greedy_algorithm_does_not_work: (\n            10,\n            vec![\n                Item { weight: 10, value: 15 },\n                Item { weight: 6, value: 7 },\n                Item { weight: 4, value: 9 }\n            ],\n            KnapsackSolution {\n                optimal_profit: 16,\n                total_weight: 10,\n                item_indices: vec![2, 3]\n            }\n        ),\n        test_greedy_algorithm_does_not_work_weight_smaller_than_capacity: (\n            10,\n            vec![\n                Item { weight: 10, value: 15 },\n                Item { weight: 1, value: 9 },\n                Item { weight: 2, value: 7 }\n            ],\n            KnapsackSolution {\n                optimal_profit: 16,\n                total_weight: 3,\n                item_indices: vec![2, 3]\n            }\n        ),\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/longest_common_subsequence.rs",
    "content": "//! This module implements the Longest Common Subsequence (LCS) algorithm.\n//! The LCS problem is finding the longest subsequence common to two sequences.\n//! It differs from the problem of finding common substrings: unlike substrings, subsequences\n//! are not required to occupy consecutive positions within the original sequences.\n//! This implementation handles Unicode strings efficiently and correctly, ensuring\n//! that multi-byte characters are managed properly.\n\n/// Computes the longest common subsequence of two input strings.\n///\n/// The longest common subsequence (LCS) of two strings is the longest sequence that can\n/// be derived from both strings by deleting some elements without changing the order of\n/// the remaining elements.\n///\n/// ## Note\n/// The function may return different LCSs for the same pair of strings depending on the\n/// order of the inputs and the nature of the sequences. This is due to the way the dynamic\n/// programming algorithm resolves ties when multiple common subsequences of the same length\n/// exist. The order of the input strings can influence the specific path taken through the\n/// DP table, resulting in different valid LCS outputs.\n///\n///  For example:\n/// `longest_common_subsequence(\"hello, world!\", \"world, hello!\")` returns `\"hello!\"`\n/// but\n/// `longest_common_subsequence(\"world, hello!\", \"hello, world!\")` returns `\"world!\"`\n///\n/// This difference arises because the dynamic programming table is filled differently based\n/// on the input order, leading to different tie-breaking decisions and thus different LCS results.\npub fn longest_common_subsequence(first_seq: &str, second_seq: &str) -> String {\n    let first_seq_chars = first_seq.chars().collect::<Vec<char>>();\n    let second_seq_chars = second_seq.chars().collect::<Vec<char>>();\n\n    let lcs_lengths = initialize_lcs_lengths(&first_seq_chars, &second_seq_chars);\n    let lcs_chars = reconstruct_lcs(&first_seq_chars, &second_seq_chars, &lcs_lengths);\n\n    lcs_chars.into_iter().collect()\n}\n\nfn initialize_lcs_lengths(first_seq_chars: &[char], second_seq_chars: &[char]) -> Vec<Vec<usize>> {\n    let first_seq_len = first_seq_chars.len();\n    let second_seq_len = second_seq_chars.len();\n\n    let mut lcs_lengths = vec![vec![0; second_seq_len + 1]; first_seq_len + 1];\n\n    // Populate the LCS lengths table\n    (1..=first_seq_len).for_each(|i| {\n        (1..=second_seq_len).for_each(|j| {\n            lcs_lengths[i][j] = if first_seq_chars[i - 1] == second_seq_chars[j - 1] {\n                lcs_lengths[i - 1][j - 1] + 1\n            } else {\n                lcs_lengths[i - 1][j].max(lcs_lengths[i][j - 1])\n            };\n        });\n    });\n\n    lcs_lengths\n}\n\nfn reconstruct_lcs(\n    first_seq_chars: &[char],\n    second_seq_chars: &[char],\n    lcs_lengths: &[Vec<usize>],\n) -> Vec<char> {\n    let mut lcs_chars = Vec::new();\n    let mut i = first_seq_chars.len();\n    let mut j = second_seq_chars.len();\n    while i > 0 && j > 0 {\n        if first_seq_chars[i - 1] == second_seq_chars[j - 1] {\n            lcs_chars.push(first_seq_chars[i - 1]);\n            i -= 1;\n            j -= 1;\n        } else if lcs_lengths[i - 1][j] >= lcs_lengths[i][j - 1] {\n            i -= 1;\n        } else {\n            j -= 1;\n        }\n    }\n\n    lcs_chars.reverse();\n    lcs_chars\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! longest_common_subsequence_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (first_seq, second_seq, expected_lcs) = $test_case;\n                    assert_eq!(longest_common_subsequence(&first_seq, &second_seq), expected_lcs);\n                }\n            )*\n        };\n    }\n\n    longest_common_subsequence_tests! {\n        empty_case: (\"\", \"\", \"\"),\n        one_empty: (\"\", \"abcd\", \"\"),\n        identical_strings: (\"abcd\", \"abcd\", \"abcd\"),\n        completely_different: (\"abcd\", \"efgh\", \"\"),\n        single_character: (\"a\", \"a\", \"a\"),\n        different_length: (\"abcd\", \"abc\", \"abc\"),\n        special_characters: (\"$#%&\", \"#@!%\", \"#%\"),\n        long_strings: (\"abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh\",\n                      \"bcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgha\",\n                      \"bcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh\"),\n        unicode_characters: (\"你好，世界\", \"再见，世界\", \"，世界\"),\n        spaces_and_punctuation_0: (\"hello, world!\", \"world, hello!\", \"hello!\"),\n        spaces_and_punctuation_1: (\"hello, world!\", \"world, hello!\", \"hello!\"), // longest_common_subsequence is not symmetric\n        random_case_1: (\"abcdef\", \"xbcxxxe\", \"bce\"),\n        random_case_2: (\"xyz\", \"abc\", \"\"),\n        random_case_3: (\"abracadabra\", \"avadakedavra\", \"aaadara\"),\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/longest_common_substring.rs",
    "content": "//! This module provides a function to find the length of the longest common substring\n//! between two strings using dynamic programming.\n\n/// Finds the length of the longest common substring between two strings using dynamic programming.\n///\n/// The algorithm uses a 2D dynamic programming table where each cell represents\n/// the length of the longest common substring ending at the corresponding indices in\n/// the two input strings. The maximum value in the DP table is the result, i.e., the\n/// length of the longest common substring.\n///\n/// The time complexity is `O(n * m)`, where `n` and `m` are the lengths of the two strings.\n/// # Arguments\n///\n/// * `s1` - The first input string.\n/// * `s2` - The second input string.\n///\n/// # Returns\n///\n/// Returns the length of the longest common substring between `s1` and `s2`.\npub fn longest_common_substring(s1: &str, s2: &str) -> usize {\n    let mut substr_len = vec![vec![0; s2.len() + 1]; s1.len() + 1];\n    let mut max_len = 0;\n\n    s1.as_bytes().iter().enumerate().for_each(|(i, &c1)| {\n        s2.as_bytes().iter().enumerate().for_each(|(j, &c2)| {\n            if c1 == c2 {\n                substr_len[i + 1][j + 1] = substr_len[i][j] + 1;\n                max_len = max_len.max(substr_len[i + 1][j + 1]);\n            }\n        });\n    });\n\n    max_len\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_longest_common_substring {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (s1, s2, expected) = $inputs;\n                    assert_eq!(longest_common_substring(s1, s2), expected);\n                    assert_eq!(longest_common_substring(s2, s1), expected);\n                }\n            )*\n        }\n    }\n\n    test_longest_common_substring! {\n        test_empty_strings: (\"\", \"\", 0),\n        test_one_empty_string: (\"\", \"a\", 0),\n        test_identical_single_char: (\"a\", \"a\", 1),\n        test_different_single_char: (\"a\", \"b\", 0),\n        test_common_substring_at_start: (\"abcdef\", \"abc\", 3),\n        test_common_substring_at_middle: (\"abcdef\", \"bcd\", 3),\n        test_common_substring_at_end: (\"abcdef\", \"def\", 3),\n        test_no_common_substring: (\"abc\", \"xyz\", 0),\n        test_overlapping_substrings: (\"abcdxyz\", \"xyzabcd\", 4),\n        test_special_characters: (\"@abc#def$\", \"#def@\", 4),\n        test_case_sensitive: (\"abcDEF\", \"ABCdef\", 0),\n        test_full_string_match: (\"GeeksforGeeks\", \"GeeksforGeeks\", 13),\n        test_substring_with_repeated_chars: (\"aaaaaaaaaaaaa\", \"aaa\", 3),\n        test_longer_strings_with_common_substring: (\"OldSite:GeeksforGeeks.org\", \"NewSite:GeeksQuiz.com\", 10),\n        test_no_common_substring_with_special_chars: (\"!!!\", \"???\", 0),\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/longest_continuous_increasing_subsequence.rs",
    "content": "use std::cmp::Ordering;\n\n/// Finds the longest continuous increasing subsequence in a slice.\n///\n/// Given a slice of elements, this function returns a slice representing\n/// the longest continuous subsequence where each element is strictly\n/// less than the following element.\n///\n/// # Arguments\n///\n/// * `arr` - A reference to a slice of elements\n///\n/// # Returns\n///\n/// A subslice of the input, representing the longest continuous increasing subsequence.\n/// If there are multiple subsequences of the same length, the function returns the first one found.\npub fn longest_continuous_increasing_subsequence<T: Ord>(arr: &[T]) -> &[T] {\n    if arr.len() <= 1 {\n        return arr;\n    }\n\n    let mut start = 0;\n    let mut max_start = 0;\n    let mut max_len = 1;\n    let mut curr_len = 1;\n\n    for i in 1..arr.len() {\n        match arr[i - 1].cmp(&arr[i]) {\n            // include current element is greater than or equal to the previous\n            // one elements in the current increasing sequence\n            Ordering::Less | Ordering::Equal => {\n                curr_len += 1;\n            }\n            // reset when a strictly decreasing element is found\n            Ordering::Greater => {\n                if curr_len > max_len {\n                    max_len = curr_len;\n                    max_start = start;\n                }\n                // reset start to the current position\n                start = i;\n                // reset current length\n                curr_len = 1;\n            }\n        }\n    }\n\n    // final check for the last sequence\n    if curr_len > max_len {\n        max_len = curr_len;\n        max_start = start;\n    }\n\n    &arr[max_start..max_start + max_len]\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_cases {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $test_case;\n                    assert_eq!(longest_continuous_increasing_subsequence(input), expected);\n                }\n            )*\n        };\n    }\n\n    test_cases! {\n        empty_array: (&[] as &[isize], &[] as &[isize]),\n        single_element: (&[1], &[1]),\n        all_increasing: (&[1, 2, 3, 4, 5], &[1, 2, 3, 4, 5]),\n        all_decreasing: (&[5, 4, 3, 2, 1], &[5]),\n        with_equal_elements: (&[1, 2, 2, 3, 4, 2], &[1, 2, 2, 3, 4]),\n        increasing_with_plateau: (&[1, 2, 2, 2, 3, 3, 4], &[1, 2, 2, 2, 3, 3, 4]),\n        mixed_elements: (&[5, 4, 3, 4, 2, 1], &[3, 4]),\n        alternating_increase_decrease: (&[1, 2, 1, 2, 1, 2], &[1, 2]),\n        zigzag: (&[1, 3, 2, 4, 3, 5], &[1, 3]),\n        single_negative_element: (&[-1], &[-1]),\n        negative_and_positive_mixed: (&[-2, -1, 0, 1, 2, 3], &[-2, -1, 0, 1, 2, 3]),\n        increasing_then_decreasing: (&[1, 2, 3, 4, 3, 2, 1], &[1, 2, 3, 4]),\n        single_increasing_subsequence_later: (&[3, 2, 1, 1, 2, 3, 4], &[1, 1, 2, 3, 4]),\n        longer_subsequence_at_start: (&[5, 6, 7, 8, 9, 2, 3, 4, 5], &[5, 6, 7, 8, 9]),\n        longer_subsequence_at_end: (&[2, 3, 4, 10, 5, 6, 7, 8, 9], &[5, 6, 7, 8, 9]),\n        longest_subsequence_at_start: (&[2, 3, 4, 5, 1, 0], &[2, 3, 4, 5]),\n        longest_subsequence_at_end: (&[1, 7, 2, 3, 4, 5,], &[2, 3, 4, 5]),\n        repeated_elements: (&[1, 1, 1, 1, 1], &[1, 1, 1, 1, 1]),\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/longest_increasing_subsequence.rs",
    "content": "/// Finds the longest increasing subsequence and returns it.\n///\n/// If multiple subsequences with the longest possible subsequence length can be found, the\n/// subsequence which appeared first will be returned (see `test_example_1`).\n///\n/// Inspired by [this LeetCode problem](https://leetcode.com/problems/longest-increasing-subsequence/).\npub fn longest_increasing_subsequence<T: Ord + Clone>(input_array: &[T]) -> Vec<T> {\n    let n = input_array.len();\n    if n <= 1 {\n        return input_array.to_vec();\n    }\n\n    let mut increasing_sequence: Vec<(T, usize)> = Vec::new();\n    let mut previous = vec![0_usize; n];\n\n    increasing_sequence.push((input_array[0].clone(), 1));\n    for i in 1..n {\n        let value = input_array[i].clone();\n        if value > increasing_sequence.last().unwrap().0 {\n            previous[i] = increasing_sequence.last().unwrap().1 - 1;\n            increasing_sequence.push((value, i + 1));\n            continue;\n        }\n\n        let change_position = increasing_sequence\n            .binary_search(&(value.clone(), 0))\n            .unwrap_or_else(|x| x);\n        increasing_sequence[change_position] = (value, i + 1);\n        previous[i] = match change_position {\n            0 => i,\n            other => increasing_sequence[other - 1].1 - 1,\n        };\n    }\n\n    // Construct subsequence\n    let mut out: Vec<T> = Vec::with_capacity(increasing_sequence.len());\n\n    out.push(increasing_sequence.last().unwrap().0.clone());\n    let mut current_index = increasing_sequence.last().unwrap().1 - 1;\n    while previous[current_index] != current_index {\n        current_index = previous[current_index];\n        out.push(input_array[current_index].clone());\n    }\n\n    out.into_iter().rev().collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::longest_increasing_subsequence;\n\n    #[test]\n    /// Need to specify generic type T in order to function\n    fn test_empty_vec() {\n        assert_eq!(longest_increasing_subsequence::<i32>(&[]), vec![]);\n    }\n\n    #[test]\n    fn test_example_1() {\n        assert_eq!(\n            longest_increasing_subsequence(&[10, 9, 2, 5, 3, 7, 101, 18]),\n            vec![2, 3, 7, 18]\n        );\n    }\n\n    #[test]\n    fn test_example_2() {\n        assert_eq!(\n            longest_increasing_subsequence(&[0, 1, 0, 3, 2, 3]),\n            vec![0, 1, 2, 3]\n        );\n    }\n\n    #[test]\n    fn test_example_3() {\n        assert_eq!(\n            longest_increasing_subsequence(&[7, 7, 7, 7, 7, 7, 7]),\n            vec![7]\n        );\n    }\n\n    #[test]\n    fn test_tle() {\n        let mut input_array = vec![0i64; 1e5 as usize];\n        let mut expected_result: Vec<i64> = Vec::with_capacity(5e4 as usize);\n        for (idx, num) in input_array.iter_mut().enumerate() {\n            match idx % 2 {\n                0 => {\n                    *num = idx as i64;\n                    expected_result.push(*num);\n                }\n                1 => *num = -(idx as i64),\n                _ => unreachable!(),\n            }\n        }\n        expected_result[0] = -1;\n        assert_eq!(\n            longest_increasing_subsequence(&input_array),\n            expected_result\n        );\n        // should be [-1, 2, 4, 6, 8, ...]\n        // the first number is not 0, it would be replaced by -1 before 2 is added\n    }\n\n    #[test]\n    fn test_negative_elements() {\n        assert_eq!(longest_increasing_subsequence(&[-2, -1]), vec![-2, -1]);\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/matrix_chain_multiply.rs",
    "content": "//! This module implements a dynamic programming solution to find the minimum\n//! number of multiplications needed to multiply a chain of matrices with given dimensions.\n//!\n//! The algorithm uses a dynamic programming approach with tabulation to calculate the minimum\n//! number of multiplications required for matrix chain multiplication.\n//!\n//! # Time Complexity\n//!\n//! The algorithm runs in O(n^3) time complexity and O(n^2) space complexity, where n is the\n//! number of matrices.\n\n/// Custom error types for matrix chain multiplication\n#[derive(Debug, PartialEq)]\npub enum MatrixChainMultiplicationError {\n    EmptyDimensions,\n    InsufficientDimensions,\n}\n\n/// Calculates the minimum number of scalar multiplications required to multiply a chain\n/// of matrices with given dimensions.\n///\n/// # Arguments\n///\n/// * `dimensions`: A vector where each element represents the dimensions of consecutive matrices\n///   in the chain. For example, [1, 2, 3, 4] represents matrices of dimensions (1x2), (2x3), and (3x4).\n///\n/// # Returns\n///\n/// The minimum number of scalar multiplications needed to compute the product of the matrices\n/// in the optimal order.\n///\n/// # Errors\n///\n/// Returns an error if the input is invalid (i.e., empty or length less than 2).\npub fn matrix_chain_multiply(\n    dimensions: Vec<usize>,\n) -> Result<usize, MatrixChainMultiplicationError> {\n    if dimensions.is_empty() {\n        return Err(MatrixChainMultiplicationError::EmptyDimensions);\n    }\n\n    if dimensions.len() == 1 {\n        return Err(MatrixChainMultiplicationError::InsufficientDimensions);\n    }\n\n    let mut min_operations = vec![vec![0; dimensions.len()]; dimensions.len()];\n\n    (2..dimensions.len()).for_each(|chain_len| {\n        (0..dimensions.len() - chain_len).for_each(|start| {\n            let end = start + chain_len;\n            min_operations[start][end] = (start + 1..end)\n                .map(|split| {\n                    min_operations[start][split]\n                        + min_operations[split][end]\n                        + dimensions[start] * dimensions[split] * dimensions[end]\n                })\n                .min()\n                .unwrap_or(usize::MAX);\n        });\n    });\n\n    Ok(min_operations[0][dimensions.len() - 1])\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_cases {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $test_case;\n                    assert_eq!(matrix_chain_multiply(input.clone()), expected);\n                    assert_eq!(matrix_chain_multiply(input.into_iter().rev().collect()), expected);\n                }\n            )*\n        };\n    }\n\n    test_cases! {\n        basic_chain_of_matrices: (vec![1, 2, 3, 4], Ok(18)),\n        chain_of_large_matrices: (vec![40, 20, 30, 10, 30], Ok(26000)),\n        long_chain_of_matrices: (vec![1, 2, 3, 4, 3, 5, 7, 6, 10], Ok(182)),\n        complex_chain_of_matrices: (vec![4, 10, 3, 12, 20, 7], Ok(1344)),\n        empty_dimensions_input: (vec![], Err(MatrixChainMultiplicationError::EmptyDimensions)),\n        single_dimensions_input: (vec![10], Err(MatrixChainMultiplicationError::InsufficientDimensions)),\n        single_matrix_input: (vec![10, 20], Ok(0)),\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/maximal_square.rs",
    "content": "use std::cmp::max;\nuse std::cmp::min;\n\n/// Maximal Square\n///\n/// Given an `m` * `n` binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area.\\\n/// <https://leetcode.com/problems/maximal-square/>\n///\n/// # Arguments:\n///   * `matrix` - an array of integer array\n///\n/// # Complexity\n///   - time complexity: O(n^2),\n///   - space complexity: O(n),\npub fn maximal_square(matrix: &mut [Vec<i32>]) -> i32 {\n    if matrix.is_empty() {\n        return 0;\n    }\n\n    let rows = matrix.len();\n    let cols = matrix[0].len();\n    let mut result: i32 = 0;\n\n    for row in 0..rows {\n        for col in 0..cols {\n            if matrix[row][col] == 1 {\n                if row == 0 || col == 0 {\n                    result = max(result, 1);\n                } else {\n                    let temp = min(matrix[row - 1][col - 1], matrix[row - 1][col]);\n\n                    let count: i32 = min(temp, matrix[row][col - 1]) + 1;\n                    result = max(result, count);\n\n                    matrix[row][col] = count;\n                }\n            }\n        }\n    }\n\n    result * result\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test() {\n        assert_eq!(maximal_square(&mut []), 0);\n\n        let mut matrix = vec![vec![0, 1], vec![1, 0]];\n        assert_eq!(maximal_square(&mut matrix), 1);\n\n        let mut matrix = vec![\n            vec![1, 0, 1, 0, 0],\n            vec![1, 0, 1, 1, 1],\n            vec![1, 1, 1, 1, 1],\n            vec![1, 0, 0, 1, 0],\n        ];\n        assert_eq!(maximal_square(&mut matrix), 4);\n\n        let mut matrix = vec![vec![0]];\n        assert_eq!(maximal_square(&mut matrix), 0);\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/maximum_subarray.rs",
    "content": "//! This module provides a function to find the largest sum of the subarray\n//! in a given array of integers using dynamic programming. It also includes\n//! tests to verify the correctness of the implementation.\n\n/// Custom error type for maximum subarray\n#[derive(Debug, PartialEq)]\npub enum MaximumSubarrayError {\n    EmptyArray,\n}\n\n/// Finds the subarray (containing at least one number) which has the largest sum\n/// and returns its sum.\n///\n/// A subarray is a contiguous part of an array.\n///\n/// # Arguments\n///\n/// * `array` - A slice of integers.\n///\n/// # Returns\n///\n/// A `Result` which is:\n/// * `Ok(isize)` representing the largest sum of a contiguous subarray.\n/// * `Err(MaximumSubarrayError)` if the array is empty.\n///\n/// # Complexity\n///\n/// * Time complexity: `O(array.len())`\n/// * Space complexity: `O(1)`\npub fn maximum_subarray(array: &[isize]) -> Result<isize, MaximumSubarrayError> {\n    if array.is_empty() {\n        return Err(MaximumSubarrayError::EmptyArray);\n    }\n\n    let mut cur_sum = array[0];\n    let mut max_sum = cur_sum;\n\n    for &x in &array[1..] {\n        cur_sum = (cur_sum + x).max(x);\n        max_sum = max_sum.max(cur_sum);\n    }\n\n    Ok(max_sum)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! maximum_subarray_tests {\n        ($($name:ident: $tc:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (array, expected) = $tc;\n                    assert_eq!(maximum_subarray(&array), expected);\n                }\n            )*\n        }\n    }\n\n    maximum_subarray_tests! {\n        test_all_non_negative: (vec![1, 0, 5, 8], Ok(14)),\n        test_all_negative: (vec![-3, -1, -8, -2], Ok(-1)),\n        test_mixed_negative_and_positive: (vec![-4, 3, -2, 5, -8], Ok(6)),\n        test_single_element_positive: (vec![6], Ok(6)),\n        test_single_element_negative: (vec![-6], Ok(-6)),\n        test_mixed_elements: (vec![-2, 1, -3, 4, -1, 2, 1, -5, 4], Ok(6)),\n        test_empty_array: (vec![], Err(MaximumSubarrayError::EmptyArray)),\n        test_all_zeroes: (vec![0, 0, 0, 0], Ok(0)),\n        test_single_zero: (vec![0], Ok(0)),\n        test_alternating_signs: (vec![3, -2, 5, -1], Ok(6)),\n        test_all_negatives_with_one_positive: (vec![-3, -4, 1, -7, -2], Ok(1)),\n        test_all_positives_with_one_negative: (vec![3, 4, -1, 7, 2], Ok(15)),\n        test_all_positives: (vec![2, 3, 1, 5], Ok(11)),\n        test_large_values: (vec![1000, -500, 1000, -500, 1000], Ok(2000)),\n        test_large_array: ((0..1000).collect::<Vec<_>>(), Ok(499500)),\n        test_large_negative_array: ((0..1000).map(|x| -x).collect::<Vec<_>>(), Ok(0)),\n        test_single_large_positive: (vec![1000000], Ok(1000000)),\n        test_single_large_negative: (vec![-1000000], Ok(-1000000)),\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/minimum_cost_path.rs",
    "content": "use std::cmp::min;\n\n/// Represents possible errors that can occur when calculating the minimum cost path in a matrix.\n#[derive(Debug, PartialEq, Eq)]\npub enum MatrixError {\n    /// Error indicating that the matrix is empty or has empty rows.\n    EmptyMatrix,\n    /// Error indicating that the matrix is not rectangular in shape.\n    NonRectangularMatrix,\n}\n\n/// Computes the minimum cost path from the top-left to the bottom-right\n/// corner of a matrix, where movement is restricted to right and down directions.\n///\n/// # Arguments\n///\n/// * `matrix` - A 2D vector of positive integers, where each element represents\n///              the cost to step on that cell.\n///\n/// # Returns\n///\n/// * `Ok(usize)` - The minimum path cost to reach the bottom-right corner from\n///   the top-left corner of the matrix.\n/// * `Err(MatrixError)` - An error if the matrix is empty or improperly formatted.\n///\n/// # Complexity\n///\n/// * Time complexity: `O(m * n)`, where `m` is the number of rows\n///   and `n` is the number of columns in the input matrix.\n/// * Space complexity: `O(n)`, as only a single row of cumulative costs\n///   is stored at any time.\npub fn minimum_cost_path(matrix: Vec<Vec<usize>>) -> Result<usize, MatrixError> {\n    // Check if the matrix is rectangular\n    if !matrix.iter().all(|row| row.len() == matrix[0].len()) {\n        return Err(MatrixError::NonRectangularMatrix);\n    }\n\n    // Check if the matrix is empty or contains empty rows\n    if matrix.is_empty() || matrix.iter().all(|row| row.is_empty()) {\n        return Err(MatrixError::EmptyMatrix);\n    }\n\n    // Initialize the first row of the cost vector\n    let mut cost = matrix[0]\n        .iter()\n        .scan(0, |acc, &val| {\n            *acc += val;\n            Some(*acc)\n        })\n        .collect::<Vec<_>>();\n\n    // Process each row from the second to the last\n    for row in matrix.iter().skip(1) {\n        // Update the first element of cost for this row\n        cost[0] += row[0];\n\n        // Update the rest of the elements in the current row of cost\n        for col in 1..matrix[0].len() {\n            cost[col] = row[col] + min(cost[col - 1], cost[col]);\n        }\n    }\n\n    // The last element in cost contains the minimum path cost to the bottom-right corner\n    Ok(cost[matrix[0].len() - 1])\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! minimum_cost_path_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (matrix, expected) = $test_case;\n                    assert_eq!(minimum_cost_path(matrix), expected);\n                }\n            )*\n        };\n    }\n\n    minimum_cost_path_tests! {\n        basic: (\n            vec![\n                vec![2, 1, 4],\n                vec![2, 1, 3],\n                vec![3, 2, 1]\n            ],\n            Ok(7)\n        ),\n        single_element: (\n            vec![\n                vec![5]\n            ],\n            Ok(5)\n        ),\n        single_row: (\n            vec![\n                vec![1, 3, 2, 1, 5]\n            ],\n            Ok(12)\n        ),\n        single_column: (\n            vec![\n                vec![1],\n                vec![3],\n                vec![2],\n                vec![1],\n                vec![5]\n            ],\n            Ok(12)\n        ),\n        large_matrix: (\n            vec![\n                vec![1, 3, 1, 5],\n                vec![2, 1, 4, 2],\n                vec![3, 2, 1, 3],\n                vec![4, 3, 2, 1]\n            ],\n            Ok(10)\n        ),\n        uniform_matrix: (\n            vec![\n                vec![1, 1, 1],\n                vec![1, 1, 1],\n                vec![1, 1, 1]\n            ],\n            Ok(5)\n        ),\n        increasing_values: (\n            vec![\n                vec![1, 2, 3],\n                vec![4, 5, 6],\n                vec![7, 8, 9]\n            ],\n            Ok(21)\n        ),\n        high_cost_path: (\n            vec![\n                vec![1, 100, 1],\n                vec![1, 100, 1],\n                vec![1, 1, 1]\n            ],\n            Ok(5)\n        ),\n        complex_matrix: (\n            vec![\n                vec![5, 9, 6, 8],\n                vec![1, 4, 7, 3],\n                vec![2, 1, 8, 2],\n                vec![3, 6, 9, 4]\n            ],\n            Ok(23)\n        ),\n        empty_matrix: (\n            vec![],\n            Err(MatrixError::EmptyMatrix)\n        ),\n        empty_row: (\n            vec![\n                vec![],\n                vec![],\n                vec![]\n            ],\n            Err(MatrixError::EmptyMatrix)\n        ),\n        non_rectangular: (\n            vec![\n                vec![1, 2, 3],\n                vec![4, 5],\n                vec![6, 7, 8]\n            ],\n            Err(MatrixError::NonRectangularMatrix)\n        ),\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/mod.rs",
    "content": "mod catalan_numbers;\nmod coin_change;\nmod egg_dropping;\nmod fibonacci;\nmod fractional_knapsack;\nmod integer_partition;\nmod is_subsequence;\nmod knapsack;\nmod longest_common_subsequence;\nmod longest_common_substring;\nmod longest_continuous_increasing_subsequence;\nmod longest_increasing_subsequence;\nmod matrix_chain_multiply;\nmod maximal_square;\nmod maximum_subarray;\nmod minimum_cost_path;\nmod optimal_bst;\nmod palindrome_partitioning;\nmod rod_cutting;\nmod smith_waterman;\nmod snail;\nmod subset_generation;\nmod subset_sum;\nmod task_assignment;\nmod trapped_rainwater;\nmod word_break;\n\npub use self::catalan_numbers::catalan_numbers;\npub use self::coin_change::coin_change;\npub use self::egg_dropping::egg_drop;\npub use self::fibonacci::{\n    binary_lifting_fibonacci, classical_fibonacci, fibonacci,\n    last_digit_of_the_sum_of_nth_fibonacci_number, logarithmic_fibonacci, matrix_fibonacci,\n    memoized_fibonacci, nth_fibonacci_number_modulo_m, recursive_fibonacci,\n};\npub use self::fractional_knapsack::fractional_knapsack;\npub use self::integer_partition::partition;\npub use self::is_subsequence::is_subsequence;\npub use self::knapsack::knapsack;\npub use self::longest_common_subsequence::longest_common_subsequence;\npub use self::longest_common_substring::longest_common_substring;\npub use self::longest_continuous_increasing_subsequence::longest_continuous_increasing_subsequence;\npub use self::longest_increasing_subsequence::longest_increasing_subsequence;\npub use self::matrix_chain_multiply::matrix_chain_multiply;\npub use self::maximal_square::maximal_square;\npub use self::maximum_subarray::maximum_subarray;\npub use self::minimum_cost_path::minimum_cost_path;\npub use self::optimal_bst::optimal_search_tree;\npub use self::palindrome_partitioning::minimum_palindrome_partitions;\npub use self::rod_cutting::rod_cut;\npub use self::smith_waterman::{score_function, smith_waterman, traceback};\npub use self::snail::snail;\npub use self::subset_generation::list_subset;\npub use self::subset_sum::is_sum_subset;\npub use self::task_assignment::count_task_assignments;\npub use self::trapped_rainwater::trapped_rainwater;\npub use self::word_break::word_break;\n"
  },
  {
    "path": "src/dynamic_programming/optimal_bst.rs",
    "content": "// Optimal Binary Search Tree Algorithm in Rust\n// Time Complexity: O(n^3) with prefix sum optimization\n// Space Complexity: O(n^2) for the dp table and prefix sum array\n\n/// Constructs an Optimal Binary Search Tree from a list of key frequencies.\n/// The goal is to minimize the expected search cost given key access frequencies.\n///\n/// # Arguments\n/// * `freq` - A slice of integers representing the frequency of key access\n///\n/// # Returns\n/// * An integer representing the minimum cost of the optimal BST\npub fn optimal_search_tree(freq: &[i32]) -> i32 {\n    let n = freq.len();\n    if n == 0 {\n        return 0;\n    }\n\n    // dp[i][j] stores the cost of optimal BST that can be formed from keys[i..=j]\n    let mut dp = vec![vec![0; n]; n];\n\n    // prefix_sum[i] stores sum of freq[0..i]\n    let mut prefix_sum = vec![0; n + 1];\n    for i in 0..n {\n        prefix_sum[i + 1] = prefix_sum[i] + freq[i];\n    }\n\n    // Base case: Trees with only one key\n    for i in 0..n {\n        dp[i][i] = freq[i];\n    }\n\n    // Build chains of increasing length l (from 2 to n)\n    for l in 2..=n {\n        for i in 0..=n - l {\n            let j = i + l - 1;\n            dp[i][j] = i32::MAX;\n\n            // Compute the total frequency sum in the range [i..=j] using prefix sum\n            let fsum = prefix_sum[j + 1] - prefix_sum[i];\n\n            // Try making each key in freq[i..=j] the root of the tree\n            for r in i..=j {\n                // Cost of left subtree\n                let left = if r > i { dp[i][r - 1] } else { 0 };\n                // Cost of right subtree\n                let right = if r < j { dp[r + 1][j] } else { 0 };\n\n                // Total cost = left + right + sum of frequencies (fsum)\n                let cost = left + right + fsum;\n\n                // Choose the minimum among all possible roots\n                if cost < dp[i][j] {\n                    dp[i][j] = cost;\n                }\n            }\n        }\n    }\n\n    // Minimum cost of the optimal BST storing all keys\n    dp[0][n - 1]\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    // Macro to generate multiple test cases for the optimal_search_tree function\n    macro_rules! optimal_bst_tests {\n        ($($name:ident: $input:expr => $expected:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let freq = $input;\n                    assert_eq!(optimal_search_tree(freq), $expected);\n                }\n            )*\n        };\n    }\n\n    optimal_bst_tests! {\n        // Common test cases\n        test_case_1: &[34, 10, 8, 50] => 180,\n        test_case_2: &[10, 12] => 32,\n        test_case_3: &[10, 12, 20] => 72,\n        test_case_4: &[25, 10, 20] => 95,\n        test_case_5: &[4, 2, 6, 3] => 26,\n\n        // Edge test cases\n        test_case_single: &[42] => 42,\n        test_case_empty: &[] => 0,\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/palindrome_partitioning.rs",
    "content": "/// Finds the minimum cuts needed for a palindrome partitioning of a string\n///\n/// Given a string s, partition s such that every substring of the partition is a palindrome.\n/// This function returns the minimum number of cuts needed.\n///\n/// Time Complexity: O(n^2)\n/// Space Complexity: O(n^2)\n///\n/// # Arguments\n///\n/// * `s` - The input string to partition\n///\n/// # Returns\n///\n/// The minimum number of cuts needed\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::dynamic_programming::minimum_palindrome_partitions;\n///\n/// assert_eq!(minimum_palindrome_partitions(\"aab\"), 1);\n/// assert_eq!(minimum_palindrome_partitions(\"aaa\"), 0);\n/// assert_eq!(minimum_palindrome_partitions(\"ababbbabbababa\"), 3);\n/// ```\n///\n/// # Algorithm Explanation\n///\n/// The algorithm uses dynamic programming with two key data structures:\n/// - `cut[i]`: minimum cuts needed for substring from index 0 to i\n/// - `is_palindromic[j][i]`: whether substring from index j to i is a palindrome\n///\n/// For each position i, we check all possible starting positions j to determine\n/// if the substring s[j..=i] is a palindrome. If it is, we update the minimum\n/// cut count accordingly.\n///\n/// Reference: <https://www.youtube.com/watch?v=_H8V5hJUGd0>\npub fn minimum_palindrome_partitions(s: &str) -> usize {\n    let chars: Vec<char> = s.chars().collect();\n    let length = chars.len();\n\n    if length == 0 {\n        return 0;\n    }\n\n    // cut[i] represents the minimum cuts needed for substring from 0 to i\n    let mut cut = vec![0; length];\n\n    // is_palindromic[j][i] represents whether substring from j to i is a palindrome\n    let mut is_palindromic = vec![vec![false; length]; length];\n\n    for i in 0..length {\n        let mut mincut = i;\n\n        for j in 0..=i {\n            // Check if substring from j to i is a palindrome\n            // A substring is a palindrome if:\n            // 1. The characters at both ends match (chars[i] == chars[j])\n            // 2. AND either:\n            //    - The substring length is less than 2 (single char or two same chars)\n            //    - OR the inner substring (j+1 to i-1) is also a palindrome\n            if chars[i] == chars[j] && (i - j < 2 || is_palindromic[j + 1][i - 1]) {\n                is_palindromic[j][i] = true;\n                mincut = if j == 0 {\n                    // If the entire substring from 0 to i is a palindrome, no cuts needed\n                    0\n                } else {\n                    // Otherwise, take minimum of current mincut and (cuts up to j-1) + 1\n                    mincut.min(cut[j - 1] + 1)\n                };\n            }\n        }\n\n        cut[i] = mincut;\n    }\n\n    cut[length - 1]\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_basic_cases() {\n        // \"aab\" -> \"aa\" | \"b\" = 1 cut\n        assert_eq!(minimum_palindrome_partitions(\"aab\"), 1);\n\n        // \"aaa\" is already a palindrome = 0 cuts\n        assert_eq!(minimum_palindrome_partitions(\"aaa\"), 0);\n\n        // Complex case\n        assert_eq!(minimum_palindrome_partitions(\"ababbbabbababa\"), 3);\n    }\n\n    #[test]\n    fn test_edge_cases() {\n        // Empty string\n        assert_eq!(minimum_palindrome_partitions(\"\"), 0);\n\n        // Single character is always a palindrome\n        assert_eq!(minimum_palindrome_partitions(\"a\"), 0);\n\n        // Two different characters need 1 cut\n        assert_eq!(minimum_palindrome_partitions(\"ab\"), 1);\n    }\n\n    #[test]\n    fn test_palindromes() {\n        // Already a palindrome\n        assert_eq!(minimum_palindrome_partitions(\"racecar\"), 0);\n        assert_eq!(minimum_palindrome_partitions(\"noon\"), 0);\n        assert_eq!(minimum_palindrome_partitions(\"abba\"), 0);\n    }\n\n    #[test]\n    fn test_non_palindromes() {\n        // All different characters need n-1 cuts\n        assert_eq!(minimum_palindrome_partitions(\"abcde\"), 4);\n\n        // Two pairs need 1 cut\n        assert_eq!(minimum_palindrome_partitions(\"aabb\"), 1);\n    }\n\n    #[test]\n    fn test_longer_strings() {\n        assert_eq!(minimum_palindrome_partitions(\"aaabaa\"), 1);\n        assert_eq!(minimum_palindrome_partitions(\"abcbm\"), 2);\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/rod_cutting.rs",
    "content": "//! This module provides functions for solving the rod-cutting problem using dynamic programming.\nuse std::cmp::max;\n\n/// Calculates the maximum possible profit from cutting a rod into pieces of varying lengths.\n///\n/// Returns the maximum profit achievable by cutting a rod into pieces such that the profit from each\n/// piece is determined by its length and predefined prices.\n///\n/// # Complexity\n/// - Time complexity: `O(n^2)`\n/// - Space complexity: `O(n)`\n///\n/// where `n` is the number of different rod lengths considered.\npub fn rod_cut(prices: &[usize]) -> usize {\n    if prices.is_empty() {\n        return 0;\n    }\n\n    (1..=prices.len()).fold(vec![0; prices.len() + 1], |mut max_profit, rod_length| {\n        max_profit[rod_length] = (1..=rod_length)\n            .map(|cut_position| prices[cut_position - 1] + max_profit[rod_length - cut_position])\n            .fold(prices[rod_length - 1], |max_price, current_price| {\n                max(max_price, current_price)\n            });\n        max_profit\n    })[prices.len()]\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! rod_cut_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected_output) = $test_case;\n                    assert_eq!(expected_output, rod_cut(input));\n                }\n            )*\n        };\n    }\n\n    rod_cut_tests! {\n        test_empty_prices: (&[], 0),\n        test_example_with_three_prices: (&[5, 8, 2], 15),\n        test_example_with_four_prices: (&[1, 5, 8, 9], 10),\n        test_example_with_five_prices: (&[5, 8, 2, 1, 7], 25),\n        test_all_zeros_except_last: (&[0, 0, 0, 0, 0, 87], 87),\n        test_descending_prices: (&[7, 6, 5, 4, 3, 2, 1], 49),\n        test_varied_prices: (&[1, 5, 8, 9, 10, 17, 17, 20], 22),\n        test_complex_prices: (&[6, 4, 8, 2, 5, 8, 2, 3, 7, 11], 60),\n        test_increasing_prices: (&[1, 5, 8, 9, 10, 17, 17, 20, 24, 30], 30),\n        test_large_range_prices: (&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 12),\n        test_single_length_price: (&[5], 5),\n        test_zero_length_price: (&[0], 0),\n        test_repeated_prices: (&[5, 5, 5, 5], 20),\n        test_no_profit: (&[0, 0, 0, 0], 0),\n        test_large_input: (&[1; 1000], 1000),\n        test_all_zero_input: (&[0; 100], 0),\n        test_very_large_prices: (&[1000000, 2000000, 3000000], 3000000),\n        test_greedy_does_not_work: (&[2, 5, 7, 8], 10),\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/smith_waterman.rs",
    "content": "//! This module contains the Smith-Waterman algorithm implementation for local sequence alignment.\n//!\n//! The Smith-Waterman algorithm is a dynamic programming algorithm used for determining\n//! similar regions between two sequences (nucleotide or protein sequences). It is particularly\n//! useful in bioinformatics for identifying optimal local alignments.\n//!\n//! # Algorithm Overview\n//!\n//! The algorithm works by:\n//! 1. Creating a scoring matrix where each cell represents the maximum alignment score\n//!    ending at that position\n//! 2. Using match, mismatch, and gap penalties to calculate scores\n//! 3. Allowing scores to reset to 0 (ensuring local rather than global alignment)\n//! 4. Tracing back from the highest scoring position to reconstruct the alignment\n//!\n//! # Time Complexity\n//!\n//! O(m * n) where m and n are the lengths of the two sequences\n//!\n//! # Space Complexity\n//!\n//! O(m * n) for the scoring matrix\n//!\n//! # References\n//!\n//! - [Smith, T.F., Waterman, M.S. (1981). \"Identification of Common Molecular Subsequences\"](https://doi.org/10.1016/0022-2836(81)90087-5)\n//! - [Wikipedia: Smith-Waterman algorithm](https://en.wikipedia.org/wiki/Smith%E2%80%93Waterman_algorithm)\n\nuse std::cmp::max;\n\n/// Calculates the score for a character pair based on match, mismatch, or gap scoring.\n///\n/// # Arguments\n///\n/// * `source_char` - Character from the source sequence\n/// * `target_char` - Character from the target sequence\n/// * `match_score` - Score awarded for matching characters (typically positive)\n/// * `mismatch_score` - Score penalty for mismatching characters (typically negative)\n/// * `gap_score` - Score penalty for gaps (typically negative)\n///\n/// # Returns\n///\n/// The calculated score for the character pair\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::dynamic_programming::score_function;\n///\n/// let score = score_function('A', 'A', 1, -1, -2);\n/// assert_eq!(score, 1); // Match\n///\n/// let score = score_function('A', 'C', 1, -1, -2);\n/// assert_eq!(score, -1); // Mismatch\n///\n/// let score = score_function('-', 'A', 1, -1, -2);\n/// assert_eq!(score, -2); // Gap\n/// ```\npub fn score_function(\n    source_char: char,\n    target_char: char,\n    match_score: i32,\n    mismatch_score: i32,\n    gap_score: i32,\n) -> i32 {\n    if source_char == '-' || target_char == '-' {\n        gap_score\n    } else if source_char == target_char {\n        match_score\n    } else {\n        mismatch_score\n    }\n}\n\n/// Performs the Smith-Waterman local sequence alignment algorithm.\n///\n/// This function creates a scoring matrix using dynamic programming to find the\n/// optimal local alignment between two sequences. The algorithm is case-insensitive.\n///\n/// # Arguments\n///\n/// * `query` - The query sequence (e.g., DNA, protein)\n/// * `subject` - The subject sequence to align against\n/// * `match_score` - Score for matching characters (default: 1)\n/// * `mismatch_score` - Penalty for mismatching characters (default: -1)\n/// * `gap_score` - Penalty for gaps/indels (default: -2)\n///\n/// # Returns\n///\n/// A 2D vector representing the dynamic programming scoring matrix\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::dynamic_programming::smith_waterman;\n///\n/// let score_matrix = smith_waterman(\"ACAC\", \"CA\", 1, -1, -2);\n/// assert_eq!(score_matrix.len(), 5); // query length + 1\n/// assert_eq!(score_matrix[0].len(), 3); // subject length + 1\n/// ```\npub fn smith_waterman(\n    query: &str,\n    subject: &str,\n    match_score: i32,\n    mismatch_score: i32,\n    gap_score: i32,\n) -> Vec<Vec<i32>> {\n    let query_upper: Vec<char> = query.to_uppercase().chars().collect();\n    let subject_upper: Vec<char> = subject.to_uppercase().chars().collect();\n\n    let m = query_upper.len();\n    let n = subject_upper.len();\n\n    // Initialize scoring matrix with zeros\n    let mut score = vec![vec![0; n + 1]; m + 1];\n\n    // Fill the scoring matrix using dynamic programming\n    for i in 1..=m {\n        for j in 1..=n {\n            // Calculate score for match/mismatch\n            let match_or_mismatch = score[i - 1][j - 1]\n                + score_function(\n                    query_upper[i - 1],\n                    subject_upper[j - 1],\n                    match_score,\n                    mismatch_score,\n                    gap_score,\n                );\n\n            // Calculate score for deletion (gap in subject)\n            let delete = score[i - 1][j] + gap_score;\n\n            // Calculate score for insertion (gap in query)\n            let insert = score[i][j - 1] + gap_score;\n\n            // Take maximum of all options, but never go below 0 (local alignment)\n            score[i][j] = max(0, max(match_or_mismatch, max(delete, insert)));\n        }\n    }\n\n    score\n}\n\n/// Performs traceback on the Smith-Waterman score matrix to reconstruct the optimal alignment.\n///\n/// This function starts from the highest scoring cell and traces back through the matrix\n/// to reconstruct the aligned sequences. The traceback stops when a cell with score 0\n/// is encountered.\n///\n/// # Arguments\n///\n/// * `score` - The score matrix from the Smith-Waterman algorithm\n/// * `query` - Original query sequence used in alignment\n/// * `subject` - Original subject sequence used in alignment\n/// * `match_score` - Score for matching characters (should match smith_waterman call)\n/// * `mismatch_score` - Score for mismatching characters (should match smith_waterman call)\n/// * `gap_score` - Penalty for gaps (should match smith_waterman call)\n///\n/// # Returns\n///\n/// A String containing the two aligned sequences separated by a newline,\n/// or an empty string if no significant alignment is found\n///\n/// # Examples\n///\n/// ```\n/// use the_algorithms_rust::dynamic_programming::{smith_waterman, traceback};\n///\n/// let score_matrix = smith_waterman(\"ACAC\", \"CA\", 1, -1, -2);\n/// let alignment = traceback(&score_matrix, \"ACAC\", \"CA\", 1, -1, -2);\n/// assert_eq!(alignment, \"CA\\nCA\");\n/// ```\npub fn traceback(\n    score: &[Vec<i32>],\n    query: &str,\n    subject: &str,\n    match_score: i32,\n    mismatch_score: i32,\n    gap_score: i32,\n) -> String {\n    let query_upper: Vec<char> = query.to_uppercase().chars().collect();\n    let subject_upper: Vec<char> = subject.to_uppercase().chars().collect();\n\n    // Find the cell with maximum score\n    let mut max_value = 0;\n    let (mut i_max, mut j_max) = (0, 0);\n\n    for (i, row) in score.iter().enumerate() {\n        for (j, &value) in row.iter().enumerate() {\n            if value > max_value {\n                max_value = value;\n                i_max = i;\n                j_max = j;\n            }\n        }\n    }\n\n    // If no significant alignment found, return empty string\n    if max_value <= 0 {\n        return String::new();\n    }\n\n    // Traceback from the maximum scoring cell\n    let (mut i, mut j) = (i_max, j_max);\n    let mut align1 = Vec::new();\n    let mut align2 = Vec::new();\n\n    // Continue tracing back until we hit a cell with score 0\n    while i > 0 && j > 0 && score[i][j] > 0 {\n        let current_score = score[i][j];\n\n        // Check if we came from diagonal (match/mismatch)\n        if current_score\n            == score[i - 1][j - 1]\n                + score_function(\n                    query_upper[i - 1],\n                    subject_upper[j - 1],\n                    match_score,\n                    mismatch_score,\n                    gap_score,\n                )\n        {\n            align1.push(query_upper[i - 1]);\n            align2.push(subject_upper[j - 1]);\n            i -= 1;\n            j -= 1;\n        }\n        // Check if we came from above (deletion/gap in subject)\n        else if current_score == score[i - 1][j] + gap_score {\n            align1.push(query_upper[i - 1]);\n            align2.push('-');\n            i -= 1;\n        }\n        // Otherwise we came from left (insertion/gap in query)\n        else {\n            align1.push('-');\n            align2.push(subject_upper[j - 1]);\n            j -= 1;\n        }\n    }\n\n    // Reverse the sequences (we built them backwards)\n    align1.reverse();\n    align2.reverse();\n\n    format!(\n        \"{}\\n{}\",\n        align1.into_iter().collect::<String>(),\n        align2.into_iter().collect::<String>()\n    )\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! smith_waterman_tests {\n        ($($name:ident: $test_cases:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (query, subject, match_score, mismatch_score, gap_score, expected) = $test_cases;\n                    assert_eq!(smith_waterman(query, subject, match_score, mismatch_score, gap_score), expected);\n                }\n            )*\n        }\n    }\n\n    macro_rules! traceback_tests {\n        ($($name:ident: $test_cases:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (score, query, subject, match_score, mismatch_score, gap_score, expected) = $test_cases;\n                    assert_eq!(traceback(&score, query, subject, match_score, mismatch_score, gap_score), expected);\n                }\n            )*\n        }\n    }\n\n    smith_waterman_tests! {\n        test_acac_ca: (\"ACAC\", \"CA\", 1, -1, -2, vec![\n            vec![0, 0, 0],\n            vec![0, 0, 1],\n            vec![0, 1, 0],\n            vec![0, 0, 2],\n            vec![0, 1, 0],\n        ]),\n        test_agt_agt: (\"AGT\", \"AGT\", 1, -1, -2, vec![\n            vec![0, 0, 0, 0],\n            vec![0, 1, 0, 0],\n            vec![0, 0, 2, 0],\n            vec![0, 0, 0, 3],\n        ]),\n        test_agt_gta: (\"AGT\", \"GTA\", 1, -1, -2, vec![\n            vec![0, 0, 0, 0],\n            vec![0, 0, 0, 1],\n            vec![0, 1, 0, 0],\n            vec![0, 0, 2, 0],\n        ]),\n        test_agt_g: (\"AGT\", \"G\", 1, -1, -2, vec![\n            vec![0, 0],\n            vec![0, 0],\n            vec![0, 1],\n            vec![0, 0],\n        ]),\n        test_g_agt: (\"G\", \"AGT\", 1, -1, -2, vec![\n            vec![0, 0, 0, 0],\n            vec![0, 0, 1, 0],\n        ]),\n        test_empty_query: (\"\", \"CA\", 1, -1, -2, vec![vec![0, 0, 0]]),\n        test_empty_subject: (\"ACAC\", \"\", 1, -1, -2, vec![vec![0], vec![0], vec![0], vec![0], vec![0]]),\n        test_both_empty: (\"\", \"\", 1, -1, -2, vec![vec![0]]),\n    }\n\n    traceback_tests! {\n        test_traceback_acac_ca: (\n            vec![\n                vec![0, 0, 0],\n                vec![0, 0, 1],\n                vec![0, 1, 0],\n                vec![0, 0, 2],\n                vec![0, 1, 0],\n            ],\n            \"ACAC\",\n            \"CA\",\n            1, -1, -2,\n            \"CA\\nCA\",\n        ),\n        test_traceback_agt_agt: (\n            vec![\n                vec![0, 0, 0, 0],\n                vec![0, 1, 0, 0],\n                vec![0, 0, 2, 0],\n                vec![0, 0, 0, 3],\n            ],\n            \"AGT\",\n            \"AGT\",\n            1, -1, -2,\n            \"AGT\\nAGT\",\n        ),\n        test_traceback_empty: (vec![vec![0, 0, 0]], \"ACAC\", \"\", 1, -1, -2, \"\"),\n        test_traceback_custom_scoring: (\n            vec![\n                vec![0, 0, 0],\n                vec![0, 0, 2],\n                vec![0, 2, 0],\n                vec![0, 0, 4],\n                vec![0, 2, 0],\n            ],\n            \"ACAC\",\n            \"CA\",\n            2, -2, -3,\n            \"CA\\nCA\",\n        ),\n    }\n\n    #[test]\n    fn test_score_function_match() {\n        assert_eq!(score_function('A', 'A', 1, -1, -2), 1);\n        assert_eq!(score_function('G', 'G', 2, -1, -1), 2);\n    }\n\n    #[test]\n    fn test_score_function_mismatch() {\n        assert_eq!(score_function('A', 'C', 1, -1, -2), -1);\n        assert_eq!(score_function('G', 'T', 1, -2, -1), -2);\n    }\n\n    #[test]\n    fn test_score_function_gap() {\n        assert_eq!(score_function('-', 'A', 1, -1, -2), -2);\n        assert_eq!(score_function('A', '-', 1, -1, -2), -2);\n    }\n\n    #[test]\n    fn test_case_insensitive() {\n        let result1 = smith_waterman(\"acac\", \"CA\", 1, -1, -2);\n        let result2 = smith_waterman(\"ACAC\", \"ca\", 1, -1, -2);\n        let result3 = smith_waterman(\"AcAc\", \"Ca\", 1, -1, -2);\n\n        assert_eq!(result1, result2);\n        assert_eq!(result2, result3);\n    }\n\n    #[test]\n    fn test_custom_scoring_end_to_end() {\n        // Test with custom scoring parameters (match=2, mismatch=-2, gap=-3)\n        let query = \"ACGT\";\n        let subject = \"ACGT\";\n        let match_score = 2;\n        let mismatch_score = -2;\n        let gap_score = -3;\n\n        // Generate score matrix with custom parameters\n        let score_matrix = smith_waterman(query, subject, match_score, mismatch_score, gap_score);\n\n        // Traceback using the same custom parameters\n        let alignment = traceback(\n            &score_matrix,\n            query,\n            subject,\n            match_score,\n            mismatch_score,\n            gap_score,\n        );\n\n        // With perfect match and match_score=2, we expect alignment \"ACGT\\nACGT\"\n        assert_eq!(alignment, \"ACGT\\nACGT\");\n\n        // Verify the score is correct (4 matches × 2 = 8)\n        assert_eq!(score_matrix[4][4], 8);\n    }\n\n    #[test]\n    fn test_alignment_at_boundary() {\n        // Test case where optimal alignment might be at row/column 0\n        let query = \"A\";\n        let subject = \"A\";\n        let score_matrix = smith_waterman(query, subject, 1, -1, -2);\n        let alignment = traceback(&score_matrix, query, subject, 1, -1, -2);\n\n        // Should find the alignment even though it's near the boundary\n        assert_eq!(alignment, \"A\\nA\");\n        assert_eq!(score_matrix[1][1], 1);\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/snail.rs",
    "content": "/// ## Spiral Sorting\r\n///\r\n/// Given an n x m array, return the array elements arranged from outermost elements\r\n/// to the middle element, traveling INWARD FROM TOP-LEFT, CLOCKWISE.\r\npub fn snail<T: Copy>(matrix: &[Vec<T>]) -> Vec<T> {\r\n    // break on empty matrix\r\n    if matrix.is_empty() || matrix[0].is_empty() {\r\n        return vec![];\r\n    }\r\n\r\n    let col_count = matrix[0].len();\r\n    let row_count = matrix.len();\r\n\r\n    // Initial maximum/minimum indices\r\n    let mut max_col = col_count - 1;\r\n    let mut min_col = 0;\r\n    let mut max_row = row_count - 1;\r\n    let mut min_row = 0;\r\n\r\n    // Initial direction is Right because\r\n    // we start from the top-left corner of the matrix at indices [0][0]\r\n    let mut dir = Direction::Right;\r\n    let mut row = 0;\r\n    let mut col = 0;\r\n    let mut result = Vec::new();\r\n\r\n    while result.len() < row_count * col_count {\r\n        result.push(matrix[row][col]);\r\n        dir.snail_move(\r\n            &mut col,\r\n            &mut row,\r\n            &mut min_col,\r\n            &mut max_col,\r\n            &mut min_row,\r\n            &mut max_row,\r\n        );\r\n    }\r\n\r\n    result\r\n}\r\n\r\nenum Direction {\r\n    Right,\r\n    Left,\r\n    Down,\r\n    Up,\r\n}\r\n\r\nimpl Direction {\r\n    pub fn snail_move(\r\n        &mut self,\r\n        col: &mut usize,\r\n        row: &mut usize,\r\n        min_col: &mut usize,\r\n        max_col: &mut usize,\r\n        min_row: &mut usize,\r\n        max_row: &mut usize,\r\n    ) {\r\n        match self {\r\n            Self::Right => {\r\n                *col = if *col < *max_col {\r\n                    *col + 1\r\n                } else {\r\n                    *self = Self::Down;\r\n                    *min_row += 1;\r\n                    *row = *min_row;\r\n                    *col\r\n                };\r\n            }\r\n\r\n            Self::Down => {\r\n                *row = if *row < *max_row {\r\n                    *row + 1\r\n                } else {\r\n                    *self = Self::Left;\r\n                    *max_col -= 1;\r\n                    *col = *max_col;\r\n                    *row\r\n                };\r\n            }\r\n\r\n            Self::Left => {\r\n                *col = if *col > usize::MIN && *col > *min_col {\r\n                    *col - 1\r\n                } else {\r\n                    *self = Self::Up;\r\n                    *max_row -= 1;\r\n                    *row = *max_row;\r\n                    *col\r\n                };\r\n            }\r\n\r\n            Self::Up => {\r\n                *row = if *row > usize::MIN && *row > *min_row {\r\n                    *row - 1\r\n                } else {\r\n                    *self = Self::Right;\r\n                    *min_col += 1;\r\n                    *col = *min_col;\r\n                    *row\r\n                };\r\n            }\r\n        };\r\n    }\r\n}\r\n\r\n#[cfg(test)]\r\nmod test {\r\n    use super::*;\r\n\r\n    #[test]\r\n    fn test_empty() {\r\n        let empty: &[Vec<i32>] = &[vec![]];\r\n        assert_eq!(snail(empty), vec![]);\r\n    }\r\n\r\n    #[test]\r\n    fn test_int() {\r\n        let square = &[vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];\r\n        assert_eq!(snail(square), vec![1, 2, 3, 6, 9, 8, 7, 4, 5]);\r\n    }\r\n\r\n    #[test]\r\n    fn test_char() {\r\n        let square = &[\r\n            vec!['S', 'O', 'M'],\r\n            vec!['E', 'T', 'H'],\r\n            vec!['I', 'N', 'G'],\r\n        ];\r\n        assert_eq!(\r\n            snail(square),\r\n            vec!['S', 'O', 'M', 'H', 'G', 'N', 'I', 'E', 'T']\r\n        );\r\n    }\r\n\r\n    #[test]\r\n    fn test_rect() {\r\n        let square = &[\r\n            vec!['H', 'E', 'L', 'L'],\r\n            vec!['O', ' ', 'W', 'O'],\r\n            vec!['R', 'L', 'D', ' '],\r\n        ];\r\n        assert_eq!(\r\n            snail(square),\r\n            vec!['H', 'E', 'L', 'L', 'O', ' ', 'D', 'L', 'R', 'O', ' ', 'W']\r\n        );\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/dynamic_programming/subset_generation.rs",
    "content": "// list all subset combinations of n element in given set of r element.\n// This is a recursive function that collects all subsets of the set of size n\n// with the given set of size r.\npub fn list_subset(\n    set: &[i32],\n    n: usize,\n    r: usize,\n    index: usize,\n    data: &mut [i32],\n    i: usize,\n) -> Vec<Vec<i32>> {\n    let mut res = Vec::new();\n\n    // Current subset is ready to be added to the list\n    if i == r {\n        let mut subset = Vec::new();\n        for j in data.iter().take(r) {\n            subset.push(*j);\n        }\n        res.push(subset);\n        return res;\n    }\n\n    // When no more elements are there to put in data[]\n    if index >= n {\n        return res;\n    }\n\n    // current is included, put next at next location\n    data[i] = set[index];\n    res.append(&mut list_subset(set, n, r, index + 1, data, i + 1));\n\n    // current is excluded, replace it with next (Note that\n    // i+1 is passed, but index is not changed)\n    res.append(&mut list_subset(set, n, r, index + 1, data, i));\n\n    res\n}\n\n// Test module\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_print_subset3() {\n        let set = [1, 2, 3, 4, 5];\n        let n = set.len();\n        const R: usize = 3;\n        let mut data = [0; R];\n\n        let res = list_subset(&set, n, R, 0, &mut data, 0);\n\n        assert_eq!(\n            res,\n            vec![\n                vec![1, 2, 3],\n                vec![1, 2, 4],\n                vec![1, 2, 5],\n                vec![1, 3, 4],\n                vec![1, 3, 5],\n                vec![1, 4, 5],\n                vec![2, 3, 4],\n                vec![2, 3, 5],\n                vec![2, 4, 5],\n                vec![3, 4, 5]\n            ]\n        );\n    }\n\n    #[test]\n    fn test_print_subset4() {\n        let set = [1, 2, 3, 4, 5];\n        let n = set.len();\n        const R: usize = 4;\n        let mut data = [0; R];\n\n        let res = list_subset(&set, n, R, 0, &mut data, 0);\n\n        assert_eq!(\n            res,\n            vec![\n                vec![1, 2, 3, 4],\n                vec![1, 2, 3, 5],\n                vec![1, 2, 4, 5],\n                vec![1, 3, 4, 5],\n                vec![2, 3, 4, 5]\n            ]\n        );\n    }\n\n    #[test]\n    fn test_print_subset5() {\n        let set = [1, 2, 3, 4, 5];\n        let n = set.len();\n        const R: usize = 5;\n        let mut data = [0; R];\n\n        let res = list_subset(&set, n, R, 0, &mut data, 0);\n\n        assert_eq!(res, vec![vec![1, 2, 3, 4, 5]]);\n    }\n\n    #[test]\n    fn test_print_incorrect_subset() {\n        let set = [1, 2, 3, 4, 5];\n        let n = set.len();\n        const R: usize = 6;\n        let mut data = [0; R];\n\n        let res = list_subset(&set, n, R, 0, &mut data, 0);\n\n        let result_set: Vec<Vec<i32>> = Vec::new();\n        assert_eq!(res, result_set);\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/subset_sum.rs",
    "content": "//! This module provides a solution to the subset sum problem using dynamic programming.\n//!\n//! # Complexity\n//! - Time complexity: O(n * sum) where n is array length and sum is the target sum\n//! - Space complexity: O(n * sum) for the DP table\n/// Determines if there exists a subset of the given array that sums to the target value.\n/// Uses dynamic programming to solve the subset sum problem.\n///\n/// # Arguments\n/// * `arr` - A slice of integers representing the input array.\n/// * `required_sum` - The target sum to check for.\n///\n/// # Returns\n/// * `bool` - A boolean indicating whether a subset exists that sums to the target.\npub fn is_sum_subset(arr: &[i32], required_sum: i32) -> bool {\n    let n = arr.len();\n\n    // Handle edge case where required sum is 0 (empty subset always sums to 0)\n    if required_sum == 0 {\n        return true;\n    }\n\n    // Handle edge case where array is empty but required sum is positive\n    if n == 0 && required_sum > 0 {\n        return false;\n    }\n    // dp[i][j] stores whether sum j can be achieved using first i elements\n    let mut dp = vec![vec![false; required_sum as usize + 1]; n + 1];\n    // Base case: sum 0 can always be achieved with any number of elements (empty subset)\n    for i in 0..=n {\n        dp[i][0] = true;\n    }\n    // Base case: with 0 elements, no positive sum can be achieved\n    for j in 1..=required_sum as usize {\n        dp[0][j] = false;\n    }\n    // Fill the DP table\n    for i in 1..=n {\n        for j in 1..=required_sum as usize {\n            if arr[i - 1] > j as i32 {\n                // Current element is too large, exclude it\n                dp[i][j] = dp[i - 1][j];\n            } else {\n                // Either exclude the current element or include it\n                dp[i][j] = dp[i - 1][j] || dp[i - 1][j - arr[i - 1] as usize];\n            }\n        }\n    }\n    dp[n][required_sum as usize]\n}\n#[cfg(test)]\nmod tests {\n    use super::*;\n    // Macro to generate multiple test cases for the is_sum_subset function\n    macro_rules! subset_sum_tests {\n        ($($name:ident: $input:expr => $expected:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (arr, sum) = $input;\n                    assert_eq!(is_sum_subset(arr, sum), $expected);\n                }\n            )*\n        };\n    }\n    subset_sum_tests! {\n        // Common test cases\n        test_case_1: (&[2, 4, 6, 8], 5) => false,\n        test_case_2: (&[2, 4, 6, 8], 14) => true,\n        test_case_3: (&[3, 34, 4, 12, 5, 2], 9) => true,\n        test_case_4: (&[3, 34, 4, 12, 5, 2], 30) => false,\n        test_case_5: (&[1, 2, 3, 4, 5], 15) => true,\n\n        // Edge test cases\n        test_case_empty_array_positive_sum: (&[], 5) => false,\n        test_case_empty_array_zero_sum: (&[], 0) => true,\n        test_case_zero_sum: (&[1, 2, 3], 0) => true,\n        test_case_single_element_match: (&[5], 5) => true,\n        test_case_single_element_no_match: (&[3], 5) => false,\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/task_assignment.rs",
    "content": "// Task Assignment Problem using Bitmasking and DP in Rust\n// Time Complexity: O(2^M * N) where M is number of people and N is number of tasks\n// Space Complexity: O(2^M * N) for the DP table\n\nuse std::collections::HashMap;\n\n/// Solves the task assignment problem where each person can do only certain tasks,\n/// each person can do only one task, and each task is performed by only one person.\n/// Uses bitmasking and dynamic programming to count total number of valid assignments.\n///\n/// # Arguments\n/// * `task_performed` - A vector of vectors where each inner vector contains tasks\n///                      that a person can perform (1-indexed task numbers)\n/// * `total_tasks` - The total number of tasks (N)\n///\n/// # Returns\n/// * The total number of valid task assignments\npub fn count_task_assignments(task_performed: Vec<Vec<usize>>, total_tasks: usize) -> i64 {\n    let num_people = task_performed.len();\n    let dp_size = 1 << num_people;\n\n    // Initialize DP table with -1 (uncomputed)\n    let mut dp = vec![vec![-1; total_tasks + 2]; dp_size];\n\n    let mut task_map = HashMap::new();\n    let final_mask = (1 << num_people) - 1;\n\n    // Build the task -> people mapping\n    for (person, tasks) in task_performed.iter().enumerate() {\n        for &task in tasks {\n            task_map.entry(task).or_insert_with(Vec::new).push(person);\n        }\n    }\n\n    // Recursive DP function\n    fn count_ways_until(\n        dp: &mut Vec<Vec<i64>>,\n        task_map: &HashMap<usize, Vec<usize>>,\n        final_mask: usize,\n        total_tasks: usize,\n        mask: usize,\n        task_no: usize,\n    ) -> i64 {\n        // Base case: all people have been assigned tasks\n        if mask == final_mask {\n            return 1;\n        }\n\n        // Base case: no more tasks available but not all people assigned\n        if task_no > total_tasks {\n            return 0;\n        }\n\n        // Return cached result if already computed\n        if dp[mask][task_no] != -1 {\n            return dp[mask][task_no];\n        }\n\n        // Option 1: Skip the current task\n        let mut total_ways =\n            count_ways_until(dp, task_map, final_mask, total_tasks, mask, task_no + 1);\n\n        // Option 2: Assign current task to a capable person who isn't busy\n        if let Some(people) = task_map.get(&task_no) {\n            for &person in people {\n                // Check if this person is already assigned a task\n                if mask & (1 << person) != 0 {\n                    continue;\n                }\n\n                // Assign task to this person and recurse\n                total_ways += count_ways_until(\n                    dp,\n                    task_map,\n                    final_mask,\n                    total_tasks,\n                    mask | (1 << person),\n                    task_no + 1,\n                );\n            }\n        }\n\n        // Cache the result\n        dp[mask][task_no] = total_ways;\n        total_ways\n    }\n\n    // Start recursion with no people assigned and first task\n    count_ways_until(&mut dp, &task_map, final_mask, total_tasks, 0, 1)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    // Macro to generate multiple test cases for the task assignment function\n    macro_rules! task_assignment_tests {\n        ($($name:ident: $input:expr => $expected:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (task_performed, total_tasks) = $input;\n                    assert_eq!(count_task_assignments(task_performed, total_tasks), $expected);\n                }\n            )*\n        };\n    }\n\n    task_assignment_tests! {\n        test_case_1: (vec![vec![1, 3, 4], vec![1, 2, 5], vec![3, 4]], 5) => 10,\n        test_case_2: (vec![vec![1, 2], vec![1, 2]], 2) => 2,\n        test_case_3: (vec![vec![1], vec![2], vec![3]], 3) => 1,\n        test_case_4: (vec![vec![1, 2, 3], vec![1, 2, 3], vec![1, 2, 3]], 3) => 6,\n        test_case_5: (vec![vec![1], vec![1]], 1) => 0,\n\n        // Edge test case\n        test_case_single_person: (vec![vec![1, 2, 3]], 3) => 3,\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/trapped_rainwater.rs",
    "content": "//! Module to calculate trapped rainwater in an elevation map.\n\n/// Computes the total volume of trapped rainwater in a given elevation map.\n///\n/// # Arguments\n///\n/// * `elevation_map` - A slice containing the heights of the terrain elevations.\n///\n/// # Returns\n///\n/// The total volume of trapped rainwater.\npub fn trapped_rainwater(elevation_map: &[u32]) -> u32 {\n    let left_max = calculate_max_values(elevation_map, false);\n    let right_max = calculate_max_values(elevation_map, true);\n    let mut water_trapped = 0;\n    // Calculate trapped water\n    for i in 0..elevation_map.len() {\n        water_trapped += left_max[i].min(right_max[i]) - elevation_map[i];\n    }\n    water_trapped\n}\n\n/// Determines the maximum heights from either direction in the elevation map.\n///\n/// # Arguments\n///\n/// * `elevation_map` - A slice representing the heights of the terrain elevations.\n/// * `reverse` - A boolean that indicates the direction of calculation.\n///   - `false` for left-to-right.\n///   - `true` for right-to-left.\n///\n/// # Returns\n///\n/// A vector containing the maximum heights encountered up to each position.\nfn calculate_max_values(elevation_map: &[u32], reverse: bool) -> Vec<u32> {\n    let mut max_values = vec![0; elevation_map.len()];\n    let mut current_max = 0;\n    for i in create_iter(elevation_map.len(), reverse) {\n        current_max = current_max.max(elevation_map[i]);\n        max_values[i] = current_max;\n    }\n    max_values\n}\n\n/// Creates an iterator for the given length, optionally reversing it.\n///\n/// # Arguments\n///\n/// * `len` - The length of the iterator.\n/// * `reverse` - A boolean that determines the order of iteration.\n///   - `false` for forward iteration.\n///   - `true` for reverse iteration.\n///\n/// # Returns\n///\n/// A boxed iterator that iterates over the range of indices.\nfn create_iter(len: usize, reverse: bool) -> Box<dyn Iterator<Item = usize>> {\n    if reverse {\n        Box::new((0..len).rev())\n    } else {\n        Box::new(0..len)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! trapped_rainwater_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (elevation_map, expected_trapped_water) = $test_case;\n                    assert_eq!(trapped_rainwater(&elevation_map), expected_trapped_water);\n                    let elevation_map_rev: Vec<u32> = elevation_map.iter().rev().cloned().collect();\n                    assert_eq!(trapped_rainwater(&elevation_map_rev), expected_trapped_water);\n                }\n            )*\n        };\n    }\n\n    trapped_rainwater_tests! {\n        test_trapped_rainwater_basic: (\n            [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1],\n            6\n        ),\n        test_trapped_rainwater_peak_under_water: (\n            [3, 0, 2, 0, 4],\n            7,\n        ),\n        test_bucket: (\n            [5, 1, 5],\n            4\n        ),\n        test_skewed_bucket: (\n            [4, 1, 5],\n            3\n        ),\n        test_trapped_rainwater_empty: (\n            [],\n            0\n        ),\n        test_trapped_rainwater_flat: (\n            [0, 0, 0, 0, 0],\n            0\n        ),\n        test_trapped_rainwater_no_trapped_water: (\n            [1, 1, 2, 4, 0, 0, 0],\n            0\n        ),\n        test_trapped_rainwater_single_elevation_map: (\n            [5],\n            0\n        ),\n        test_trapped_rainwater_two_point_elevation_map: (\n            [5, 1],\n            0\n        ),\n        test_trapped_rainwater_large_elevation_map_difference: (\n            [5, 1, 6, 1, 7, 1, 8],\n            15\n        ),\n    }\n}\n"
  },
  {
    "path": "src/dynamic_programming/word_break.rs",
    "content": "use crate::data_structures::Trie;\n\n/// Checks if a string can be segmented into a space-separated sequence\n/// of one or more words from the given dictionary.\n///\n/// # Arguments\n/// * `s` - The input string to be segmented.\n/// * `word_dict` - A slice of words forming the dictionary.\n///\n/// # Returns\n/// * `bool` - `true` if the string can be segmented, `false` otherwise.\npub fn word_break(s: &str, word_dict: &[&str]) -> bool {\n    let mut trie = Trie::new();\n    for &word in word_dict {\n        trie.insert(word.chars(), true);\n    }\n\n    // Memoization vector: one extra space to handle out-of-bound end case.\n    let mut memo = vec![None; s.len() + 1];\n    search(&trie, s, 0, &mut memo)\n}\n\n/// Recursively checks if the substring starting from `start` can be segmented\n/// using words in the trie and memoizes the results.\n///\n/// # Arguments\n/// * `trie` - The Trie containing the dictionary words.\n/// * `s` - The input string.\n/// * `start` - The starting index for the current substring.\n/// * `memo` - A vector for memoization to store intermediate results.\n///\n/// # Returns\n/// * `bool` - `true` if the substring can be segmented, `false` otherwise.\nfn search(trie: &Trie<char, bool>, s: &str, start: usize, memo: &mut Vec<Option<bool>>) -> bool {\n    if start == s.len() {\n        return true;\n    }\n\n    if let Some(res) = memo[start] {\n        return res;\n    }\n\n    for end in start + 1..=s.len() {\n        if trie.get(s[start..end].chars()).is_some() && search(trie, s, end, memo) {\n            memo[start] = Some(true);\n            return true;\n        }\n    }\n\n    memo[start] = Some(false);\n    false\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_cases {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, dict, expected) = $test_case;\n                    assert_eq!(word_break(input, &dict), expected);\n                }\n            )*\n        }\n    }\n\n    test_cases! {\n        typical_case_1: (\"applepenapple\", vec![\"apple\", \"pen\"], true),\n        typical_case_2: (\"catsandog\", vec![\"cats\", \"dog\", \"sand\", \"and\", \"cat\"], false),\n        typical_case_3: (\"cars\", vec![\"car\", \"ca\", \"rs\"], true),\n        edge_case_empty_string: (\"\", vec![\"apple\", \"pen\"], true),\n        edge_case_empty_dict: (\"apple\", vec![], false),\n        edge_case_single_char_in_dict: (\"a\", vec![\"a\"], true),\n        edge_case_single_char_not_in_dict: (\"b\", vec![\"a\"], false),\n        edge_case_all_words_larger_than_input: (\"a\", vec![\"apple\", \"banana\"], false),\n        edge_case_no_solution_large_string: (\"abcdefghijklmnoqrstuv\", vec![\"a\", \"bc\", \"def\", \"ghij\", \"klmno\", \"pqrst\"], false),\n        successful_segmentation_large_string: (\"abcdefghijklmnopqrst\", vec![\"a\", \"bc\", \"def\", \"ghij\", \"klmno\", \"pqrst\"], true),\n        long_string_repeated_pattern: (&\"ab\".repeat(100), vec![\"a\", \"b\", \"ab\"], true),\n        long_string_no_solution: (&\"a\".repeat(100), vec![\"b\"], false),\n        mixed_size_dict_1: (\"pineapplepenapple\", vec![\"apple\", \"pen\", \"applepen\", \"pine\", \"pineapple\"], true),\n        mixed_size_dict_2: (\"catsandog\", vec![\"cats\", \"dog\", \"sand\", \"and\", \"cat\"], false),\n        mixed_size_dict_3: (\"abcd\", vec![\"a\", \"abc\", \"b\", \"cd\"], true),\n        performance_stress_test_large_valid: (&\"abc\".repeat(1000), vec![\"a\", \"ab\", \"abc\"], true),\n        performance_stress_test_large_invalid: (&\"x\".repeat(1000), vec![\"a\", \"ab\", \"abc\"], false),\n    }\n}\n"
  },
  {
    "path": "src/financial/depreciation.rs",
    "content": "//! # Depreciation\n//!\n//! In accounting, depreciation refers to the decreases in the value of a fixed\n//! asset during the asset's useful life. When an organization purchases a fixed\n//! asset, the purchase expenditure is not recognized as an expense immediately.\n//! Instead, the decreases in the asset's value are recognized as expenses over\n//! the years during which the asset is used.\n//!\n//! The following methods are implemented here:\n//! - **Straight-line method** — cost spread evenly over the asset's useful life.\n//! - **Diminishing balance method** — a fixed percentage is applied each year to\n//!   the asset's remaining book value.\n//! - **Units-of-production method** — depreciation is tied to actual usage\n//!   (units produced / hours used) rather than time.\n//! - **Sum-of-years' digits (SYD)** — an accelerated method that applies a\n//!   declining fraction to the depreciable cost each year.\n//! - **Double-declining balance (DDB)** — the most common accelerated method;\n//!   uses `rate = 2 / useful_years` and automatically switches to straight-line\n//!   in the year that method yields a higher charge.\n//!\n//! Further information: <https://en.wikipedia.org/wiki/Depreciation>\n\n// ─────────────────────────────────────────────────────────────\n// Error type\n// ─────────────────────────────────────────────────────────────\n\n/// Errors that can occur during a depreciation calculation.\n#[derive(Debug, PartialEq)]\npub enum DepreciationError {\n    /// `useful_years` was supplied as zero.\n    UsefulYearsZero,\n    /// `purchase_value` is negative.\n    NegativePurchaseValue,\n    /// `purchase_value` is less than `residual_value`.\n    PurchaseValueLessThanResidual,\n    /// A rate or percentage argument is out of its valid range.\n    InvalidRate(String),\n    /// The sum of units-of-production estimates does not match `total_units`.\n    UnitsMismatch { expected: f64, got: f64 },\n}\n\nimpl std::fmt::Display for DepreciationError {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::UsefulYearsZero => write!(f, \"Useful years must be at least 1\"),\n            Self::NegativePurchaseValue => {\n                write!(f, \"Purchase value cannot be less than zero\")\n            }\n            Self::PurchaseValueLessThanResidual => {\n                write!(f, \"Purchase value cannot be less than residual value\")\n            }\n            Self::InvalidRate(msg) => write!(f, \"Invalid rate: {msg}\"),\n            Self::UnitsMismatch { expected, got } => write!(\n                f,\n                \"Units mismatch: expected {expected} total units, got {got}\"\n            ),\n        }\n    }\n}\n\nimpl std::error::Error for DepreciationError {}\n\n// ─────────────────────────────────────────────────────────────\n// Shared validation helper\n// ─────────────────────────────────────────────────────────────\n\nfn validate_common(\n    useful_years: u32,\n    purchase_value: f64,\n    residual_value: f64,\n) -> Result<(), DepreciationError> {\n    if useful_years == 0 {\n        return Err(DepreciationError::UsefulYearsZero);\n    }\n    if purchase_value < 0.0 {\n        return Err(DepreciationError::NegativePurchaseValue);\n    }\n    if purchase_value < residual_value {\n        return Err(DepreciationError::PurchaseValueLessThanResidual);\n    }\n    Ok(())\n}\n\n// ─────────────────────────────────────────────────────────────\n// Strategy 1 — Straight-line\n// ─────────────────────────────────────────────────────────────\n\n/// Calculates depreciation using the **straight-line** method.\n///\n/// The depreciable cost is divided equally across every period.\n///\n/// **Formula:**\n/// ```text\n/// annual_expense = (purchase_value - residual_value) / useful_years\n/// ```\n///\n/// The last year's expense is adjusted so that accumulated depreciation\n/// sums to exactly `purchase_value - residual_value` (avoids floating-point\n/// drift).\n///\n/// # Errors\n/// Returns [`DepreciationError`] if any argument is invalid.\n///\n/// # Examples\n/// ```\n/// use the_algorithms_rust::financial::straight_line_depreciation;\n///\n/// let result = straight_line_depreciation(10, 1100.0, 100.0).unwrap();\n/// assert!(result.iter().all(|&v| (v - 100.0).abs() < 1e-9));\n/// ```\npub fn straight_line_depreciation(\n    useful_years: u32,\n    purchase_value: f64,\n    residual_value: f64,\n) -> Result<Vec<f64>, DepreciationError> {\n    validate_common(useful_years, purchase_value, residual_value)?;\n\n    let depreciable_cost = purchase_value - residual_value;\n    let annual_expense = depreciable_cost / useful_years as f64;\n\n    let mut schedule: Vec<f64> = Vec::with_capacity(useful_years as usize);\n    let mut accumulated = 0.0_f64;\n\n    for period in 0..useful_years {\n        if period == useful_years - 1 {\n            // Last period absorbs any floating-point remainder\n            schedule.push(depreciable_cost - accumulated);\n        } else {\n            accumulated += annual_expense;\n            schedule.push(annual_expense);\n        }\n    }\n\n    Ok(schedule)\n}\n\n// ─────────────────────────────────────────────────────────────\n// Strategy 2 — Diminishing balance (declining balance)\n// ─────────────────────────────────────────────────────────────\n\n/// Calculates depreciation using the **diminishing balance** (declining\n/// balance) method.\n///\n/// A fixed `rate` (0 < rate ≤ 1) is applied each year to the *remaining book\n/// value* of the asset.  In the final year the entire remaining book value\n/// above the residual is written off, ensuring the schedule sums exactly to\n/// the depreciable cost.\n///\n/// **Formula per period:**\n/// ```text\n/// expense(t) = book_value(t) * rate\n/// book_value(t+1) = book_value(t) - expense(t)\n/// ```\n///\n/// A common variant is the **double-declining balance** method, which sets\n/// `rate = 2 / useful_years`.\n///\n/// # Errors\n/// Returns [`DepreciationError`] if any argument is invalid or `rate` is not\n/// in `(0, 1]`.\n///\n/// # Examples\n/// ```\n/// use the_algorithms_rust::financial::diminishing_balance_depreciation;\n///\n/// // Double-declining balance on a 5-year, $10 000 asset with no salvage value\n/// let rate = 2.0 / 5.0;\n/// let schedule = diminishing_balance_depreciation(5, 10_000.0, 0.0, rate).unwrap();\n/// let total: f64 = schedule.iter().sum();\n/// assert!((total - 10_000.0).abs() < 1e-6);\n/// ```\npub fn diminishing_balance_depreciation(\n    useful_years: u32,\n    purchase_value: f64,\n    residual_value: f64,\n    rate: f64,\n) -> Result<Vec<f64>, DepreciationError> {\n    validate_common(useful_years, purchase_value, residual_value)?;\n\n    if rate <= 0.0 || rate > 1.0 {\n        return Err(DepreciationError::InvalidRate(format!(\n            \"Diminishing balance rate must be in (0, 1], got {rate}\"\n        )));\n    }\n\n    let mut schedule: Vec<f64> = Vec::with_capacity(useful_years as usize);\n    let mut book_value = purchase_value;\n\n    for period in 0..useful_years {\n        if period == useful_years - 1 {\n            // Final year: write off everything above residual value\n            schedule.push(book_value - residual_value);\n        } else {\n            let expense = book_value * rate;\n            // Never depreciate below the residual value mid-life\n            let expense = expense.min(book_value - residual_value);\n            schedule.push(expense);\n            book_value -= expense;\n        }\n    }\n\n    Ok(schedule)\n}\n\n// ─────────────────────────────────────────────────────────────\n// Strategy 3 — Units-of-production\n// ─────────────────────────────────────────────────────────────\n\n/// Calculates depreciation using the **units-of-production** method.\n///\n/// Depreciation in each period is proportional to the number of units\n/// produced (or hours used) in that period relative to the total expected\n/// output over the asset's life.\n///\n/// **Formula per period:**\n/// ```text\n/// expense(t) = (units_in_period(t) / total_units) * depreciable_cost\n/// ```\n///\n/// `units_per_period` must sum to `total_units` (within a small floating-point\n/// tolerance).\n///\n/// # Errors\n/// Returns [`DepreciationError`] if any argument is invalid or the unit\n/// totals do not match.\n///\n/// # Examples\n/// ```\n/// use the_algorithms_rust::financial::units_of_production_depreciation;\n///\n/// // 4-year asset; total output = 100 000 units\n/// let schedule = units_of_production_depreciation(\n///     1_000.0, 100.0, 100_000.0,\n///     &[30_000.0, 25_000.0, 25_000.0, 20_000.0],\n/// ).unwrap();\n/// let total: f64 = schedule.iter().sum();\n/// assert!((total - 900.0).abs() < 1e-6);\n/// ```\npub fn units_of_production_depreciation(\n    purchase_value: f64,\n    residual_value: f64,\n    total_units: f64,\n    units_per_period: &[f64],\n) -> Result<Vec<f64>, DepreciationError> {\n    let useful_years = units_per_period.len() as u32;\n    validate_common(useful_years, purchase_value, residual_value)?;\n\n    if total_units <= 0.0 {\n        return Err(DepreciationError::InvalidRate(\n            \"total_units must be positive\".into(),\n        ));\n    }\n\n    let units_sum: f64 = units_per_period.iter().sum();\n    if (units_sum - total_units).abs() > 1e-6 * total_units {\n        return Err(DepreciationError::UnitsMismatch {\n            expected: total_units,\n            got: units_sum,\n        });\n    }\n\n    let depreciable_cost = purchase_value - residual_value;\n    let depreciation_per_unit = depreciable_cost / total_units;\n\n    let mut schedule: Vec<f64> = Vec::with_capacity(units_per_period.len());\n    let mut accumulated = 0.0_f64;\n\n    for (i, &units) in units_per_period.iter().enumerate() {\n        if i == units_per_period.len() - 1 {\n            // Final period absorbs floating-point remainder\n            schedule.push(depreciable_cost - accumulated);\n        } else {\n            let expense = units * depreciation_per_unit;\n            accumulated += expense;\n            schedule.push(expense);\n        }\n    }\n\n    Ok(schedule)\n}\n\n// ─────────────────────────────────────────────────────────────\n// Strategy 4 — Sum-of-years' digits (SYD)\n// ─────────────────────────────────────────────────────────────\n\n/// Calculates depreciation using the **sum-of-years' digits (SYD)** method.\n///\n/// This is an *accelerated* method: higher depreciation is charged in earlier\n/// years, tapering off as the asset ages.  Each year's expense is computed by\n/// multiplying the depreciable cost by a fraction whose numerator is the\n/// remaining useful life at the start of the period and whose denominator is\n/// the sum of all year numbers (the \"sum of digits\").\n///\n/// **Formula:**\n/// ```text\n/// SYD          = n * (n + 1) / 2          where n = useful_years\n/// fraction(t)  = (n - t + 1) / SYD        for period t = 1 … n\n/// expense(t)   = fraction(t) * depreciable_cost\n/// ```\n///\n/// The schedule always sums exactly to `purchase_value - residual_value`.\n///\n/// # Errors\n/// Returns [`DepreciationError`] if any argument is invalid.\n///\n/// # Examples\n/// ```\n/// use the_algorithms_rust::financial::sum_of_years_digits_depreciation;\n///\n/// // 5-year asset, $10 000 cost, no residual\n/// // SYD = 15; fractions: 5/15, 4/15, 3/15, 2/15, 1/15\n/// let s = sum_of_years_digits_depreciation(5, 10_000.0, 0.0).unwrap();\n/// assert!((s[0] - 10_000.0 * 5.0 / 15.0).abs() < 1e-9);\n/// assert!((s[4] - 10_000.0 * 1.0 / 15.0).abs() < 1e-9);\n/// let total: f64 = s.iter().sum();\n/// assert!((total - 10_000.0).abs() < 1e-9);\n/// ```\npub fn sum_of_years_digits_depreciation(\n    useful_years: u32,\n    purchase_value: f64,\n    residual_value: f64,\n) -> Result<Vec<f64>, DepreciationError> {\n    validate_common(useful_years, purchase_value, residual_value)?;\n\n    let n = useful_years as f64;\n    // Sum of digits: 1 + 2 + … + n = n(n+1)/2\n    let syd = n * (n + 1.0) / 2.0;\n    let depreciable_cost = purchase_value - residual_value;\n\n    let mut schedule: Vec<f64> = Vec::with_capacity(useful_years as usize);\n    let mut accumulated = 0.0_f64;\n\n    for period in 1..=useful_years {\n        let remaining_life = (useful_years - period + 1) as f64;\n        if period == useful_years {\n            // Last period absorbs any floating-point remainder\n            schedule.push(depreciable_cost - accumulated);\n        } else {\n            let expense = (remaining_life / syd) * depreciable_cost;\n            accumulated += expense;\n            schedule.push(expense);\n        }\n    }\n\n    Ok(schedule)\n}\n\n// ─────────────────────────────────────────────────────────────\n// Strategy 5 — Double-declining balance (DDB)\n// ─────────────────────────────────────────────────────────────\n\n/// Calculates depreciation using the **double-declining balance (DDB)** method.\n///\n/// DDB is the most widely used form of the diminishing balance method.  It\n/// applies a rate of `2 / useful_years` to the current book value each period.\n///\n/// A key accounting rule is applied automatically: **in any year where the\n/// straight-line charge on the remaining book value would exceed the DDB\n/// charge, the method switches to straight-line** for that year and all\n/// subsequent years.  This ensures the book value reaches the residual value\n/// by the end of the asset's life without requiring a large write-off in the\n/// final year.\n///\n/// **Formula:**\n/// ```text\n/// rate            = 2 / useful_years\n/// ddb_expense(t)  = book_value(t) * rate\n/// sl_expense(t)   = (book_value(t) - residual_value) / remaining_years(t)\n/// expense(t)      = max(ddb_expense(t), sl_expense(t))\n/// ```\n///\n/// # Errors\n/// Returns [`DepreciationError`] if any argument is invalid.\n///\n/// # Examples\n/// ```\n/// use the_algorithms_rust::financial::double_declining_balance_depreciation;\n///\n/// // Classic textbook example: 5-year, $10 000, $1 000 residual\n/// let s = double_declining_balance_depreciation(5, 10_000.0, 1_000.0).unwrap();\n/// let total: f64 = s.iter().sum();\n/// assert!((total - 9_000.0).abs() < 1e-6);\n/// // First year should be higher than straight-line ($1 800 vs $4 000)\n/// assert!(s[0] > s[4]);\n/// ```\npub fn double_declining_balance_depreciation(\n    useful_years: u32,\n    purchase_value: f64,\n    residual_value: f64,\n) -> Result<Vec<f64>, DepreciationError> {\n    validate_common(useful_years, purchase_value, residual_value)?;\n\n    let rate = 2.0 / useful_years as f64;\n    let depreciable_cost = purchase_value - residual_value;\n    let mut schedule: Vec<f64> = Vec::with_capacity(useful_years as usize);\n    let mut book_value = purchase_value;\n    let mut accumulated = 0.0_f64;\n\n    for period in 1..=useful_years {\n        let remaining_years = (useful_years - period + 1) as f64;\n\n        // DDB charge for this period (never below zero)\n        let ddb_expense = (book_value * rate).max(0.0);\n\n        // Straight-line charge on remaining depreciable cost\n        let sl_expense = ((book_value - residual_value) / remaining_years).max(0.0);\n\n        // Switch to straight-line if it gives a larger charge\n        let expense = ddb_expense.max(sl_expense);\n\n        // Cap so we never depreciate below residual value\n        let expense = expense.min(book_value - residual_value);\n\n        if period == useful_years {\n            // Final period: write off exactly what remains above residual\n            schedule.push(depreciable_cost - accumulated);\n        } else {\n            accumulated += expense;\n            schedule.push(expense);\n            book_value -= expense;\n        }\n    }\n\n    Ok(schedule)\n}\n\n// ─────────────────────────────────────────────────────────────\n// Tests\n// ─────────────────────────────────────────────────────────────\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    // ── Straight-line ────────────────────────────────────────\n\n    #[test]\n    fn sl_basic() {\n        let s = straight_line_depreciation(10, 1100.0, 100.0).unwrap();\n        assert_eq!(s.len(), 10);\n        assert!(s.iter().all(|&v| (v - 100.0).abs() < 1e-9));\n    }\n\n    #[test]\n    fn sl_six_years() {\n        let s = straight_line_depreciation(6, 1250.0, 50.0).unwrap();\n        assert!(s.iter().all(|&v| (v - 200.0).abs() < 1e-9));\n    }\n\n    #[test]\n    fn sl_no_residual() {\n        let s = straight_line_depreciation(4, 1001.0, 0.0).unwrap();\n        assert!(s.iter().all(|&v| (v - 250.25).abs() < 1e-9));\n    }\n\n    #[test]\n    fn sl_sum_equals_depreciable_cost() {\n        let purchase = 7_500.0_f64;\n        let residual = 500.0_f64;\n        let s = straight_line_depreciation(7, purchase, residual).unwrap();\n        let total: f64 = s.iter().sum();\n        assert!((total - (purchase - residual)).abs() < 1e-9);\n    }\n\n    #[test]\n    fn sl_single_year() {\n        let s = straight_line_depreciation(1, 4985.0, 100.0).unwrap();\n        assert_eq!(s.len(), 1);\n        assert!((s[0] - 4885.0).abs() < 1e-9);\n    }\n\n    #[test]\n    fn sl_err_zero_years() {\n        assert_eq!(\n            straight_line_depreciation(0, 1000.0, 0.0),\n            Err(DepreciationError::UsefulYearsZero)\n        );\n    }\n\n    #[test]\n    fn sl_err_negative_purchase() {\n        assert_eq!(\n            straight_line_depreciation(5, -500.0, 0.0),\n            Err(DepreciationError::NegativePurchaseValue)\n        );\n    }\n\n    #[test]\n    fn sl_err_residual_exceeds_purchase() {\n        assert_eq!(\n            straight_line_depreciation(5, 100.0, 200.0),\n            Err(DepreciationError::PurchaseValueLessThanResidual)\n        );\n    }\n\n    // ── Diminishing balance ──────────────────────────────────\n\n    #[test]\n    fn db_sum_equals_depreciable_cost() {\n        let purchase = 10_000.0_f64;\n        let residual = 0.0_f64;\n        let rate = 2.0 / 5.0; // double-declining, 5-year\n        let s = diminishing_balance_depreciation(5, purchase, residual, rate).unwrap();\n        let total: f64 = s.iter().sum();\n        assert!((total - (purchase - residual)).abs() < 1e-6);\n    }\n\n    #[test]\n    fn db_never_below_residual() {\n        let purchase = 5_000.0_f64;\n        let residual = 500.0_f64;\n        let s = diminishing_balance_depreciation(6, purchase, residual, 0.5).unwrap();\n        // book value must never drop below residual\n        let mut book = purchase;\n        for expense in &s {\n            book -= expense;\n        }\n        assert!(book >= residual - 1e-9);\n    }\n\n    #[test]\n    fn db_err_rate_zero() {\n        assert!(matches!(\n            diminishing_balance_depreciation(5, 1000.0, 0.0, 0.0),\n            Err(DepreciationError::InvalidRate(_))\n        ));\n    }\n\n    #[test]\n    fn db_err_rate_above_one() {\n        assert!(matches!(\n            diminishing_balance_depreciation(5, 1000.0, 0.0, 1.1),\n            Err(DepreciationError::InvalidRate(_))\n        ));\n    }\n\n    // ── Units-of-production ──────────────────────────────────\n\n    #[test]\n    fn up_sum_equals_depreciable_cost() {\n        let purchase = 1_000.0_f64;\n        let residual = 100.0_f64;\n        let total_units = 100_000.0_f64;\n        let periods = vec![30_000.0, 25_000.0, 25_000.0, 20_000.0];\n        let s =\n            units_of_production_depreciation(purchase, residual, total_units, &periods).unwrap();\n        let total: f64 = s.iter().sum();\n        assert!((total - (purchase - residual)).abs() < 1e-9);\n    }\n\n    #[test]\n    fn up_proportional_expenses() {\n        let purchase = 10_000.0_f64;\n        let residual = 0.0_f64;\n        let total = 1_000.0_f64;\n        let periods = vec![250.0, 250.0, 250.0, 250.0];\n        let s = units_of_production_depreciation(purchase, residual, total, &periods).unwrap();\n        assert!(s.iter().all(|&v| (v - 2_500.0).abs() < 1e-6));\n    }\n\n    #[test]\n    fn up_err_units_mismatch() {\n        assert!(matches!(\n            units_of_production_depreciation(1000.0, 0.0, 100.0, &[30.0, 40.0, 20.0]),\n            Err(DepreciationError::UnitsMismatch { .. })\n        ));\n    }\n\n    #[test]\n    fn up_err_zero_total_units() {\n        assert!(matches!(\n            units_of_production_depreciation(1000.0, 0.0, 0.0, &[0.0]),\n            Err(DepreciationError::InvalidRate(_))\n        ));\n    }\n\n    // ── Sum-of-years' digits ─────────────────────────────────\n\n    #[test]\n    fn syd_sum_equals_depreciable_cost() {\n        let purchase = 10_000.0_f64;\n        let residual = 0.0_f64;\n        let s = sum_of_years_digits_depreciation(5, purchase, residual).unwrap();\n        let total: f64 = s.iter().sum();\n        assert!((total - (purchase - residual)).abs() < 1e-9);\n    }\n\n    #[test]\n    fn syd_first_year_fraction() {\n        // Year 1 fraction = n / SYD = 5/15 for a 5-year asset\n        let s = sum_of_years_digits_depreciation(5, 10_000.0, 0.0).unwrap();\n        let expected = 10_000.0 * 5.0 / 15.0;\n        assert!((s[0] - expected).abs() < 1e-9);\n    }\n\n    #[test]\n    fn syd_last_year_fraction() {\n        // Year 5 fraction = 1/15\n        let s = sum_of_years_digits_depreciation(5, 10_000.0, 0.0).unwrap();\n        let expected = 10_000.0 * 1.0 / 15.0;\n        assert!((s[4] - expected).abs() < 1e-9);\n    }\n\n    #[test]\n    fn syd_decreasing_charges() {\n        // Each year's charge must be strictly less than the previous\n        let s = sum_of_years_digits_depreciation(6, 12_000.0, 0.0).unwrap();\n        for window in s.windows(2) {\n            assert!(window[0] > window[1]);\n        }\n    }\n\n    #[test]\n    fn syd_with_residual() {\n        let purchase = 5_000.0_f64;\n        let residual = 500.0_f64;\n        let s = sum_of_years_digits_depreciation(4, purchase, residual).unwrap();\n        let total: f64 = s.iter().sum();\n        assert!((total - (purchase - residual)).abs() < 1e-9);\n    }\n\n    #[test]\n    fn syd_single_year() {\n        let s = sum_of_years_digits_depreciation(1, 2_000.0, 200.0).unwrap();\n        assert_eq!(s.len(), 1);\n        assert!((s[0] - 1_800.0).abs() < 1e-9);\n    }\n\n    #[test]\n    fn syd_err_zero_years() {\n        assert_eq!(\n            sum_of_years_digits_depreciation(0, 1000.0, 0.0),\n            Err(DepreciationError::UsefulYearsZero)\n        );\n    }\n\n    // ── Double-declining balance ─────────────────────────────\n\n    #[test]\n    fn ddb_sum_equals_depreciable_cost() {\n        let purchase = 10_000.0_f64;\n        let residual = 1_000.0_f64;\n        let s = double_declining_balance_depreciation(5, purchase, residual).unwrap();\n        let total: f64 = s.iter().sum();\n        assert!((total - (purchase - residual)).abs() < 1e-6);\n    }\n\n    #[test]\n    fn ddb_first_year_is_double_sl() {\n        // Year-1 DDB charge = 2/n * purchase_value\n        let s = double_declining_balance_depreciation(5, 10_000.0, 0.0).unwrap();\n        let expected_first = 10_000.0 * 2.0 / 5.0;\n        assert!((s[0] - expected_first).abs() < 1e-9);\n    }\n\n    #[test]\n    fn ddb_never_below_residual() {\n        let purchase = 8_000.0_f64;\n        let residual = 800.0_f64;\n        let s = double_declining_balance_depreciation(6, purchase, residual).unwrap();\n        let mut book = purchase;\n        for expense in &s {\n            book -= expense;\n        }\n        assert!(book >= residual - 1e-9);\n    }\n\n    #[test]\n    fn ddb_switches_to_sl() {\n        // With residual value, DDB must switch to straight-line at some point;\n        // the last few charges should be equal (straight-line portion).\n        let s = double_declining_balance_depreciation(5, 10_000.0, 2_000.0).unwrap();\n        // At minimum the last two years should not decrease like pure DDB\n        assert!(s[3] <= s[2] || (s[3] - s[4]).abs() < 1e-6);\n    }\n\n    #[test]\n    fn ddb_err_zero_years() {\n        assert_eq!(\n            double_declining_balance_depreciation(0, 1000.0, 0.0),\n            Err(DepreciationError::UsefulYearsZero)\n        );\n    }\n\n    #[test]\n    fn ddb_err_residual_exceeds_purchase() {\n        assert_eq!(\n            double_declining_balance_depreciation(5, 100.0, 200.0),\n            Err(DepreciationError::PurchaseValueLessThanResidual)\n        );\n    }\n}\n"
  },
  {
    "path": "src/financial/equated_monthly_installments.rs",
    "content": "//! Calculates the Equated Monthly Installment (EMI) for a loan.\n//!\n//! Formula: A = p * r * (1 + r)^n / ((1 + r)^n - 1)\n//! where:\n//!   - `p` is the principal\n//!   - `r` is the monthly interest rate (annual rate / 12)\n//!   - `n` is the total number of monthly payments (years * 12)\n//!\n//! Wikipedia Reference: https://en.wikipedia.org/wiki/Equated_monthly_installment\n\n/// Computes the monthly EMI for a loan.\n///\n/// # Arguments\n/// * `principal`        - The total amount borrowed (must be > 0)\n/// * `rate_per_annum`   - Annual interest rate as a decimal, e.g. 0.12 for 12% (must be >= 0)\n/// * `years_to_repay`   - Loan term in whole years (must be > 0)\n///\n/// # Errors\n/// Returns an `Err(&'static str)` if any argument is out of range.\npub fn equated_monthly_installments(\n    principal: f64,\n    rate_per_annum: f64,\n    years_to_repay: u32,\n) -> Result<f64, &'static str> {\n    if principal <= 0.0 {\n        return Err(\"Principal borrowed must be > 0\");\n    }\n    if rate_per_annum < 0.0 {\n        return Err(\"Rate of interest must be >= 0\");\n    }\n    if years_to_repay == 0 {\n        return Err(\"Years to repay must be an integer > 0\");\n    }\n\n    // Divide annual rate by 12 to obtain the monthly rate\n    let rate_per_month = rate_per_annum / 12.0;\n\n    // Multiply years by 12 to obtain the total number of monthly payments\n    let number_of_payments = f64::from(years_to_repay * 12);\n\n    // Handle the edge case where the interest rate is 0 (simple division)\n    if rate_per_month == 0.0 {\n        return Ok(principal / number_of_payments);\n    }\n\n    let factor = (1.0 + rate_per_month).powf(number_of_payments);\n    Ok(principal * rate_per_month * factor / (factor - 1.0))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_equated_monthly_installments() {\n        const EPSILON: f64 = 1e-8;\n\n        // Standard cases\n        let result = equated_monthly_installments(25000.0, 0.12, 3).unwrap();\n        assert!((result - 830.357_745_321_279_3).abs() < EPSILON);\n\n        let result = equated_monthly_installments(25000.0, 0.12, 10).unwrap();\n        assert!((result - 358.677_371_006_468_26).abs() < EPSILON);\n\n        // With 0% interest the EMI is simply principal / number_of_payments\n        let result = equated_monthly_installments(12000.0, 0.0, 1).unwrap();\n        assert!((result - 1000.0).abs() < EPSILON);\n\n        // Error cases\n        assert_eq!(\n            equated_monthly_installments(0.0, 0.12, 3),\n            Err(\"Principal borrowed must be > 0\")\n        );\n        assert_eq!(\n            equated_monthly_installments(-5000.0, 0.12, 3),\n            Err(\"Principal borrowed must be > 0\")\n        );\n        assert_eq!(\n            equated_monthly_installments(25000.0, -1.0, 3),\n            Err(\"Rate of interest must be >= 0\")\n        );\n        assert_eq!(\n            equated_monthly_installments(25000.0, 0.12, 0),\n            Err(\"Years to repay must be an integer > 0\")\n        );\n    }\n}\n"
  },
  {
    "path": "src/financial/exponential_moving_average.rs",
    "content": "//! Calculate the exponential moving average (EMA) on the series of stock prices.\n//!\n//! Wikipedia Reference: <https://en.wikipedia.org/wiki/Exponential_smoothing>\n//! Investopedia Reference: <https://www.investopedia.com/terms/e/ema.asp>\n//!\n//! Exponential moving average is used in finance to analyze changes in stock prices.\n//! EMA is used in conjunction with Simple Moving Average (SMA). EMA reacts to\n//! changes in value quicker than SMA, which is one of its key advantages.\n//!\n//! # Formula\n//! ```text\n//! st = alpha * xt + (1 - alpha) * st_prev\n//! ```\n//! Where:\n//! - `st`      : Exponential moving average at timestamp t\n//! - `xt`      : Stock price at timestamp t\n//! - `st_prev` : Exponential moving average at timestamp t-1\n//! - `alpha`   : 2 / (1 + window_size) — the smoothing factor\n\n/// Returns an iterator of exponential moving averages over the given stock prices.\n///\n/// # Errors\n/// Returns an error string if `window_size` is zero.\n///\n/// # Examples\n/// ```\n/// use the_algorithms_rust::financial::exponential_moving_average;\n/// let prices = vec![2.0, 5.0, 3.0, 8.2, 6.0, 9.0, 10.0];\n/// let result: Vec<f64> = exponential_moving_average(prices.into_iter(), 3).unwrap().collect();\n/// let expected = vec![2.0, 3.5, 3.25, 5.725, 5.8625, 7.43125, 8.715625];\n/// for (r, e) in result.iter().zip(expected.iter()) {\n///     assert!((r - e).abs() < 1e-9);\n/// }\n/// ```\npub fn exponential_moving_average(\n    stock_prices: impl Iterator<Item = f64>,\n    window_size: usize,\n) -> Result<impl Iterator<Item = f64>, &'static str> {\n    if window_size == 0 {\n        return Err(\"window_size must be > 0\");\n    }\n\n    let alpha = 2.0 / (1.0 + window_size as f64);\n\n    let iter = stock_prices\n        .enumerate()\n        .scan(0.0_f64, move |moving_average, (i, stock_price)| {\n            *moving_average = if i <= window_size {\n                // Use simple moving average until window_size is first reached\n                if i == 0 {\n                    stock_price\n                } else {\n                    (*moving_average + stock_price) * 0.5\n                }\n            } else {\n                // Apply exponential smoothing formula\n                alpha * stock_price + (1.0 - alpha) * *moving_average\n            };\n            Some(*moving_average)\n        });\n\n    Ok(iter)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn approx_eq(a: f64, b: f64) -> bool {\n        (a - b).abs() < 1e-9\n    }\n\n    #[test]\n    fn test_basic_ema() {\n        let prices = vec![2.0, 5.0, 3.0, 8.2, 6.0, 9.0, 10.0];\n        let expected = [2.0, 3.5, 3.25, 5.725, 5.8625, 7.43125, 8.715625];\n        let result: Vec<f64> = exponential_moving_average(prices.into_iter(), 3)\n            .unwrap()\n            .collect();\n\n        assert_eq!(result.len(), expected.len());\n        for (r, e) in result.iter().zip(expected.iter()) {\n            assert!(approx_eq(*r, *e), \"Expected {e}, got {r}\");\n        }\n    }\n\n    #[test]\n    fn test_window_size_one() {\n        // With window_size=1, alpha=1.0, so EMA should equal each price after the first\n        let prices = vec![1.0, 2.0, 3.0];\n        let result: Vec<f64> = exponential_moving_average(prices.into_iter(), 1)\n            .unwrap()\n            .collect();\n        // i=0: price (window boundary), i=1: SMA=(1+2)*0.5=1.5, i=2: alpha=1.0 => 3.0\n        assert!(approx_eq(result[0], 1.0));\n        assert!(approx_eq(result[1], 1.5));\n        assert!(approx_eq(result[2], 3.0));\n    }\n\n    #[test]\n    fn test_single_price() {\n        let prices = vec![42.0];\n        let result: Vec<f64> = exponential_moving_average(prices.into_iter(), 3)\n            .unwrap()\n            .collect();\n        assert_eq!(result, vec![42.0]);\n    }\n\n    #[test]\n    fn test_empty_prices() {\n        let prices: Vec<f64> = vec![];\n        assert!(exponential_moving_average(prices.into_iter(), 3)\n            .unwrap()\n            .next()\n            .is_none());\n    }\n\n    #[test]\n    fn test_zero_window_size_returns_error() {\n        let prices = vec![1.0, 2.0, 3.0];\n        assert!(exponential_moving_average(prices.into_iter(), 0).is_err());\n    }\n}\n"
  },
  {
    "path": "src/financial/finance_ratios.rs",
    "content": "// Calculating simple ratios like Return on Investment (ROI), Debt to Equity, Gross Profit Margin\n// and Earnings per Sale (EPS)\npub fn return_on_investment(gain: f64, cost: f64) -> f64 {\n    (gain - cost) / cost\n}\n\npub fn debt_to_equity(debt: f64, equity: f64) -> f64 {\n    debt / equity\n}\n\npub fn gross_profit_margin(revenue: f64, cost: f64) -> f64 {\n    (revenue - cost) / revenue\n}\n\npub fn earnings_per_sale(net_income: f64, pref_dividend: f64, share_avg: f64) -> f64 {\n    (net_income - pref_dividend) / share_avg\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_return_on_investment() {\n        // let gain = 1200, cost = 1000 thus, ROI = (1200 - 1000)/1000 = 0.2\n        let result = return_on_investment(1200.0, 1000.0);\n        assert!((result - 0.2).abs() < 0.001);\n    }\n\n    #[test]\n    fn test_debt_to_equity() {\n        // let debt = 300, equity = 150 thus, debt to equity ratio = 300/150 = 2\n        let result = debt_to_equity(300.0, 150.0);\n        assert!((result - 2.0).abs() < 0.001);\n    }\n\n    #[test]\n    fn test_gross_profit_margin() {\n        // let revenue = 1000, cost = 800 thus, gross profit margin = (1000-800)/1000 = 0.2\n        let result = gross_profit_margin(1000.0, 800.0);\n        assert!((result - 0.2).abs() < 0.01);\n    }\n\n    #[test]\n    fn test_earnings_per_sale() {\n        // let net_income = 350, pref_dividend = 50, share_avg = 25 this EPS = (350-50)/25 = 12\n        let result = earnings_per_sale(350.0, 50.0, 25.0);\n        assert!((result - 12.0).abs() < 0.001);\n    }\n}\n"
  },
  {
    "path": "src/financial/interest.rs",
    "content": "//! Calculates simple, compound, and APR interest on a principal amount.\n//!\n//! Formulas:\n//!   Simple Interest:   I = p * r * t\n//!   Compound Interest: I = p * ((1 + r)^n - 1)\n//!   APR Interest:      Compound interest with r = annual_rate / 365\n//!                      and n = years * 365\n//! where:\n//!   - `p` is the principal\n//!   - `r` is the interest rate per period\n//!   - `t` is the number of periods (days)\n//!   - `n` is the total number of compounding periods\n//!\n//! Reference: https://www.investopedia.com/terms/i/interest.asp\n\n/// Calculates simple interest earned over a number of days.\n///\n/// # Arguments\n/// * `principal`             - The initial amount of money (must be > 0)\n/// * `daily_interest_rate`   - The daily interest rate as a decimal (must be >= 0)\n/// * `days_between_payments` - The number of days between payments (must be > 0)\n///\n/// # Errors\n/// Returns an `Err(&'static str)` if any argument is out of range.\npub fn simple_interest(\n    principal: f64,\n    daily_interest_rate: f64,\n    days_between_payments: f64,\n) -> Result<f64, &'static str> {\n    if principal <= 0.0 {\n        return Err(\"principal must be > 0\");\n    }\n    if daily_interest_rate < 0.0 {\n        return Err(\"daily_interest_rate must be >= 0\");\n    }\n    if days_between_payments <= 0.0 {\n        return Err(\"days_between_payments must be > 0\");\n    }\n    Ok(principal * daily_interest_rate * days_between_payments)\n}\n\n/// Calculates compound interest earned over a number of compounding periods.\n///\n/// # Arguments\n/// * `principal`                     - The initial amount of money (must be > 0)\n/// * `nominal_annual_interest_rate`  - The rate per compounding period as a decimal (must be >= 0)\n/// * `number_of_compounding_periods` - The total number of compounding periods (must be > 0)\n///\n/// # Errors\n/// Returns an `Err(&'static str)` if any argument is out of range.\npub fn compound_interest(\n    principal: f64,\n    nominal_annual_interest_rate: f64,\n    number_of_compounding_periods: f64,\n) -> Result<f64, &'static str> {\n    if principal <= 0.0 {\n        return Err(\"principal must be > 0\");\n    }\n    if nominal_annual_interest_rate < 0.0 {\n        return Err(\"nominal_annual_interest_rate must be >= 0\");\n    }\n    if number_of_compounding_periods <= 0.0 {\n        return Err(\"number_of_compounding_periods must be > 0\");\n    }\n    Ok(\n        principal\n            * ((1.0 + nominal_annual_interest_rate).powf(number_of_compounding_periods) - 1.0),\n    )\n}\n\n/// Calculates interest using the Annual Percentage Rate (APR), compounded daily.\n///\n/// Converts the APR to a daily rate and compounds over the equivalent number\n/// of days, giving a more accurate real-world figure than simple annual compounding.\n///\n/// # Arguments\n/// * `principal`                      - The initial amount of money (must be > 0)\n/// * `nominal_annual_percentage_rate` - The APR as a decimal (must be >= 0)\n/// * `number_of_years`                - The loan or investment duration in years (must be > 0)\n///\n/// # Errors\n/// Returns an `Err(&'static str)` if any argument is out of range.\npub fn apr_interest(\n    principal: f64,\n    nominal_annual_percentage_rate: f64,\n    number_of_years: f64,\n) -> Result<f64, &'static str> {\n    if principal <= 0.0 {\n        return Err(\"principal must be > 0\");\n    }\n    if nominal_annual_percentage_rate < 0.0 {\n        return Err(\"nominal_annual_percentage_rate must be >= 0\");\n    }\n    if number_of_years <= 0.0 {\n        return Err(\"number_of_years must be > 0\");\n    }\n    // Divide annual rate by 365 to obtain the daily rate\n    // Multiply years by 365 to obtain the total number of daily compounding periods\n    compound_interest(\n        principal,\n        nominal_annual_percentage_rate / 365.0,\n        number_of_years * 365.0,\n    )\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_simple_interest() {\n        const EPSILON: f64 = 1e-9;\n\n        // Standard cases\n        assert!((simple_interest(18000.0, 0.06, 3.0).unwrap() - 3240.0).abs() < EPSILON);\n        assert!((simple_interest(0.5, 0.06, 3.0).unwrap() - 0.09).abs() < EPSILON);\n        assert!((simple_interest(18000.0, 0.01, 10.0).unwrap() - 1800.0).abs() < EPSILON);\n        assert!((simple_interest(5500.0, 0.01, 100.0).unwrap() - 5500.0).abs() < EPSILON);\n\n        // Zero interest rate yields zero interest\n        assert!((simple_interest(18000.0, 0.0, 3.0).unwrap() - 0.0).abs() < EPSILON);\n\n        // Error cases\n        assert_eq!(\n            simple_interest(-10000.0, 0.06, 3.0),\n            Err(\"principal must be > 0\")\n        );\n        assert_eq!(\n            simple_interest(0.0, 0.06, 3.0),\n            Err(\"principal must be > 0\")\n        );\n        assert_eq!(\n            simple_interest(10000.0, -0.06, 3.0),\n            Err(\"daily_interest_rate must be >= 0\")\n        );\n        assert_eq!(\n            simple_interest(5500.0, 0.01, -5.0),\n            Err(\"days_between_payments must be > 0\")\n        );\n        assert_eq!(\n            simple_interest(5500.0, 0.01, 0.0),\n            Err(\"days_between_payments must be > 0\")\n        );\n    }\n\n    #[test]\n    fn test_compound_interest() {\n        const EPSILON: f64 = 1e-9;\n\n        // Standard cases\n        assert!(\n            (compound_interest(10000.0, 0.05, 3.0).unwrap() - 1_576.250_000_000_001_4).abs()\n                < EPSILON\n        );\n        assert!(\n            (compound_interest(10000.0, 0.05, 1.0).unwrap() - 500.000_000_000_000_45).abs()\n                < EPSILON\n        );\n        assert!(\n            (compound_interest(0.5, 0.05, 3.0).unwrap() - 0.078_812_500_000_000_06).abs() < EPSILON\n        );\n\n        // Zero interest rate yields zero interest\n        assert!((compound_interest(10000.0, 0.0, 5.0).unwrap() - 0.0).abs() < EPSILON);\n\n        // Error cases\n        assert_eq!(\n            compound_interest(-5500.0, 0.01, 5.0),\n            Err(\"principal must be > 0\")\n        );\n        assert_eq!(\n            compound_interest(10000.0, -3.5, 3.0),\n            Err(\"nominal_annual_interest_rate must be >= 0\")\n        );\n        assert_eq!(\n            compound_interest(10000.0, 0.06, -4.0),\n            Err(\"number_of_compounding_periods must be > 0\")\n        );\n    }\n\n    #[test]\n    fn test_apr_interest() {\n        const EPSILON: f64 = 1e-9;\n\n        // Standard cases\n        assert!(\n            (apr_interest(10000.0, 0.05, 3.0).unwrap() - 1_618.223_072_263_547).abs() < EPSILON\n        );\n        assert!(\n            (apr_interest(10000.0, 0.05, 1.0).unwrap() - 512.674_964_674_473_2).abs() < EPSILON\n        );\n        assert!((apr_interest(0.5, 0.05, 3.0).unwrap() - 0.080_911_153_613_177_36).abs() < EPSILON);\n\n        // Zero interest rate yields zero interest\n        assert!((apr_interest(10000.0, 0.0, 5.0).unwrap() - 0.0).abs() < EPSILON);\n\n        // Error cases\n        assert_eq!(\n            apr_interest(-5500.0, 0.01, 5.0),\n            Err(\"principal must be > 0\")\n        );\n        assert_eq!(\n            apr_interest(10000.0, -3.5, 3.0),\n            Err(\"nominal_annual_percentage_rate must be >= 0\")\n        );\n        assert_eq!(\n            apr_interest(10000.0, 0.06, -4.0),\n            Err(\"number_of_years must be > 0\")\n        );\n    }\n}\n"
  },
  {
    "path": "src/financial/mod.rs",
    "content": "mod depreciation;\nmod equated_monthly_installments;\nmod exponential_moving_average;\nmod finance_ratios;\nmod interest;\nmod npv;\nmod npv_sensitivity;\nmod payback;\nmod present_value;\nmod treynor_ratio;\n\npub use self::depreciation::{\n    diminishing_balance_depreciation, double_declining_balance_depreciation,\n    straight_line_depreciation, sum_of_years_digits_depreciation, units_of_production_depreciation,\n};\npub use self::equated_monthly_installments::equated_monthly_installments;\npub use self::exponential_moving_average::exponential_moving_average;\npub use self::finance_ratios::{\n    debt_to_equity, earnings_per_sale, gross_profit_margin, return_on_investment,\n};\npub use self::interest::{apr_interest, compound_interest, simple_interest};\npub use self::npv::npv;\npub use self::npv_sensitivity::npv_sensitivity;\npub use self::payback::payback;\npub use self::present_value::present_value;\npub use self::treynor_ratio::treynor_ratio;\n"
  },
  {
    "path": "src/financial/npv.rs",
    "content": "/// Calculates Net Present Value given a vector of cash flows and a discount rate.\n/// cash_flows: Vector of f64 representing cash flows for each period.\n/// rate: Discount rate as an f64 (e.g., 0.05 for 5%)\n\npub fn npv(cash_flows: &[f64], rate: f64) -> f64 {\n    cash_flows\n        .iter()\n        .enumerate()\n        .map(|(t, &cf)| cf / (1.00 + rate).powi(t as i32))\n        .sum()\n}\n\n// tests\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_npv_basic() {\n        let cash_flows = vec![-1000.0, 300.0, 400.0, -50.0];\n        let rate = 0.10;\n        let result = npv(&cash_flows, rate);\n        // Calculated value ≈ -434.25\n        assert!((result - (-434.25)).abs() < 0.05); // Allow small margin of error\n    }\n\n    #[test]\n    fn test_npv_zero_rate() {\n        let cash_flows = vec![100.0, 200.0, -50.0];\n        let rate = 0.0;\n        let result = npv(&cash_flows, rate);\n        assert!((result - 250.0).abs() < 0.05);\n    }\n\n    #[test]\n    fn test_npv_empty() {\n        // For empty cash flows: NPV should be 0\n        let cash_flows: Vec<f64> = vec![];\n        let rate = 0.05;\n        let result = npv(&cash_flows, rate);\n        assert_eq!(result, 0.0);\n    }\n}\n"
  },
  {
    "path": "src/financial/npv_sensitivity.rs",
    "content": "/// Computes the Net Present Value (NPV) of a cash flow series\n/// at multiple discount rates to show sensitivity.\n///\n/// # Inputs:\n/// - `cash_flows`: A slice of cash flows, where each entry is a period value\n///   e.g., year 0 is initial investment, year 1+ are returns or costs\n/// - `discount_rates`: A slice of discount rates, e.g. `[0.05, 0.10, 0.20]`,\n///   where each rate is evaluated independently.\n///\n/// # Output:\n/// - Returns a vector of NPV values, each corresponding to a rate in `discount_rates`.\n///   For example, output is `[npv_rate1, npv_rate2, ...]`.\n\npub fn npv_sensitivity(cash_flows: &[f64], discount_rates: &[f64]) -> Vec<f64> {\n    discount_rates\n        .iter()\n        .cloned()\n        .map(|rate| {\n            cash_flows\n                .iter()\n                .enumerate()\n                .map(|(t, &cf)| cf / (1.0 + rate).powi(t as i32))\n                .sum()\n        })\n        .collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn test_npv_sensitivity() {\n        let cashflows = [-1000.00, 400.00, 400.00, 400.00];\n        let rates = [0.05, 0.1, 0.2];\n        let expected = [89.30, -5.26, -157.41];\n        let out = npv_sensitivity(&cashflows, &rates);\n        assert_eq!(out.len(), 3);\n        // value check\n        for (o, e) in out.iter().zip(expected.iter()) {\n            assert!((o - e).abs() < 0.1);\n        }\n    }\n}\n"
  },
  {
    "path": "src/financial/payback.rs",
    "content": "/// Returns the payback period in years\n/// If investment is not paid back, returns None.\n\npub fn payback(cash_flow: &[f64]) -> Option<usize> {\n    let mut total = 0.00;\n    for (year, &cf) in cash_flow.iter().enumerate() {\n        total += cf;\n        if total >= 0.00 {\n            return Some(year);\n        }\n    }\n    None\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_payback() {\n        let cash_flows = vec![-1000.0, 300.0, 400.0, 500.0];\n        assert_eq!(payback(&cash_flows), Some(3)); // paid back in year 3\n    }\n\n    #[test]\n    fn test_no_payback() {\n        let cash_flows = vec![-1000.0, 100.0, 100.0, 100.0];\n        assert_eq!(payback(&cash_flows), None); // never paid back\n    }\n}\n"
  },
  {
    "path": "src/financial/present_value.rs",
    "content": "/// In economics and finance, present value (PV), also known as present discounted value,\n/// is the value of an expected income stream determined as of the date of valuation.\n///\n/// -> Wikipedia reference: https://en.wikipedia.org/wiki/Present_value\n\n#[derive(PartialEq, Eq, Debug)]\npub enum PresentValueError {\n    NegetiveDiscount,\n    EmptyCashFlow,\n}\n\npub fn present_value(discount_rate: f64, cash_flows: Vec<f64>) -> Result<f64, PresentValueError> {\n    if discount_rate < 0.0 {\n        return Err(PresentValueError::NegetiveDiscount);\n    }\n    if cash_flows.is_empty() {\n        return Err(PresentValueError::EmptyCashFlow);\n    }\n\n    let present_value = cash_flows\n        .iter()\n        .enumerate()\n        .map(|(i, &cash_flow)| cash_flow / (1.0 + discount_rate).powi(i as i32))\n        .sum::<f64>();\n\n    Ok(round(present_value))\n}\n\nfn round(value: f64) -> f64 {\n    (value * 100.0).round() / 100.0\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_present_value {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let ((discount_rate,cash_flows), expected) = $inputs;\n                    assert_eq!(present_value(discount_rate,cash_flows).unwrap(), expected);\n                }\n            )*\n        }\n    }\n\n    macro_rules! test_present_value_Err {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let ((discount_rate,cash_flows), expected) = $inputs;\n                    assert_eq!(present_value(discount_rate,cash_flows).unwrap_err(), expected);\n                }\n            )*\n        }\n    }\n\n    macro_rules! test_round {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $inputs;\n                    assert_eq!(round(input), expected);\n                }\n            )*\n        }\n    }\n\n    test_present_value! {\n        general_inputs1:((0.13, vec![10.0, 20.70, -293.0, 297.0]),4.69),\n        general_inputs2:((0.07, vec![-109129.39, 30923.23, 15098.93, 29734.0, 39.0]),-42739.63),\n        general_inputs3:((0.07, vec![109129.39, 30923.23, 15098.93, 29734.0, 39.0]), 175519.15),\n        zero_input:((0.0, vec![109129.39, 30923.23, 15098.93, 29734.0, 39.0]),  184924.55),\n\n    }\n\n    test_present_value_Err! {\n        negative_discount_rate:((-1.0, vec![10.0, 20.70, -293.0, 297.0]), PresentValueError::NegetiveDiscount),\n        empty_cash_flow:((1.0, vec![]), PresentValueError::EmptyCashFlow),\n\n    }\n    test_round! {\n            test1:(0.55434,  0.55),\n            test2:(10.453,  10.45),\n            test3:(1111_f64,  1111_f64),\n    }\n}\n"
  },
  {
    "path": "src/financial/treynor_ratio.rs",
    "content": "/// Calculates the Treynor Ratio for a portfolio.\n///\n/// # Inputs\n/// - `portfolio_return`: Portfolio return\n/// - `risk_free_rate`: Risk-free rate\n/// - `beta`: Portfolio beta\n/// where Beta is a financial metric that measures the systematic risk of a security or portfolio compared to the overall market.\n///\n/// # Output\n/// - Returns excess return per unit of market risk\npub fn treynor_ratio(portfolio_return: f64, risk_free_rate: f64, beta: f64) -> f64 {\n    if beta == 0.0 {\n        f64::NAN\n    } else {\n        (portfolio_return - risk_free_rate) / beta\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_treynor_ratio() {\n        // for portfolio_return = 0.10, risk_free_rate = 0.05, beta = 1.5\n        // expected result: (0.10 - 0.05) / 1.5 = 0.033333...\n        assert!((treynor_ratio(0.10, 0.05, 1.50) - 0.03333).abs() < 0.01);\n    }\n\n    #[test]\n    fn test_treynor_ratio_empty_beta() {\n        // test for zero beta (undefined ratio)\n        assert!(treynor_ratio(0.10, 0.05, 0.00).is_nan());\n    }\n}\n"
  },
  {
    "path": "src/general/convex_hull.rs",
    "content": "use std::cmp::Ordering::Equal;\n\nfn sort_by_min_angle(pts: &[(f64, f64)], min: &(f64, f64)) -> Vec<(f64, f64)> {\n    let mut points: Vec<(f64, f64, (f64, f64))> = pts\n        .iter()\n        .map(|x| {\n            (\n                (x.1 - min.1).atan2(x.0 - min.0),\n                // angle\n                (x.1 - min.1).hypot(x.0 - min.0),\n                // distance (we want the closest to be first)\n                *x,\n            )\n        })\n        .collect();\n    points.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Equal));\n    points.into_iter().map(|x| x.2).collect()\n}\n\n// calculates the z coordinate of the vector product of vectors ab and ac\nfn calc_z_coord_vector_product(a: &(f64, f64), b: &(f64, f64), c: &(f64, f64)) -> f64 {\n    (b.0 - a.0) * (c.1 - a.1) - (c.0 - a.0) * (b.1 - a.1)\n}\n\n/*\n    If three points are aligned and are part of the convex hull then the three are kept.\n    If one doesn't want to keep those points, it is easy to iterate the answer and remove them.\n\n    The first point is the one with the lowest y-coordinate and the lowest x-coordinate.\n    Points are then given counter-clockwise, and the closest one is given first if needed.\n*/\npub fn convex_hull_graham(pts: &[(f64, f64)]) -> Vec<(f64, f64)> {\n    if pts.is_empty() {\n        return vec![];\n    }\n\n    let mut stack: Vec<(f64, f64)> = vec![];\n    let min = pts\n        .iter()\n        .min_by(|a, b| {\n            let ord = a.1.partial_cmp(&b.1).unwrap_or(Equal);\n            match ord {\n                Equal => a.0.partial_cmp(&b.0).unwrap_or(Equal),\n                o => o,\n            }\n        })\n        .unwrap();\n    let points = sort_by_min_angle(pts, min);\n\n    if points.len() <= 3 {\n        return points;\n    }\n\n    for point in points {\n        while stack.len() > 1\n            && calc_z_coord_vector_product(&stack[stack.len() - 2], &stack[stack.len() - 1], &point)\n                < 0.\n        {\n            stack.pop();\n        }\n        stack.push(point);\n    }\n\n    stack\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn empty() {\n        assert_eq!(convex_hull_graham(&[]), vec![]);\n    }\n\n    #[test]\n    fn not_enough_points() {\n        let list = vec![(0f64, 0f64)];\n        assert_eq!(convex_hull_graham(&list), list);\n    }\n\n    #[test]\n    fn not_enough_points1() {\n        let list = vec![(2f64, 2f64), (1f64, 1f64), (0f64, 0f64)];\n        let ans = vec![(0f64, 0f64), (1f64, 1f64), (2f64, 2f64)];\n        assert_eq!(convex_hull_graham(&list), ans);\n    }\n\n    #[test]\n    fn not_enough_points2() {\n        let list = vec![(2f64, 2f64), (1f64, 2f64), (0f64, 0f64)];\n        let ans = vec![(0f64, 0f64), (2f64, 2f64), (1f64, 2f64)];\n        assert_eq!(convex_hull_graham(&list), ans);\n    }\n\n    #[test]\n    // from https://codegolf.stackexchange.com/questions/11035/find-the-convex-hull-of-a-set-of-2d-points\n    fn lots_of_points() {\n        let list = vec![\n            (4.4, 14.),\n            (6.7, 15.25),\n            (6.9, 12.8),\n            (2.1, 11.1),\n            (9.5, 14.9),\n            (13.2, 11.9),\n            (10.3, 12.3),\n            (6.8, 9.5),\n            (3.3, 7.7),\n            (0.6, 5.1),\n            (5.3, 2.4),\n            (8.45, 4.7),\n            (11.5, 9.6),\n            (13.8, 7.3),\n            (12.9, 3.1),\n            (11., 1.1),\n        ];\n        let ans = vec![\n            (11., 1.1),\n            (12.9, 3.1),\n            (13.8, 7.3),\n            (13.2, 11.9),\n            (9.5, 14.9),\n            (6.7, 15.25),\n            (4.4, 14.),\n            (2.1, 11.1),\n            (0.6, 5.1),\n            (5.3, 2.4),\n        ];\n\n        assert_eq!(convex_hull_graham(&list), ans);\n    }\n\n    #[test]\n    // from https://codegolf.stackexchange.com/questions/11035/find-the-convex-hull-of-a-set-of-2d-points\n    fn lots_of_points2() {\n        let list = vec![\n            (1., 0.),\n            (1., 1.),\n            (1., -1.),\n            (0.68957, 0.283647),\n            (0.909487, 0.644276),\n            (0.0361877, 0.803816),\n            (0.583004, 0.91555),\n            (-0.748169, 0.210483),\n            (-0.553528, -0.967036),\n            (0.316709, -0.153861),\n            (-0.79267, 0.585945),\n            (-0.700164, -0.750994),\n            (0.452273, -0.604434),\n            (-0.79134, -0.249902),\n            (-0.594918, -0.397574),\n            (-0.547371, -0.434041),\n            (0.958132, -0.499614),\n            (0.039941, 0.0990732),\n            (-0.891471, -0.464943),\n            (0.513187, -0.457062),\n            (-0.930053, 0.60341),\n            (0.656995, 0.854205),\n        ];\n        let ans = vec![\n            (1., -1.),\n            (1., 0.),\n            (1., 1.),\n            (0.583004, 0.91555),\n            (0.0361877, 0.803816),\n            (-0.930053, 0.60341),\n            (-0.891471, -0.464943),\n            (-0.700164, -0.750994),\n            (-0.553528, -0.967036),\n        ];\n\n        assert_eq!(convex_hull_graham(&list), ans);\n    }\n}\n"
  },
  {
    "path": "src/general/fisher_yates_shuffle.rs",
    "content": "use std::time::{SystemTime, UNIX_EPOCH};\n\nuse crate::math::PCG32;\n\nconst DEFAULT: u64 = 4294967296;\n\nfn gen_range(range: usize, generator: &mut PCG32) -> usize {\n    generator.get_u64() as usize % range\n}\n\npub fn fisher_yates_shuffle(array: &mut [i32]) {\n    let seed = match SystemTime::now().duration_since(UNIX_EPOCH) {\n        Ok(duration) => duration.as_millis() as u64,\n        Err(_) => DEFAULT,\n    };\n\n    let mut random_generator = PCG32::new_default(seed);\n\n    let len = array.len();\n\n    for i in 0..(len - 2) {\n        let r = gen_range(len - i, &mut random_generator);\n        array.swap(i, i + r);\n    }\n}\n"
  },
  {
    "path": "src/general/genetic.rs",
    "content": "use std::cmp::Ordering;\nuse std::collections::BTreeSet;\nuse std::fmt::Debug;\n\n/// The goal is to showcase how Genetic algorithms generically work\n/// See: https://en.wikipedia.org/wiki/Genetic_algorithm for concepts\n\n/// This is the definition of a Chromosome for a genetic algorithm\n/// We can picture this as \"one contending solution to our problem\"\n/// It is generic over:\n/// * Eval, which could be a float, or any other totally ordered type, so that we can rank solutions to our problem\n/// * Rng: a random number generator (could be thread rng, etc.)\npub trait Chromosome<Rng: rand::RngExt, Eval> {\n    /// Mutates this Chromosome, changing its genes\n    fn mutate(&mut self, rng: &mut Rng);\n\n    /// Mixes this chromosome with another one\n    fn crossover(&self, other: &Self, rng: &mut Rng) -> Self;\n\n    /// How well this chromosome fits the problem we're trying to solve\n    /// **The smaller the better it fits** (we could use abs(... - expected_value) for instance\n    fn fitness(&self) -> Eval;\n}\n\npub trait SelectionStrategy<Rng: rand::RngExt> {\n    fn new(rng: Rng) -> Self;\n\n    /// Selects a portion of the population for reproduction\n    /// Could be totally random ones or the ones that fit best, etc.\n    /// This assumes the population is sorted by how it fits the solution (the first the better)\n    fn select<'a, Eval: Into<f64>, C: Chromosome<Rng, Eval>>(\n        &mut self,\n        population: &'a [C],\n    ) -> (&'a C, &'a C);\n}\n\n/// A roulette wheel selection strategy\n/// https://en.wikipedia.org/wiki/Fitness_proportionate_selection\n#[allow(dead_code)]\npub struct RouletteWheel<Rng: rand::RngExt> {\n    rng: Rng,\n}\nimpl<Rng: rand::RngExt> SelectionStrategy<Rng> for RouletteWheel<Rng> {\n    fn new(rng: Rng) -> Self {\n        Self { rng }\n    }\n\n    fn select<'a, Eval: Into<f64>, C: Chromosome<Rng, Eval>>(\n        &mut self,\n        population: &'a [C],\n    ) -> (&'a C, &'a C) {\n        // We will assign a probability for every item in the population, based on its proportion towards the sum of all fitness\n        // This would work well for an increasing fitness function, but not in our case of a fitness function for which \"lower is better\"\n        // We thus need to take the reciprocal\n        let mut parents = Vec::with_capacity(2);\n        let fitnesses: Vec<f64> = population\n            .iter()\n            .filter_map(|individual| {\n                let fitness = individual.fitness().into();\n                if individual.fitness().into() == 0.0 {\n                    parents.push(individual);\n                    None\n                } else {\n                    Some(1.0 / fitness)\n                }\n            })\n            .collect();\n        if parents.len() == 2 {\n            return (parents[0], parents[1]);\n        }\n        let sum: f64 = fitnesses.iter().sum();\n        let mut spin = self.rng.random_range(0.0..=sum);\n        for individual in population {\n            let fitness: f64 = individual.fitness().into();\n            if spin <= fitness {\n                parents.push(individual);\n                if parents.len() == 2 {\n                    return (parents[0], parents[1]);\n                }\n            } else {\n                spin -= fitness;\n            }\n        }\n        panic!(\"Could not select parents\");\n    }\n}\n\n#[allow(dead_code)]\npub struct Tournament<const K: usize, Rng: rand::RngExt> {\n    rng: Rng,\n}\nimpl<const K: usize, Rng: rand::RngExt> SelectionStrategy<Rng> for Tournament<K, Rng> {\n    fn new(rng: Rng) -> Self {\n        Self { rng }\n    }\n\n    fn select<'a, Eval, C: Chromosome<Rng, Eval>>(\n        &mut self,\n        population: &'a [C],\n    ) -> (&'a C, &'a C) {\n        if K < 2 {\n            panic!(\"K must be > 2\");\n        }\n        // This strategy is defined as the following: pick K chromosomes randomly, use the 2 that fits the best\n        // We assume the population is sorted\n        // This means we can draw K random (distinct) numbers between (0..population.len()) and return the chromosomes at the 2 lowest indices\n        let mut picked_indices = BTreeSet::new(); // will keep indices ordered\n        while picked_indices.len() < K {\n            picked_indices.insert(self.rng.random_range(0..population.len()));\n        }\n        let mut iter = picked_indices.into_iter();\n        (\n            &population[iter.next().unwrap()],\n            &population[iter.next().unwrap()],\n        )\n    }\n}\n\ntype Comparator<T> = Box<dyn FnMut(&T, &T) -> Ordering>;\npub struct GeneticAlgorithm<\n    Rng: rand::RngExt,\n    Eval: PartialOrd,\n    C: Chromosome<Rng, Eval>,\n    Selection: SelectionStrategy<Rng>,\n> {\n    rng: Rng, // will be used to draw random numbers for initial population, mutations and crossovers\n    population: Vec<C>, // the set of random solutions (chromosomes)\n    threshold: Eval, // Any chromosome fitting over this threshold is considered a valid solution\n    max_generations: usize, // So that we don't loop infinitely\n    mutation_chance: f64, // what's the probability a chromosome will mutate\n    crossover_chance: f64, // what's the probability two chromosomes will cross-over and give birth to a new chromosome\n    compare: Comparator<Eval>,\n    selection: Selection, // how we will select parent chromosomes for crossing over, see `SelectionStrategy`\n}\n\npub struct GenericAlgorithmParams {\n    max_generations: usize,\n    mutation_chance: f64,\n    crossover_chance: f64,\n}\n\nimpl<\n        Rng: rand::RngExt,\n        Eval: Into<f64> + PartialOrd + Debug,\n        C: Chromosome<Rng, Eval> + Clone + Debug,\n        Selection: SelectionStrategy<Rng>,\n    > GeneticAlgorithm<Rng, Eval, C, Selection>\n{\n    pub fn init(\n        rng: Rng,\n        population: Vec<C>,\n        threshold: Eval,\n        params: GenericAlgorithmParams,\n        compare: Comparator<Eval>,\n        selection: Selection,\n    ) -> Self {\n        let GenericAlgorithmParams {\n            max_generations,\n            mutation_chance,\n            crossover_chance,\n        } = params;\n        Self {\n            rng,\n            population,\n            threshold,\n            max_generations,\n            mutation_chance,\n            crossover_chance,\n            compare,\n            selection,\n        }\n    }\n\n    pub fn solve(&mut self) -> Option<C> {\n        let mut generations = 1; // 1st generation is our initial population\n        while generations <= self.max_generations {\n            // 1. Sort the population by fitness score, remember: the lower the better (so natural ordering)\n            self.population\n                .sort_by(|c1: &C, c2: &C| (self.compare)(&c1.fitness(), &c2.fitness()));\n\n            // 2. Stop condition: we might have found a good solution\n            if let Some(solution) = self.population.first() {\n                if solution.fitness() <= self.threshold {\n                    return Some(solution).cloned();\n                }\n            }\n\n            // 3. Apply random mutations to the whole population\n            for chromosome in self.population.iter_mut() {\n                if self.rng.random::<f64>() <= self.mutation_chance {\n                    chromosome.mutate(&mut self.rng);\n                }\n            }\n            // 4. Select parents that will be mating to create new chromosomes\n            let mut new_population = Vec::with_capacity(self.population.len() + 1);\n            while new_population.len() < self.population.len() {\n                let (p1, p2) = self.selection.select(&self.population);\n                if self.rng.random::<f64>() <= self.crossover_chance {\n                    let child = p1.crossover(p2, &mut self.rng);\n                    new_population.push(child);\n                } else {\n                    // keep parents\n                    new_population.extend([p1.clone(), p2.clone()]);\n                }\n            }\n            if new_population.len() > self.population.len() {\n                // We might have added 2 parents\n                new_population.pop();\n            }\n            self.population = new_population;\n            // 5. Rinse & Repeat until we find a proper solution or we reach the maximum number of generations\n            generations += 1;\n        }\n        None\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::general::genetic::{\n        Chromosome, GenericAlgorithmParams, GeneticAlgorithm, RouletteWheel, SelectionStrategy,\n        Tournament,\n    };\n    use rand::rngs::ThreadRng;\n    use rand::{rng, RngExt};\n    use std::collections::HashMap;\n    use std::fmt::{Debug, Formatter};\n    use std::ops::RangeInclusive;\n\n    #[test]\n    #[ignore] // Too long and not deterministic enough to be part of CI, more of an example than a test\n    fn find_secret() {\n        let chars = 'a'..='z';\n        let secret = \"thisistopsecret\".to_owned();\n        // Note: we'll pick genes (a, b, c) in the range -10, 10\n        #[derive(Clone)]\n        struct TestString {\n            chars: RangeInclusive<char>,\n            secret: String,\n            genes: Vec<char>,\n        }\n        impl TestString {\n            fn new(rng: &mut ThreadRng, secret: String, chars: RangeInclusive<char>) -> Self {\n                let current = (0..secret.len())\n                    .map(|_| rng.random_range(chars.clone()))\n                    .collect::<Vec<_>>();\n\n                Self {\n                    chars,\n                    secret,\n                    genes: current,\n                }\n            }\n        }\n        impl Debug for TestString {\n            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n                f.write_str(&self.genes.iter().collect::<String>())\n            }\n        }\n        impl Chromosome<ThreadRng, i32> for TestString {\n            fn mutate(&mut self, rng: &mut ThreadRng) {\n                // let's assume mutations happen completely randomly, one \"gene\" at a time (i.e. one char at a time)\n                let gene_idx = rng.random_range(0..self.secret.len());\n                let new_char = rng.random_range(self.chars.clone());\n                self.genes[gene_idx] = new_char;\n            }\n\n            fn crossover(&self, other: &Self, rng: &mut ThreadRng) -> Self {\n                // Let's not assume anything here, simply mixing random genes from both parents\n                let genes = (0..self.secret.len())\n                    .map(|idx| {\n                        if rng.random_bool(0.5) {\n                            // pick gene from self\n                            self.genes[idx]\n                        } else {\n                            // pick gene from other parent\n                            other.genes[idx]\n                        }\n                    })\n                    .collect();\n                Self {\n                    chars: self.chars.clone(),\n                    secret: self.secret.clone(),\n                    genes,\n                }\n            }\n\n            fn fitness(&self) -> i32 {\n                // We are just counting how many chars are distinct from secret\n                self.genes\n                    .iter()\n                    .zip(self.secret.chars())\n                    .filter(|(char, expected)| expected != *char)\n                    .count() as i32\n            }\n        }\n        let mut rng = rng();\n        let pop_count = 1_000;\n        let mut population = Vec::with_capacity(pop_count);\n        for _ in 0..pop_count {\n            population.push(TestString::new(&mut rng, secret.clone(), chars.clone()));\n        }\n        let selection: Tournament<100, ThreadRng> = Tournament::new(rng.clone());\n        let params = GenericAlgorithmParams {\n            max_generations: 100,\n            mutation_chance: 0.2,\n            crossover_chance: 0.4,\n        };\n        let mut solver =\n            GeneticAlgorithm::init(rng, population, 0, params, Box::new(i32::cmp), selection);\n        let res = solver.solve();\n        assert!(res.is_some());\n        assert_eq!(res.unwrap().genes, secret.chars().collect::<Vec<_>>())\n    }\n\n    #[test]\n    #[ignore] // Too long and not deterministic enough to be part of CI, more of an example than a test\n    fn solve_mastermind() {\n        #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]\n        enum ColoredPeg {\n            Red,\n            Yellow,\n            Green,\n            Blue,\n            White,\n            Black,\n        }\n        struct GuessAnswer {\n            right_pos: i32, // right color at the right pos\n            wrong_pos: i32, // right color, but at wrong pos\n        }\n        #[derive(Clone, Debug)]\n        struct CodeMaker {\n            // the player coming up with a secret code\n            code: [ColoredPeg; 4],\n            count_by_color: HashMap<ColoredPeg, usize>,\n        }\n        impl CodeMaker {\n            fn new(code: [ColoredPeg; 4]) -> Self {\n                let mut count_by_color = HashMap::with_capacity(4);\n                for peg in &code {\n                    *count_by_color.entry(*peg).or_insert(0) += 1;\n                }\n                Self {\n                    code,\n                    count_by_color,\n                }\n            }\n            fn eval(&self, guess: &[ColoredPeg; 4]) -> GuessAnswer {\n                let mut right_pos = 0;\n                let mut wrong_pos = 0;\n                let mut idx_by_colors = self.count_by_color.clone();\n                for (idx, color) in guess.iter().enumerate() {\n                    if self.code[idx] == *color {\n                        right_pos += 1;\n                        let count = idx_by_colors.get_mut(color).unwrap();\n                        *count -= 1; // don't reuse to say \"right color but wrong pos\"\n                        if *count == 0 {\n                            idx_by_colors.remove(color);\n                        }\n                    }\n                }\n                for (idx, color) in guess.iter().enumerate() {\n                    if self.code[idx] != *color {\n                        // try to use another color\n                        if let Some(count) = idx_by_colors.get_mut(color) {\n                            *count -= 1;\n                            if *count == 0 {\n                                idx_by_colors.remove(color);\n                            }\n                            wrong_pos += 1;\n                        }\n                    }\n                }\n                GuessAnswer {\n                    right_pos,\n                    wrong_pos,\n                }\n            }\n        }\n\n        #[derive(Clone)]\n        struct CodeBreaker {\n            maker: CodeMaker, // so that we can ask the code maker if our guess is good or not\n            guess: [ColoredPeg; 4],\n        }\n        impl Debug for CodeBreaker {\n            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n                f.write_str(format!(\"{:?}\", self.guess).as_str())\n            }\n        }\n        fn random_color(rng: &mut ThreadRng) -> ColoredPeg {\n            match rng.random_range(0..=5) {\n                0 => ColoredPeg::Red,\n                1 => ColoredPeg::Yellow,\n                2 => ColoredPeg::Green,\n                3 => ColoredPeg::Blue,\n                4 => ColoredPeg::White,\n                _ => ColoredPeg::Black,\n            }\n        }\n        fn random_guess(rng: &mut ThreadRng) -> [ColoredPeg; 4] {\n            std::array::from_fn(|_| random_color(rng))\n        }\n        impl Chromosome<ThreadRng, i32> for CodeBreaker {\n            fn mutate(&mut self, rng: &mut ThreadRng) {\n                // change one random color\n                let idx = rng.random_range(0..4);\n                self.guess[idx] = random_color(rng);\n            }\n\n            fn crossover(&self, other: &Self, rng: &mut ThreadRng) -> Self {\n                Self {\n                    maker: self.maker.clone(),\n                    guess: std::array::from_fn(|i| {\n                        if rng.random::<f64>() < 0.5 {\n                            self.guess[i]\n                        } else {\n                            other.guess[i]\n                        }\n                    }),\n                }\n            }\n\n            fn fitness(&self) -> i32 {\n                // Ask the code maker for the result\n                let answer = self.maker.eval(&self.guess);\n                // Remember: we need to have fitness return 0 if the guess is good, and the higher number we return, the further we are from a proper solution\n                let mut res = 32; // worst case scenario, everything is wrong\n                res -= answer.right_pos * 8; // count 8 points for the right item at the right spot\n                res -= answer.wrong_pos; // count 1 point for having a right color\n                res\n            }\n        }\n        let code = [\n            ColoredPeg::Red,\n            ColoredPeg::Red,\n            ColoredPeg::White,\n            ColoredPeg::Blue,\n        ];\n        let maker = CodeMaker::new(code);\n        let population_count = 10;\n        let params = GenericAlgorithmParams {\n            max_generations: 100,\n            mutation_chance: 0.5,\n            crossover_chance: 0.3,\n        };\n        let mut rng = rng();\n        let mut initial_pop = Vec::with_capacity(population_count);\n        for _ in 0..population_count {\n            initial_pop.push(CodeBreaker {\n                maker: maker.clone(),\n                guess: random_guess(&mut rng),\n            });\n        }\n        let selection = RouletteWheel { rng: rng.clone() };\n        let mut solver =\n            GeneticAlgorithm::init(rng, initial_pop, 0, params, Box::new(i32::cmp), selection);\n        let res = solver.solve();\n        assert!(res.is_some());\n        assert_eq!(code, res.unwrap().guess);\n    }\n}\n"
  },
  {
    "path": "src/general/hanoi.rs",
    "content": "pub fn hanoi(n: i32, from: i32, to: i32, via: i32, moves: &mut Vec<(i32, i32)>) {\n    if n > 0 {\n        hanoi(n - 1, from, via, to, moves);\n        moves.push((from, to));\n        hanoi(n - 1, via, to, from, moves);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn hanoi_simple() {\n        let correct_solution: Vec<(i32, i32)> =\n            vec![(1, 3), (1, 2), (3, 2), (1, 3), (2, 1), (2, 3), (1, 3)];\n        let mut our_solution: Vec<(i32, i32)> = Vec::new();\n        hanoi(3, 1, 3, 2, &mut our_solution);\n        assert_eq!(correct_solution, our_solution);\n    }\n}\n"
  },
  {
    "path": "src/general/huffman_encoding.rs",
    "content": "use std::{\n    cmp::Ordering,\n    collections::{BTreeMap, BinaryHeap},\n};\n\n#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]\npub struct HuffmanValue {\n    // For the `value` to overflow, the sum of frequencies should be bigger\n    // than u64. So we should be safe here\n    /// The encoded value\n    pub value: u64,\n    /// number of bits used (up to 64)\n    pub bits: u32,\n}\n\npub struct HuffmanNode<T> {\n    pub left: Option<Box<HuffmanNode<T>>>,\n    pub right: Option<Box<HuffmanNode<T>>>,\n    pub symbol: Option<T>,\n    pub frequency: u64,\n}\n\nimpl<T> PartialEq for HuffmanNode<T> {\n    fn eq(&self, other: &Self) -> bool {\n        self.frequency == other.frequency\n    }\n}\n\nimpl<T> PartialOrd for HuffmanNode<T> {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl<T> Eq for HuffmanNode<T> {}\n\nimpl<T> Ord for HuffmanNode<T> {\n    fn cmp(&self, other: &Self) -> Ordering {\n        self.frequency.cmp(&other.frequency).reverse()\n    }\n}\n\nimpl<T: Clone + Copy + Ord> HuffmanNode<T> {\n    /// Turn the tree into the map that can be used in encoding\n    pub fn get_alphabet(\n        height: u32,\n        path: u64,\n        node: &HuffmanNode<T>,\n        map: &mut BTreeMap<T, HuffmanValue>,\n    ) {\n        match node.symbol {\n            Some(s) => {\n                map.insert(\n                    s,\n                    HuffmanValue {\n                        value: path,\n                        bits: height,\n                    },\n                );\n            }\n            None => {\n                Self::get_alphabet(height + 1, path, node.left.as_ref().unwrap(), map);\n                Self::get_alphabet(\n                    height + 1,\n                    path | (1 << height),\n                    node.right.as_ref().unwrap(),\n                    map,\n                );\n            }\n        }\n    }\n}\n\npub struct HuffmanDictionary<T> {\n    pub alphabet: BTreeMap<T, HuffmanValue>,\n    pub root: HuffmanNode<T>,\n}\n\nimpl<T: Clone + Copy + Ord> HuffmanDictionary<T> {\n    /// Creates a new Huffman dictionary from alphabet symbols and their frequencies.\n    ///\n    /// Returns `None` if the alphabet is empty.\n    ///\n    /// # Arguments\n    /// * `alphabet` - A slice of tuples containing symbols and their frequencies\n    ///\n    /// # Example\n    /// ```\n    /// # use the_algorithms_rust::general::HuffmanDictionary;\n    /// let freq = vec![('a', 5), ('b', 2), ('c', 1)];\n    /// let dict = HuffmanDictionary::new(&freq).unwrap();\n    ///\n    pub fn new(alphabet: &[(T, u64)]) -> Option<Self> {\n        if alphabet.is_empty() {\n            return None;\n        }\n\n        let mut alph: BTreeMap<T, HuffmanValue> = BTreeMap::new();\n\n        // Special case: single symbol\n        if alphabet.len() == 1 {\n            let (symbol, _freq) = alphabet[0];\n            alph.insert(\n                symbol,\n                HuffmanValue {\n                    value: 0,\n                    bits: 1, // Must use at least 1 bit per symbol\n                },\n            );\n\n            let root = HuffmanNode {\n                left: None,\n                right: None,\n                symbol: Some(symbol),\n                frequency: alphabet[0].1,\n            };\n\n            return Some(HuffmanDictionary {\n                alphabet: alph,\n                root,\n            });\n        }\n\n        let mut queue: BinaryHeap<HuffmanNode<T>> = BinaryHeap::new();\n        for (symbol, freq) in alphabet.iter() {\n            queue.push(HuffmanNode {\n                left: None,\n                right: None,\n                symbol: Some(*symbol),\n                frequency: *freq,\n            });\n        }\n        for _ in 1..alphabet.len() {\n            let left = queue.pop().unwrap();\n            let right = queue.pop().unwrap();\n            let sm_freq = left.frequency + right.frequency;\n            queue.push(HuffmanNode {\n                left: Some(Box::new(left)),\n                right: Some(Box::new(right)),\n                symbol: None,\n                frequency: sm_freq,\n            });\n        }\n        if let Some(root) = queue.pop() {\n            HuffmanNode::get_alphabet(0, 0, &root, &mut alph);\n            Some(HuffmanDictionary {\n                alphabet: alph,\n                root,\n            })\n        } else {\n            None\n        }\n    }\n    pub fn encode(&self, data: &[T]) -> HuffmanEncoding {\n        let mut result = HuffmanEncoding::new();\n        for value in data.iter() {\n            result.add_data(self.alphabet[value]);\n        }\n        result\n    }\n}\npub struct HuffmanEncoding {\n    pub num_bits: u64,\n    pub data: Vec<u64>,\n}\n\nimpl Default for HuffmanEncoding {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl HuffmanEncoding {\n    pub fn new() -> Self {\n        HuffmanEncoding {\n            num_bits: 0,\n            data: vec![0],\n        }\n    }\n    #[inline]\n    pub fn add_data(&mut self, data: HuffmanValue) {\n        let shift = (self.num_bits & 63) as u32;\n        let val = data.value;\n        *self.data.last_mut().unwrap() |= val.wrapping_shl(shift);\n        if (shift + data.bits) >= 64 {\n            self.data.push(val.wrapping_shr(64 - shift));\n        }\n        self.num_bits += data.bits as u64;\n    }\n\n    #[inline]\n    fn get_bit(&self, pos: u64) -> bool {\n        (self.data[(pos >> 6) as usize] & (1 << (pos & 63))) != 0\n    }\n\n    /// In case the encoding is invalid, `None` is returned\n    pub fn decode<T: Clone + Copy + Ord>(&self, dict: &HuffmanDictionary<T>) -> Option<Vec<T>> {\n        // Handle empty encoding\n        if self.num_bits == 0 {\n            return Some(vec![]);\n        }\n\n        // Special case: single symbol in dictionary\n        if dict.alphabet.len() == 1 {\n            //all bits represent the same symbol\n            let symbol = dict.alphabet.keys().next()?;\n            let result = vec![*symbol; self.num_bits as usize];\n            return Some(result);\n        }\n\n        // Normal case: multiple symbols\n        let mut state = &dict.root;\n        let mut result: Vec<T> = vec![];\n\n        for i in 0..self.num_bits {\n            if let Some(symbol) = state.symbol {\n                result.push(symbol);\n                state = &dict.root;\n            }\n            state = if self.get_bit(i) {\n                state.right.as_ref()?\n            } else {\n                state.left.as_ref()?\n            }\n        }\n\n        // Check if we ended on a symbol\n        if self.num_bits > 0 {\n            result.push(state.symbol?);\n        }\n\n        Some(result)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    fn get_frequency(bytes: &[u8]) -> Vec<(u8, u64)> {\n        let mut cnts: Vec<u64> = vec![0; 256];\n        for &b in bytes.iter() {\n            cnts[b as usize] += 1;\n        }\n        let mut result = vec![];\n        cnts.iter()\n            .enumerate()\n            .filter(|(_, &v)| v > 0)\n            .for_each(|(b, &cnt)| result.push((b as u8, cnt)));\n        result\n    }\n\n    #[test]\n    fn empty_text() {\n        let text = \"\";\n        let bytes = text.as_bytes();\n        let freq = get_frequency(bytes);\n        let dict = HuffmanDictionary::new(&freq);\n        assert!(dict.is_none());\n    }\n\n    #[test]\n    fn one_symbol_text() {\n        let text = \"aaaa\";\n        let bytes = text.as_bytes();\n        let freq = get_frequency(bytes);\n        let dict = HuffmanDictionary::new(&freq).unwrap();\n        let encoded = dict.encode(bytes);\n        assert_eq!(encoded.num_bits, 4);\n        let decoded = encoded.decode(&dict).unwrap();\n        assert_eq!(decoded, bytes);\n    }\n\n    #[test]\n    fn test_decode_empty_encoding_struct() {\n        // Create a minimal but VALID HuffmanDictionary.\n        // This is required because decode() expects a dictionary, even though\n        // the content of the dictionary doesn't matter when num_bits == 0.\n        let freq = vec![(b'a', 1)];\n        let dict = HuffmanDictionary::new(&freq).unwrap();\n\n        // Manually create the target state: an encoding with 0 bits.\n        let empty_encoding = HuffmanEncoding {\n            data: vec![],\n            num_bits: 0,\n        };\n\n        let result = empty_encoding.decode(&dict);\n\n        assert_eq!(result, Some(vec![]));\n    }\n\n    #[test]\n    fn minimal_decode_end_check() {\n        let freq = vec![(b'a', 1), (b'b', 1)];\n        let bytes = b\"ab\";\n\n        let dict = HuffmanDictionary::new(&freq).unwrap();\n        let encoded = dict.encode(bytes);\n\n        // This decode will go through the main loop and hit the final 'if self.num_bits > 0' check.\n        let decoded = encoded.decode(&dict).unwrap();\n\n        assert_eq!(decoded, bytes);\n    }\n\n    #[test]\n    fn test_decode_corrupted_stream_dead_end() {\n        // Create a dictionary with three symbols to ensure a deeper tree.\n        // This makes hitting a dead-end (None pointer) easier.\n        let freq = vec![(b'a', 1), (b'b', 1), (b'c', 1)];\n        let bytes = b\"ab\";\n        let dict = HuffmanDictionary::new(&freq).unwrap();\n\n        let encoded = dict.encode(bytes);\n\n        // Manually corrupt the stream to stop mid-symbol.\n        // We will truncate num_bits by a small amount (e.g., 1 bit).\n        // This forces the loop to stop on an *intermediate* node.\n        let corrupted_encoding = HuffmanEncoding {\n            data: encoded.data,\n            // Shorten the bit count by one. The total length of the 'ab' stream\n            // is likely 4 or 5 bits. This forces the loop to end one bit early,\n            // leaving the state on an internal node.\n            num_bits: encoded\n                .num_bits\n                .checked_sub(1)\n                .expect(\"Encoding should be > 0 bits\"),\n        };\n\n        // Assert that the decode fails gracefully.\n        // The loop finishes, the final 'if self.num_bits > 0' executes,\n        // and result.push(state.symbol?) fails because state.symbol is None.\n        assert_eq!(corrupted_encoding.decode(&dict), None);\n    }\n\n    #[test]\n    fn small_text() {\n        let text = \"Hello world\";\n        let bytes = text.as_bytes();\n        let freq = get_frequency(bytes);\n        let dict = HuffmanDictionary::new(&freq).unwrap();\n        let encoded = dict.encode(bytes);\n        assert_eq!(encoded.num_bits, 32);\n        let decoded = encoded.decode(&dict).unwrap();\n        assert_eq!(decoded, bytes);\n    }\n    #[test]\n    fn lorem_ipsum() {\n        let text = concat!(\n            \"The quick brown fox jumped over the lazy dog.\",\n            \"Lorem ipsum dolor sit amet, consectetur \",\n            \"adipiscing elit, sed do eiusmod tempor incididunt ut labore et \",\n            \"dolore magna aliqua. Facilisis magna etiam tempor orci. Nullam \",\n            \"non nisi est sit amet facilisis magna. Commodo nulla facilisi \",\n            \"nullam vehicula. Interdum posuere lorem ipsum dolor. Elit eget \",\n            \"gravida cum sociis natoque penatibus. Dictum sit amet justo donec \",\n            \"enim. Tempor commodo ullamcorper a lacus vestibulum sed. Nisl \",\n            \"suscipit adipiscing bibendum est ultricies. Sit amet aliquam id \",\n            \"diam maecenas ultricies.\"\n        );\n        let bytes = text.as_bytes();\n        let freq = get_frequency(bytes);\n        let dict = HuffmanDictionary::new(&freq).unwrap();\n        let encoded = dict.encode(bytes);\n        assert_eq!(encoded.num_bits, 2372);\n        let decoded = encoded.decode(&dict).unwrap();\n        assert_eq!(decoded, bytes);\n\n        let text = \"The dictionary should work on other texts too\";\n        let bytes = text.as_bytes();\n        let encoded = dict.encode(bytes);\n        assert_eq!(encoded.num_bits, 215);\n        let decoded = encoded.decode(&dict).unwrap();\n        assert_eq!(decoded, bytes);\n    }\n}\n"
  },
  {
    "path": "src/general/kadane_algorithm.rs",
    "content": "/**\n * @file\n * @brief Find the maximum subarray sum using Kadane's algorithm.(https://en.wikipedia.org/wiki/Maximum_subarray_problem)\n *\n * @details\n * This program provides a function to find the maximum subarray sum in an array of integers\n * using Kadane's algorithm.\n *\n * @param arr A slice of integers representing the array.\n * @return The maximum subarray sum.\n *\n * @author [Gyandeep] (https://github.com/Gyan172004)\n * @see Wikipedia - Maximum subarray problem\n */\n\n/**\n * Find the maximum subarray sum using Kadane's algorithm.\n * @param arr A slice of integers representing the array.\n * @return The maximum subarray sum.\n */\npub fn max_sub_array(nums: Vec<i32>) -> i32 {\n    if nums.is_empty() {\n        return 0;\n    }\n\n    let mut max_current = nums[0];\n    let mut max_global = nums[0];\n\n    nums.iter().skip(1).for_each(|&item| {\n        max_current = std::cmp::max(item, max_current + item);\n        if max_current > max_global {\n            max_global = max_current;\n        }\n    });\n    max_global\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    /**\n     * Test case for Kadane's algorithm with positive numbers.\n     */\n    #[test]\n    fn test_kadanes_algorithm_positive() {\n        let arr = [1, 2, 3, 4, 5];\n        assert_eq!(max_sub_array(arr.to_vec()), 15);\n    }\n\n    /**\n     * Test case for Kadane's algorithm with negative numbers.\n     */\n    #[test]\n    fn test_kadanes_algorithm_negative() {\n        let arr = [-2, -3, -4, -1, -2];\n        assert_eq!(max_sub_array(arr.to_vec()), -1);\n    }\n\n    /**\n     * Test case for Kadane's algorithm with mixed numbers.\n     */\n    #[test]\n    fn test_kadanes_algorithm_mixed() {\n        let arr = [-2, 1, -3, 4, -1, 2, 1, -5, 4];\n        assert_eq!(max_sub_array(arr.to_vec()), 6);\n    }\n\n    /**\n     * Test case for Kadane's algorithm with an empty array.\n     */\n    #[test]\n    fn test_kadanes_algorithm_empty() {\n        let arr: [i32; 0] = [];\n        assert_eq!(max_sub_array(arr.to_vec()), 0);\n    }\n\n    /**\n     * Test case for Kadane's algorithm with a single positive number.\n     */\n    #[test]\n    fn test_kadanes_algorithm_single_positive() {\n        let arr = [10];\n        assert_eq!(max_sub_array(arr.to_vec()), 10);\n    }\n}\n"
  },
  {
    "path": "src/general/kmeans.rs",
    "content": "// Macro to implement kmeans for both f64 and f32 without writing everything\n// twice or importing the `num` crate\nmacro_rules! impl_kmeans {\n    ($kind: ty, $modname: ident) => {\n        // Since we can't overload methods in rust, we have to use namespacing\n        pub mod $modname {\n\n            /// computes sum of squared deviation between two identically sized vectors\n            /// `x`, and `y`.\n            fn distance(x: &[$kind], y: &[$kind]) -> $kind {\n                x.iter()\n                    .zip(y.iter())\n                    .fold(0.0, |dist, (&xi, &yi)| dist + (xi - yi).powi(2))\n            }\n\n            /// Returns a vector containing the indices z<sub>i</sub> in {0, ..., K-1} of\n            /// the centroid nearest to each datum.\n            fn nearest_centroids(xs: &[Vec<$kind>], centroids: &[Vec<$kind>]) -> Vec<usize> {\n                xs.iter()\n                    .map(|xi| {\n                        // Find the argmin by folding using a tuple containing the argmin\n                        // and the minimum distance.\n                        let (argmin, _) = centroids.iter().enumerate().fold(\n                            (0_usize, <$kind>::INFINITY),\n                            |(min_ix, min_dist), (ix, ci)| {\n                                let dist = distance(xi, ci);\n                                if dist < min_dist {\n                                    (ix, dist)\n                                } else {\n                                    (min_ix, min_dist)\n                                }\n                            },\n                        );\n                        argmin\n                    })\n                    .collect()\n            }\n\n            /// Recompute the centroids given the current clustering\n            fn recompute_centroids(\n                xs: &[Vec<$kind>],\n                clustering: &[usize],\n                k: usize,\n            ) -> Vec<Vec<$kind>> {\n                let ndims = xs[0].len();\n\n                // NOTE: Kind of inefficient because we sweep all the data from each of the\n                // k centroids.\n                (0..k)\n                    .map(|cluster_ix| {\n                        let mut centroid: Vec<$kind> = vec![0.0; ndims];\n                        let mut n_cluster: $kind = 0.0;\n                        xs.iter().zip(clustering.iter()).for_each(|(xi, &zi)| {\n                            if zi == cluster_ix {\n                                n_cluster += 1.0;\n                                xi.iter().enumerate().for_each(|(j, &x_ij)| {\n                                    centroid[j] += x_ij;\n                                });\n                            }\n                        });\n                        centroid.iter().map(|&c_j| c_j / n_cluster).collect()\n                    })\n                    .collect()\n            }\n\n            /// Assign the N D-dimensional data, `xs`, to `k` clusters using K-Means clustering\n            pub fn kmeans(xs: Vec<Vec<$kind>>, k: usize) -> Vec<usize> {\n                assert!(xs.len() >= k);\n\n                // Rather than pulling in a dependency to radomly select the staring\n                // points for the centroids, we're going to deterministally choose them by\n                // slecting evenly spaced points in `xs`\n                let n_per_cluster: usize = xs.len() / k;\n                let centroids: Vec<Vec<$kind>> =\n                    (0..k).map(|j| xs[j * n_per_cluster].clone()).collect();\n\n                let mut clustering = nearest_centroids(&xs, &centroids);\n\n                loop {\n                    let centroids = recompute_centroids(&xs, &clustering, k);\n                    let new_clustering = nearest_centroids(&xs, &centroids);\n\n                    // loop until the clustering doesn't change after the new centroids are computed\n                    if new_clustering\n                        .iter()\n                        .zip(clustering.iter())\n                        .all(|(&za, &zb)| za == zb)\n                    {\n                        // We need to use `return` to break out of the `loop`\n                        return clustering;\n                    }\n                    clustering = new_clustering;\n                }\n            }\n        }\n    };\n}\n\n// generate code for kmeans for f32 and f64 data\nimpl_kmeans!(f64, f64);\nimpl_kmeans!(f32, f32);\n\n#[cfg(test)]\nmod test {\n    use self::super::f64::kmeans;\n\n    #[test]\n    fn easy_univariate_clustering() {\n        let xs: Vec<Vec<f64>> = vec![\n            vec![-1.1],\n            vec![-1.2],\n            vec![-1.3],\n            vec![-1.4],\n            vec![1.1],\n            vec![1.2],\n            vec![1.3],\n            vec![1.4],\n        ];\n        let clustering = kmeans(xs, 2);\n        assert_eq!(clustering, vec![0, 0, 0, 0, 1, 1, 1, 1]);\n    }\n\n    #[test]\n    fn easy_univariate_clustering_odd_number_of_data() {\n        let xs: Vec<Vec<f64>> = vec![\n            vec![-1.1],\n            vec![-1.2],\n            vec![-1.3],\n            vec![-1.4],\n            vec![1.1],\n            vec![1.2],\n            vec![1.3],\n            vec![1.4],\n            vec![1.5],\n        ];\n        let clustering = kmeans(xs, 2);\n        assert_eq!(clustering, vec![0, 0, 0, 0, 1, 1, 1, 1, 1]);\n    }\n\n    #[test]\n    fn easy_bivariate_clustering() {\n        let xs: Vec<Vec<f64>> = vec![\n            vec![-1.1, 0.2],\n            vec![-1.2, 0.3],\n            vec![-1.3, 0.1],\n            vec![-1.4, 0.4],\n            vec![1.1, -1.1],\n            vec![1.2, -1.0],\n            vec![1.3, -1.2],\n            vec![1.4, -1.3],\n        ];\n        let clustering = kmeans(xs, 2);\n        assert_eq!(clustering, vec![0, 0, 0, 0, 1, 1, 1, 1]);\n    }\n\n    #[test]\n    fn high_dims() {\n        let xs: Vec<Vec<f64>> = vec![\n            vec![-2.7825343, -1.7604825, -5.5550113, -2.9752946, -2.7874138],\n            vec![-2.9847919, -3.8209332, -2.1531757, -2.2710119, -2.3582877],\n            vec![-3.0109320, -2.2366132, -2.8048492, -1.2632331, -4.5755581],\n            vec![-2.8432186, -1.0383805, -2.2022826, -2.7435962, -2.0013399],\n            vec![-2.6638082, -3.5520086, -1.3684702, -2.1562444, -1.3186447],\n            vec![1.7409171, 1.9687576, 4.7162628, 4.5743537, 3.7905611],\n            vec![3.2932369, 2.8508700, 2.5580937, 2.0437325, 4.2192562],\n            vec![2.5843321, 2.8329818, 2.1329531, 3.2562319, 2.4878733],\n            vec![2.1859638, 3.2880048, 3.7018615, 2.3641232, 1.6281994],\n            vec![2.6201773, 0.9006588, 2.6774097, 1.8188620, 1.6076493],\n        ];\n\n        let clustering = kmeans(xs, 2);\n        assert_eq!(clustering, vec![0, 0, 0, 0, 0, 1, 1, 1, 1, 1]);\n    }\n}\n"
  },
  {
    "path": "src/general/mex.rs",
    "content": "use std::collections::BTreeSet;\n\n// Find minimum excluded number from a set of given numbers using a set\n/// Finds the MEX of the values provided in `arr`\n/// Uses [`BTreeSet`](std::collections::BTreeSet)\n/// O(nlog(n)) implementation\npub fn mex_using_set(arr: &[i64]) -> i64 {\n    let mut s: BTreeSet<i64> = BTreeSet::new();\n    for i in 0..=arr.len() {\n        s.insert(i as i64);\n    }\n    for x in arr {\n        s.remove(x);\n    }\n    // TODO: change the next 10 lines to *s.first().unwrap() when merged into stable\n    // set should never have 0 elements\n    if let Some(x) = s.into_iter().next() {\n        x\n    } else {\n        panic!(\"Some unknown error in mex_using_set\")\n    }\n}\n/// Finds the MEX of the values provided in `arr`\n/// Uses sorting\n/// O(nlog(n)) implementation\npub fn mex_using_sort(arr: &[i64]) -> i64 {\n    let mut arr = arr.to_vec();\n    arr.sort();\n    let mut mex = 0;\n    for x in arr {\n        if x == mex {\n            mex += 1;\n        }\n    }\n    mex\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    struct MexTests {\n        test_arrays: Vec<Vec<i64>>,\n        outputs: Vec<i64>,\n    }\n    impl MexTests {\n        fn new() -> Self {\n            Self {\n                test_arrays: vec![\n                    vec![-1, 0, 1, 2, 3],\n                    vec![-100, 0, 1, 2, 3, 5],\n                    vec![-1000000, 0, 1, 2, 5],\n                    vec![2, 0, 1, 2, 4],\n                    vec![1, 2, 3, 0, 4],\n                    vec![0, 1, 5, 2, 4, 3],\n                    vec![0, 1, 2, 3, 4, 5, 6],\n                    vec![0, 1, 2, 3, 4, 5, 6, 7],\n                    vec![0, 1, 2, 3, 4, 5, 6, 7, 8],\n                ],\n                outputs: vec![4, 4, 3, 3, 5, 6, 7, 8, 9],\n            }\n        }\n        fn test_function(&self, f: fn(&[i64]) -> i64) {\n            for (nums, output) in self.test_arrays.iter().zip(self.outputs.iter()) {\n                assert_eq!(f(nums), *output);\n            }\n        }\n    }\n    #[test]\n    fn test_mex_using_set() {\n        let tests = MexTests::new();\n        mex_using_set(&[1, 23, 3]);\n        tests.test_function(mex_using_set);\n    }\n    #[test]\n    fn test_mex_using_sort() {\n        let tests = MexTests::new();\n        tests.test_function(mex_using_sort);\n    }\n}\n"
  },
  {
    "path": "src/general/mod.rs",
    "content": "mod convex_hull;\nmod fisher_yates_shuffle;\nmod genetic;\nmod hanoi;\nmod huffman_encoding;\nmod kadane_algorithm;\nmod kmeans;\nmod mex;\nmod permutations;\nmod subarray_sum_equals_k;\nmod two_sum;\n\npub use self::convex_hull::convex_hull_graham;\npub use self::fisher_yates_shuffle::fisher_yates_shuffle;\npub use self::genetic::GeneticAlgorithm;\npub use self::hanoi::hanoi;\npub use self::huffman_encoding::{HuffmanDictionary, HuffmanEncoding};\npub use self::kadane_algorithm::max_sub_array;\npub use self::kmeans::f32::kmeans as kmeans_f32;\npub use self::kmeans::f64::kmeans as kmeans_f64;\npub use self::mex::mex_using_set;\npub use self::mex::mex_using_sort;\npub use self::permutations::{\n    heap_permute, permute, permute_unique, steinhaus_johnson_trotter_permute,\n};\npub use self::subarray_sum_equals_k::subarray_sum_equals_k;\npub use self::two_sum::two_sum;\n"
  },
  {
    "path": "src/general/permutations/heap.rs",
    "content": "use std::fmt::Debug;\n\n/// Computes all permutations of an array using Heap's algorithm\n/// Read `recurse_naive` first, since we're building on top of the same intuition\npub fn heap_permute<T: Clone + Debug>(arr: &[T]) -> Vec<Vec<T>> {\n    if arr.is_empty() {\n        return vec![vec![]];\n    }\n    let n = arr.len();\n    let mut collector = Vec::with_capacity((1..=n).product()); // collects the permuted arrays\n    let mut arr = arr.to_owned(); // Heap's algorithm needs to mutate the array\n    heap_recurse(&mut arr, n, &mut collector);\n    collector\n}\n\nfn heap_recurse<T: Clone + Debug>(arr: &mut [T], k: usize, collector: &mut Vec<Vec<T>>) {\n    if k == 1 {\n        // same base-case as in the naive version\n        collector.push((*arr).to_owned());\n        return;\n    }\n    // Remember the naive recursion. We did the following: swap(i, last), recurse, swap back(i, last)\n    // Heap's algorithm has a more clever way of permuting the elements so that we never need to swap back!\n    for i in 0..k {\n        // now deal with [a, b]\n        let swap_idx = if k.is_multiple_of(2) { i } else { 0 };\n        arr.swap(swap_idx, k - 1);\n        heap_recurse(arr, k - 1, collector);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use quickcheck_macros::quickcheck;\n\n    use crate::general::permutations::heap_permute;\n    use crate::general::permutations::tests::{\n        assert_permutations, assert_valid_permutation, NotTooBigVec,\n    };\n\n    #[test]\n    fn test_3_different_values() {\n        let original = vec![1, 2, 3];\n        let res = heap_permute(&original);\n        assert_eq!(res.len(), 6); // 3!\n        for permut in res {\n            assert_valid_permutation(&original, &permut)\n        }\n    }\n\n    #[test]\n    fn test_3_times_the_same_value() {\n        let original = vec![1, 1, 1];\n        let res = heap_permute(&original);\n        assert_eq!(res.len(), 6); // 3!\n        for permut in res {\n            assert_valid_permutation(&original, &permut)\n        }\n    }\n\n    #[quickcheck]\n    fn test_some_elements(NotTooBigVec { inner: original }: NotTooBigVec) {\n        let permutations = heap_permute(&original);\n        assert_permutations(&original, &permutations)\n    }\n}\n"
  },
  {
    "path": "src/general/permutations/mod.rs",
    "content": "mod heap;\nmod naive;\nmod steinhaus_johnson_trotter;\n\npub use self::heap::heap_permute;\npub use self::naive::{permute, permute_unique};\npub use self::steinhaus_johnson_trotter::steinhaus_johnson_trotter_permute;\n\n#[cfg(test)]\nmod tests {\n    use quickcheck::{Arbitrary, Gen};\n    use std::collections::HashMap;\n\n    pub fn assert_permutations(original: &[i32], permutations: &[Vec<i32>]) {\n        if original.is_empty() {\n            assert_eq!(vec![vec![] as Vec<i32>], permutations);\n            return;\n        }\n        let n = original.len();\n        assert_eq!((1..=n).product::<usize>(), permutations.len()); // n!\n        for permut in permutations {\n            assert_valid_permutation(original, permut);\n        }\n    }\n\n    pub fn assert_valid_permutation(original: &[i32], permuted: &[i32]) {\n        assert_eq!(original.len(), permuted.len());\n        let mut indices = HashMap::with_capacity(original.len());\n        for value in original {\n            *indices.entry(*value).or_insert(0) += 1;\n        }\n        for permut_value in permuted {\n            let count = indices.get_mut(permut_value).unwrap_or_else(|| {\n                panic!(\"Value {permut_value} appears too many times in permutation\")\n            });\n            *count -= 1; // use this value\n            if *count == 0 {\n                indices.remove(permut_value); // so that we can simply check every value has been removed properly\n            }\n        }\n        assert!(indices.is_empty())\n    }\n\n    #[test]\n    fn test_valid_permutations() {\n        assert_valid_permutation(&[1, 2, 3], &[1, 2, 3]);\n        assert_valid_permutation(&[1, 2, 3], &[1, 3, 2]);\n        assert_valid_permutation(&[1, 2, 3], &[2, 1, 3]);\n        assert_valid_permutation(&[1, 2, 3], &[2, 3, 1]);\n        assert_valid_permutation(&[1, 2, 3], &[3, 1, 2]);\n        assert_valid_permutation(&[1, 2, 3], &[3, 2, 1]);\n    }\n\n    #[test]\n    #[should_panic]\n    fn test_invalid_permutation_1() {\n        assert_valid_permutation(&[1, 2, 3], &[4, 2, 3]);\n    }\n\n    #[test]\n    #[should_panic]\n    fn test_invalid_permutation_2() {\n        assert_valid_permutation(&[1, 2, 3], &[1, 4, 3]);\n    }\n\n    #[test]\n    #[should_panic]\n    fn test_invalid_permutation_3() {\n        assert_valid_permutation(&[1, 2, 3], &[1, 2, 4]);\n    }\n\n    #[test]\n    #[should_panic]\n    fn test_invalid_permutation_repeat() {\n        assert_valid_permutation(&[1, 2, 3], &[1, 2, 2]);\n    }\n\n    /// A Data Structure for testing permutations\n    /// Holds a Vec<i32> with just a few items, so that it's not too long to compute permutations\n    #[derive(Debug, Clone)]\n    pub struct NotTooBigVec {\n        pub(crate) inner: Vec<i32>, // opaque type alias so that we can implement Arbitrary\n    }\n\n    const MAX_SIZE: usize = 8; // 8! ~= 40k permutations already\n    impl Arbitrary for NotTooBigVec {\n        fn arbitrary(g: &mut Gen) -> Self {\n            let size = usize::arbitrary(g) % MAX_SIZE;\n            let res = (0..size).map(|_| i32::arbitrary(g)).collect();\n            NotTooBigVec { inner: res }\n        }\n    }\n}\n"
  },
  {
    "path": "src/general/permutations/naive.rs",
    "content": "use std::collections::HashSet;\nuse std::fmt::Debug;\nuse std::hash::Hash;\n\n/// Here's a basic (naive) implementation for generating permutations\npub fn permute<T: Clone + Debug>(arr: &[T]) -> Vec<Vec<T>> {\n    if arr.is_empty() {\n        return vec![vec![]];\n    }\n    let n = arr.len();\n    let count = (1..=n).product(); // n! permutations\n    let mut collector = Vec::with_capacity(count); // collects the permuted arrays\n    let mut arr = arr.to_owned(); // we'll need to mutate the array\n\n    // the idea is the following: imagine [a, b, c]\n    // always swap an item with the last item, then generate all permutations from the first k characters\n    // permute_recurse(arr, k - 1, collector); // leave the last character alone, and permute the first k-1 characters\n    permute_recurse(&mut arr, n, &mut collector);\n    collector\n}\n\nfn permute_recurse<T: Clone + Debug>(arr: &mut Vec<T>, k: usize, collector: &mut Vec<Vec<T>>) {\n    if k == 1 {\n        collector.push(arr.to_owned());\n        return;\n    }\n    for i in 0..k {\n        arr.swap(i, k - 1); // swap i with the last character\n        permute_recurse(arr, k - 1, collector); // collect the permutations of the rest\n        arr.swap(i, k - 1); // swap back to original\n    }\n}\n\n/// A common variation of generating permutations is to generate only unique permutations\n/// Of course, we could use the version above together with a Set as collector instead of a Vec.\n/// But let's try something different: how can we avoid to generate duplicated permutations in the first place, can we tweak the algorithm above?\npub fn permute_unique<T: Clone + Debug + Eq + Hash + Copy>(arr: &[T]) -> Vec<Vec<T>> {\n    if arr.is_empty() {\n        return vec![vec![]];\n    }\n    let n = arr.len();\n    let count = (1..=n).product(); // n! permutations\n    let mut collector = Vec::with_capacity(count); // collects the permuted arrays\n    let mut arr = arr.to_owned(); // Heap's algorithm needs to mutate the array\n    permute_recurse_unique(&mut arr, n, &mut collector);\n    collector\n}\n\nfn permute_recurse_unique<T: Clone + Debug + Eq + Hash + Copy>(\n    arr: &mut Vec<T>,\n    k: usize,\n    collector: &mut Vec<Vec<T>>,\n) {\n    // We have the same base-case as previously, whenever we reach the first element in the array, collect the result\n    if k == 1 {\n        collector.push(arr.to_owned());\n        return;\n    }\n    // We'll keep the same idea (swap with last item, and generate all permutations for the first k - 1)\n    // But we'll have to be careful though: how would we generate duplicates?\n    // Basically if, when swapping i with k-1, we generate the exact same array as in a previous iteration\n    // Imagine [a, a, b]\n    // i = 0:\n    //  Swap (a, b) => [b, a, a], fix 'a' as last, and generate all permutations of [b, a] => [b, a, a], [a, b, a]\n    //  Swap Back to [a, a, b]\n    // i = 1:\n    //  Swap(a, b) => [b, a, a], we've done that already!!\n    let mut swapped = HashSet::with_capacity(k);\n    for i in 0..k {\n        if swapped.contains(&arr[i]) {\n            continue;\n        }\n        swapped.insert(arr[i]);\n        arr.swap(i, k - 1); // swap i with the last character\n        permute_recurse_unique(arr, k - 1, collector); // collect the permutations\n        arr.swap(i, k - 1); // go back to original\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::general::permutations::naive::{permute, permute_unique};\n    use crate::general::permutations::tests::{\n        assert_permutations, assert_valid_permutation, NotTooBigVec,\n    };\n    use quickcheck_macros::quickcheck;\n    use std::collections::HashSet;\n\n    #[test]\n    fn test_3_different_values() {\n        let original = vec![1, 2, 3];\n        let res = permute(&original);\n        assert_eq!(res.len(), 6); // 3!\n        for permut in res {\n            assert_valid_permutation(&original, &permut)\n        }\n    }\n\n    #[test]\n    fn empty_array() {\n        let empty: std::vec::Vec<u8> = vec![];\n        assert_eq!(permute(&empty), vec![vec![]]);\n        assert_eq!(permute_unique(&empty), vec![vec![]]);\n    }\n\n    #[test]\n    fn test_3_times_the_same_value() {\n        let original = vec![1, 1, 1];\n        let res = permute(&original);\n        assert_eq!(res.len(), 6); // 3!\n        for permut in res {\n            assert_valid_permutation(&original, &permut)\n        }\n    }\n\n    #[quickcheck]\n    fn test_some_elements(NotTooBigVec { inner: original }: NotTooBigVec) {\n        let permutations = permute(&original);\n        assert_permutations(&original, &permutations)\n    }\n\n    #[test]\n    fn test_unique_values() {\n        let original = vec![1, 1, 2, 2];\n        let unique_permutations = permute_unique(&original);\n        let every_permutation = permute(&original);\n        for unique_permutation in &unique_permutations {\n            assert!(every_permutation.contains(unique_permutation));\n        }\n        assert_eq!(\n            unique_permutations.len(),\n            every_permutation.iter().collect::<HashSet<_>>().len()\n        )\n    }\n}\n"
  },
  {
    "path": "src/general/permutations/steinhaus_johnson_trotter.rs",
    "content": "/// <https://en.wikipedia.org/wiki/Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm>\npub fn steinhaus_johnson_trotter_permute<T: Clone>(array: &[T]) -> Vec<Vec<T>> {\n    let len = array.len();\n    let mut array = array.to_owned();\n    let mut inversion_vector = vec![0; len];\n    let mut i = 1;\n    let mut res = Vec::with_capacity((1..=len).product());\n    res.push(array.clone());\n    while i < len {\n        if inversion_vector[i] < i {\n            if i % 2 == 0 {\n                array.swap(0, i);\n            } else {\n                array.swap(inversion_vector[i], i);\n            }\n            res.push(array.to_vec());\n            inversion_vector[i] += 1;\n            i = 1;\n        } else {\n            inversion_vector[i] = 0;\n            i += 1;\n        }\n    }\n    res\n}\n\n#[cfg(test)]\nmod tests {\n    use quickcheck_macros::quickcheck;\n\n    use crate::general::permutations::steinhaus_johnson_trotter::steinhaus_johnson_trotter_permute;\n    use crate::general::permutations::tests::{\n        assert_permutations, assert_valid_permutation, NotTooBigVec,\n    };\n\n    #[test]\n    fn test_3_different_values() {\n        let original = vec![1, 2, 3];\n        let res = steinhaus_johnson_trotter_permute(&original);\n        assert_eq!(res.len(), 6); // 3!\n        for permut in res {\n            assert_valid_permutation(&original, &permut)\n        }\n    }\n\n    #[test]\n    fn test_3_times_the_same_value() {\n        let original = vec![1, 1, 1];\n        let res = steinhaus_johnson_trotter_permute(&original);\n        assert_eq!(res.len(), 6); // 3!\n        for permut in res {\n            assert_valid_permutation(&original, &permut)\n        }\n    }\n\n    #[quickcheck]\n    fn test_some_elements(NotTooBigVec { inner: original }: NotTooBigVec) {\n        let permutations = steinhaus_johnson_trotter_permute(&original);\n        assert_permutations(&original, &permutations)\n    }\n}\n"
  },
  {
    "path": "src/general/subarray_sum_equals_k.rs",
    "content": "use std::collections::HashMap;\n\n/// Counts the number of contiguous subarrays that sum to exactly k.\n///\n/// # Parameters\n///\n/// - `nums`: A slice of integers\n/// - `k`: The target sum\n///\n/// # Returns\n///\n/// The number of contiguous subarrays with sum equal to k.\n///\n/// # Complexity\n///\n/// - Time: O(n)\n/// - Space: O(n)\n\npub fn subarray_sum_equals_k(nums: &[i32], k: i32) -> i32 {\n    let mut prefix_sum_count: HashMap<i64, i32> = HashMap::new();\n    prefix_sum_count.insert(0, 1);\n\n    let mut prefix_sum: i64 = 0;\n    let mut count = 0;\n\n    for &num in nums {\n        prefix_sum += num as i64;\n        let target = prefix_sum - k as i64;\n\n        if let Some(&freq) = prefix_sum_count.get(&target) {\n            count += freq;\n        }\n\n        *prefix_sum_count.entry(prefix_sum).or_insert(0) += 1;\n    }\n\n    count\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_basic() {\n        assert_eq!(subarray_sum_equals_k(&[1, 1, 1], 2), 2);\n        assert_eq!(subarray_sum_equals_k(&[1, 2, 3], 3), 2);\n    }\n\n    #[test]\n    fn test_single_element() {\n        assert_eq!(subarray_sum_equals_k(&[1], 1), 1);\n        assert_eq!(subarray_sum_equals_k(&[1], 0), 0);\n    }\n\n    #[test]\n    fn test_empty() {\n        assert_eq!(subarray_sum_equals_k(&[], 0), 0);\n        assert_eq!(subarray_sum_equals_k(&[], 5), 0);\n    }\n\n    #[test]\n    fn test_negative_numbers() {\n        assert_eq!(subarray_sum_equals_k(&[-1, -1, 1], 0), 1);\n        assert_eq!(subarray_sum_equals_k(&[1, -1, 0], 0), 3);\n    }\n\n    #[test]\n    fn test_no_match() {\n        assert_eq!(subarray_sum_equals_k(&[1, 2, 3], 10), 0);\n    }\n\n    #[test]\n    fn test_multiple_matches() {\n        assert_eq!(subarray_sum_equals_k(&[1, 0, 1, 0, 1], 1), 8);\n    }\n}\n"
  },
  {
    "path": "src/general/two_sum.rs",
    "content": "use std::collections::HashMap;\n\n/// Given an array of integers nums and an integer target,\n/// return indices of the two numbers such that they add up to target.\n///\n/// # Parameters\n///\n/// - `nums`: A list of numbers to check.\n/// - `target`: The target sum.\n///\n/// # Returns\n///\n/// If the target sum is found in the array, the indices of the augend and\n/// addend are returned as a tuple.\n///\n/// If the target sum cannot be found in the array, `None` is returned.\n///\npub fn two_sum(nums: Vec<i32>, target: i32) -> Option<(usize, usize)> {\n    // This HashMap is used to look up a corresponding index in the `nums` list.\n    // Given that we know where we are at in the array, we can look up our\n    // complementary value using this table and only go through the list once.\n    //\n    // We populate this table with distances from the target. As we go through\n    // the list, a distance is computed like so:\n    //\n    //     `target - current_value`\n    //\n    // This distance also tells us about the complementary value we're looking\n    // for in the array. If we don't find that value, we insert `current_value`\n    // into the table for future look-ups. As we iterate through the list,\n    // the number we just inserted might be the perfect distance for another\n    // number, and we've found a match!\n    //\n    let mut distance_table: HashMap<i32, usize> = HashMap::new();\n\n    for (i, current_value) in nums.iter().enumerate() {\n        match distance_table.get(&(target - current_value)) {\n            Some(j) => return Some((i, *j)),\n            _ => distance_table.insert(*current_value, i),\n        };\n    }\n\n    // No match was found!\n    None\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test() {\n        let nums = vec![2, 7, 11, 15];\n        assert_eq!(two_sum(nums, 9), Some((1, 0)));\n\n        let nums = vec![3, 2, 4];\n        assert_eq!(two_sum(nums, 6), Some((2, 1)));\n\n        let nums = vec![3, 3];\n        assert_eq!(two_sum(nums, 6), Some((1, 0)));\n\n        let nums = vec![2, 7, 11, 15];\n        assert_eq!(two_sum(nums, 16), None);\n    }\n}\n"
  },
  {
    "path": "src/geometry/closest_points.rs",
    "content": "use crate::geometry::Point;\nuse std::cmp::Ordering;\n\nfn cmp_x(p1: &Point, p2: &Point) -> Ordering {\n    let acmp = f64_cmp(&p1.x, &p2.x);\n    match acmp {\n        Ordering::Equal => f64_cmp(&p1.y, &p2.y),\n        _ => acmp,\n    }\n}\n\nfn f64_cmp(a: &f64, b: &f64) -> Ordering {\n    a.partial_cmp(b).unwrap()\n}\n\n/// returns the two closest points\n/// or None if there are zero or one point\npub fn closest_points(points: &[Point]) -> Option<(Point, Point)> {\n    let mut points_x: Vec<Point> = points.to_vec();\n    points_x.sort_by(cmp_x);\n    let mut points_y = points_x.clone();\n    points_y.sort_by(|p1: &Point, p2: &Point| -> Ordering { p1.y.partial_cmp(&p2.y).unwrap() });\n\n    closest_points_aux(&points_x, points_y, 0, points_x.len())\n}\n\n// We maintain two vectors with the same points, one sort by x coordinates and one sorted by y\n// coordinates.\nfn closest_points_aux(\n    points_x: &[Point],\n    points_y: Vec<Point>,\n    mut start: usize,\n    mut end: usize,\n) -> Option<(Point, Point)> {\n    let n = end - start;\n\n    if n <= 1 {\n        return None;\n    }\n\n    if n <= 3 {\n        // bruteforce\n        let mut min = points_x[0].euclidean_distance(&points_x[1]);\n        let mut pair = (points_x[0].clone(), points_x[1].clone());\n\n        for i in 1..n {\n            for j in (i + 1)..n {\n                let new = points_x[i].euclidean_distance(&points_x[j]);\n                if new < min {\n                    min = new;\n                    pair = (points_x[i].clone(), points_x[j].clone());\n                }\n            }\n        }\n        return Some(pair);\n    }\n\n    let mid = start + (end - start) / 2;\n    let mid_x = points_x[mid].x;\n\n    // Separate points into y_left and y_right vectors based on their x-coordinate. Since y is\n    // already sorted by y_axis, y_left and y_right will also be sorted.\n    let mut y_left = vec![];\n    let mut y_right = vec![];\n    for point in &points_y {\n        if point.x < mid_x {\n            y_left.push(point.clone());\n        } else {\n            y_right.push(point.clone());\n        }\n    }\n\n    let left = closest_points_aux(points_x, y_left, start, mid);\n    let right = closest_points_aux(points_x, y_right, mid, end);\n\n    let (mut min_sqr_dist, mut pair) = match (left, right) {\n        (Some((l1, l2)), Some((r1, r2))) => {\n            let dl = l1.euclidean_distance(&l2);\n            let dr = r1.euclidean_distance(&r2);\n            if dl < dr {\n                (dl, (l1, l2))\n            } else {\n                (dr, (r1, r2))\n            }\n        }\n        (Some((a, b)), None) | (None, Some((a, b))) => (a.euclidean_distance(&b), (a, b)),\n        (None, None) => unreachable!(),\n    };\n\n    let dist = min_sqr_dist;\n    while points_x[start].x < mid_x - dist {\n        start += 1;\n    }\n    while points_x[end - 1].x > mid_x + dist {\n        end -= 1;\n    }\n\n    for (i, e) in points_y.iter().enumerate() {\n        for k in 1..8 {\n            if i + k >= points_y.len() {\n                break;\n            }\n\n            let new = e.euclidean_distance(&points_y[i + k]);\n            if new < min_sqr_dist {\n                min_sqr_dist = new;\n                pair = ((*e).clone(), points_y[i + k].clone());\n            }\n        }\n    }\n\n    Some(pair)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::closest_points;\n    use super::Point;\n\n    fn eq(p1: Option<(Point, Point)>, p2: Option<(Point, Point)>) -> bool {\n        match (p1, p2) {\n            (None, None) => true,\n            (Some((p1, p2)), Some((p3, p4))) => (p1 == p3 && p2 == p4) || (p1 == p4 && p2 == p3),\n            _ => false,\n        }\n    }\n\n    macro_rules! assert_display {\n        ($left: expr, $right: expr) => {\n            assert!(\n                eq($left, $right),\n                \"assertion failed: `(left == right)`\\nleft: `{:?}`,\\nright: `{:?}`\",\n                $left,\n                $right\n            )\n        };\n    }\n\n    #[test]\n    fn zero_points() {\n        let vals: [Point; 0] = [];\n        assert_display!(closest_points(&vals), None::<(Point, Point)>);\n    }\n\n    #[test]\n    fn one_points() {\n        let vals = [Point::new(0., 0.)];\n        assert_display!(closest_points(&vals), None::<(Point, Point)>);\n    }\n\n    #[test]\n    fn two_points() {\n        let vals = [Point::new(0., 0.), Point::new(1., 1.)];\n        assert_display!(\n            closest_points(&vals),\n            Some((vals[0].clone(), vals[1].clone()))\n        );\n    }\n\n    #[test]\n    fn three_points() {\n        let vals = [Point::new(0., 0.), Point::new(1., 1.), Point::new(3., 3.)];\n        assert_display!(\n            closest_points(&vals),\n            Some((vals[0].clone(), vals[1].clone()))\n        );\n    }\n\n    #[test]\n    fn list_1() {\n        let vals = [\n            Point::new(0., 0.),\n            Point::new(2., 1.),\n            Point::new(5., 2.),\n            Point::new(2., 3.),\n            Point::new(4., 0.),\n            Point::new(0., 4.),\n            Point::new(5., 6.),\n            Point::new(4., 4.),\n            Point::new(7., 3.),\n            Point::new(-1., 2.),\n            Point::new(2., 6.),\n        ];\n        assert_display!(\n            closest_points(&vals),\n            Some((Point::new(2., 1.), Point::new(2., 3.)))\n        );\n    }\n\n    #[test]\n    fn list_2() {\n        let vals = [\n            Point::new(1., 3.),\n            Point::new(4., 6.),\n            Point::new(8., 8.),\n            Point::new(7., 5.),\n            Point::new(5., 3.),\n            Point::new(10., 3.),\n            Point::new(7., 1.),\n            Point::new(8., 3.),\n            Point::new(4., 9.),\n            Point::new(4., 12.),\n            Point::new(4., 15.),\n            Point::new(7., 14.),\n            Point::new(8., 12.),\n            Point::new(6., 10.),\n            Point::new(4., 14.),\n            Point::new(2., 7.),\n            Point::new(3., 8.),\n            Point::new(5., 8.),\n            Point::new(6., 7.),\n            Point::new(8., 10.),\n            Point::new(6., 12.),\n        ];\n        assert_display!(\n            closest_points(&vals),\n            Some((Point::new(4., 14.), Point::new(4., 15.)))\n        );\n    }\n\n    #[test]\n    fn vertical_points() {\n        let vals = [\n            Point::new(0., 0.),\n            Point::new(0., 50.),\n            Point::new(0., -25.),\n            Point::new(0., 40.),\n            Point::new(0., 42.),\n            Point::new(0., 100.),\n            Point::new(0., 17.),\n            Point::new(0., 29.),\n            Point::new(0., -50.),\n            Point::new(0., 37.),\n            Point::new(0., 34.),\n            Point::new(0., 8.),\n            Point::new(0., 3.),\n            Point::new(0., 46.),\n        ];\n        assert_display!(\n            closest_points(&vals),\n            Some((Point::new(0., 40.), Point::new(0., 42.)))\n        );\n    }\n}\n"
  },
  {
    "path": "src/geometry/graham_scan.rs",
    "content": "use crate::geometry::Point;\nuse std::cmp::Ordering;\n\nfn point_min(a: &&Point, b: &&Point) -> Ordering {\n    // Find the bottom-most point. In the case of a tie, find the left-most.\n    if a.y == b.y {\n        a.x.partial_cmp(&b.x).unwrap()\n    } else {\n        a.y.partial_cmp(&b.y).unwrap()\n    }\n}\n\n// Returns a Vec of Points that make up the convex hull of `points`. Returns an empty Vec if there\n// is no convex hull.\npub fn graham_scan(mut points: Vec<Point>) -> Vec<Point> {\n    if points.len() <= 2 {\n        return vec![];\n    }\n\n    let min_point = points.iter().min_by(point_min).unwrap().clone();\n    points.retain(|p| p != &min_point);\n    if points.is_empty() {\n        // edge case where all the points are the same\n        return vec![];\n    }\n\n    let point_cmp = |a: &Point, b: &Point| -> Ordering {\n        // Sort points in counter-clockwise direction relative to the min point. We can this by\n        // checking the orientation of consecutive vectors (min_point, a) and (a, b).\n        let orientation = min_point.consecutive_orientation(a, b);\n        if orientation < 0.0 {\n            Ordering::Greater\n        } else if orientation > 0.0 {\n            Ordering::Less\n        } else {\n            let a_dist = min_point.euclidean_distance(a);\n            let b_dist = min_point.euclidean_distance(b);\n            // When two points have the same relative angle to the min point, we should only\n            // include the further point in the convex hull. We sort further points into a lower\n            // index, and in the algorithm, remove all consecutive points with the same relative\n            // angle.\n            b_dist.partial_cmp(&a_dist).unwrap()\n        }\n    };\n    points.sort_by(point_cmp);\n    let mut convex_hull: Vec<Point> = vec![];\n\n    // We always add the min_point, and the first two points in the sorted vec.\n    convex_hull.push(min_point.clone());\n    convex_hull.push(points[0].clone());\n    let mut top = 1;\n    for point in points.iter().skip(1) {\n        if min_point.consecutive_orientation(point, &convex_hull[top]) == 0.0 {\n            // Remove consecutive points with the same angle. We make sure include the furthest\n            // point in the convex hull in the sort comparator.\n            continue;\n        }\n        loop {\n            // In this loop, we remove points that we determine are no longer part of the convex\n            // hull.\n            if top <= 1 {\n                break;\n            }\n            // If there is a segment(i+1, i+2) turns right relative to segment(i, i+1), point(i+1)\n            // is not part of the convex hull.\n            let orientation =\n                convex_hull[top - 1].consecutive_orientation(&convex_hull[top], point);\n            if orientation <= 0.0 {\n                top -= 1;\n                convex_hull.pop();\n            } else {\n                break;\n            }\n        }\n        convex_hull.push(point.clone());\n        top += 1;\n    }\n    if convex_hull.len() <= 2 {\n        return vec![];\n    }\n    convex_hull\n}\n\n#[cfg(test)]\nmod tests {\n    use super::graham_scan;\n    use super::Point;\n\n    fn test_graham(convex_hull: Vec<Point>, others: Vec<Point>) {\n        let mut points = convex_hull.clone();\n        points.append(&mut others.clone());\n        let graham = graham_scan(points);\n        for point in convex_hull {\n            assert!(graham.contains(&point));\n        }\n        for point in others {\n            assert!(!graham.contains(&point));\n        }\n    }\n\n    #[test]\n    fn too_few_points() {\n        test_graham(vec![], vec![]);\n        test_graham(vec![], vec![Point::new(0.0, 0.0)]);\n    }\n\n    #[test]\n    fn duplicate_point() {\n        let p = Point::new(0.0, 0.0);\n        test_graham(vec![], vec![p.clone(), p.clone(), p.clone(), p.clone(), p]);\n    }\n\n    #[test]\n    fn points_same_line() {\n        let p1 = Point::new(1.0, 0.0);\n        let p2 = Point::new(2.0, 0.0);\n        let p3 = Point::new(3.0, 0.0);\n        let p4 = Point::new(4.0, 0.0);\n        let p5 = Point::new(5.0, 0.0);\n        // let p6 = Point::new(1.0, 1.0);\n        test_graham(vec![], vec![p1, p2, p3, p4, p5]);\n    }\n\n    #[test]\n    fn triangle() {\n        let p1 = Point::new(1.0, 1.0);\n        let p2 = Point::new(2.0, 1.0);\n        let p3 = Point::new(1.5, 2.0);\n        let points = vec![p1, p2, p3];\n        test_graham(points, vec![]);\n    }\n\n    #[test]\n    fn rectangle() {\n        let p1 = Point::new(1.0, 1.0);\n        let p2 = Point::new(2.0, 1.0);\n        let p3 = Point::new(2.0, 2.0);\n        let p4 = Point::new(1.0, 2.0);\n        let points = vec![p1, p2, p3, p4];\n        test_graham(points, vec![]);\n    }\n\n    #[test]\n    fn triangle_with_points_in_middle() {\n        let p1 = Point::new(1.0, 1.0);\n        let p2 = Point::new(2.0, 1.0);\n        let p3 = Point::new(1.5, 2.0);\n        let p4 = Point::new(1.5, 1.5);\n        let p5 = Point::new(1.2, 1.3);\n        let p6 = Point::new(1.8, 1.2);\n        let p7 = Point::new(1.5, 1.9);\n        let hull = vec![p1, p2, p3];\n        let others = vec![p4, p5, p6, p7];\n        test_graham(hull, others);\n    }\n\n    #[test]\n    fn rectangle_with_points_in_middle() {\n        let p1 = Point::new(1.0, 1.0);\n        let p2 = Point::new(2.0, 1.0);\n        let p3 = Point::new(2.0, 2.0);\n        let p4 = Point::new(1.0, 2.0);\n        let p5 = Point::new(1.5, 1.5);\n        let p6 = Point::new(1.2, 1.3);\n        let p7 = Point::new(1.8, 1.2);\n        let p8 = Point::new(1.9, 1.7);\n        let p9 = Point::new(1.4, 1.9);\n        let hull = vec![p1, p2, p3, p4];\n        let others = vec![p5, p6, p7, p8, p9];\n        test_graham(hull, others);\n    }\n\n    #[test]\n    fn star() {\n        // A single stroke star shape (kind of). Only the tips(p1-5) are part of the convex hull. The\n        // other points would create angles >180 degrees if they were part of the polygon.\n        let p1 = Point::new(-5.0, 6.0);\n        let p2 = Point::new(-11.0, 0.0);\n        let p3 = Point::new(-9.0, -8.0);\n        let p4 = Point::new(4.0, 4.0);\n        let p5 = Point::new(6.0, -7.0);\n        let p6 = Point::new(-7.0, -2.0);\n        let p7 = Point::new(-2.0, -4.0);\n        let p8 = Point::new(0.0, 1.0);\n        let p9 = Point::new(1.0, 0.0);\n        let p10 = Point::new(-6.0, 1.0);\n        let hull = vec![p1, p2, p3, p4, p5];\n        let others = vec![p6, p7, p8, p9, p10];\n        test_graham(hull, others);\n    }\n\n    #[test]\n    fn rectangle_with_points_on_same_line() {\n        let p1 = Point::new(1.0, 1.0);\n        let p2 = Point::new(2.0, 1.0);\n        let p3 = Point::new(2.0, 2.0);\n        let p4 = Point::new(1.0, 2.0);\n        let p5 = Point::new(1.5, 1.0);\n        let p6 = Point::new(1.0, 1.5);\n        let p7 = Point::new(2.0, 1.5);\n        let p8 = Point::new(1.5, 2.0);\n        let hull = vec![p1, p2, p3, p4];\n        let others = vec![p5, p6, p7, p8];\n        test_graham(hull, others);\n    }\n}\n"
  },
  {
    "path": "src/geometry/jarvis_scan.rs",
    "content": "use crate::geometry::Point;\nuse crate::geometry::Segment;\n\n// Returns a Vec of Points that make up the convex hull of `points`. Returns an empty Vec if there\n// is no convex hull.\npub fn jarvis_march(points: Vec<Point>) -> Vec<Point> {\n    if points.len() <= 2 {\n        return vec![];\n    }\n\n    let mut convex_hull = vec![];\n    let mut left_point = 0;\n    for i in 1..points.len() {\n        // Find the initial point, which is the leftmost point. In the case of a tie, we take the\n        // bottom-most point. This helps prevent adding colinear points on the last segment to the hull.\n        if points[i].x < points[left_point].x\n            || (points[i].x == points[left_point].x && points[i].y < points[left_point].y)\n        {\n            left_point = i;\n        }\n    }\n    convex_hull.push(points[left_point].clone());\n\n    let mut p = left_point;\n    loop {\n        // Find the next counter-clockwise point.\n        let mut next_p = (p + 1) % points.len();\n        for i in 0..points.len() {\n            let orientation = points[p].consecutive_orientation(&points[i], &points[next_p]);\n            if orientation > 0.0 {\n                next_p = i;\n            }\n        }\n\n        if next_p == left_point {\n            // Completed constructing the hull. Exit the loop.\n            break;\n        }\n        p = next_p;\n\n        let last = convex_hull.len() - 1;\n        if convex_hull.len() > 1\n            && Segment::from_points(points[p].clone(), convex_hull[last - 1].clone())\n                .on_segment(&convex_hull[last])\n        {\n            // If the last point lies on the segment with the new point and the second to last\n            // point, we can remove the last point from the hull.\n            convex_hull[last] = points[p].clone();\n        } else {\n            convex_hull.push(points[p].clone());\n        }\n    }\n\n    if convex_hull.len() <= 2 {\n        return vec![];\n    }\n    let last = convex_hull.len() - 1;\n    if Segment::from_points(convex_hull[0].clone(), convex_hull[last - 1].clone())\n        .on_segment(&convex_hull[last])\n    {\n        // Check for the edge case where the last point lies on the segment with the zero'th and\n        // second the last point. In this case, we remove the last point from the hull.\n        convex_hull.pop();\n        if convex_hull.len() == 2 {\n            return vec![];\n        }\n    }\n    convex_hull\n}\n\n#[cfg(test)]\nmod tests {\n    use super::jarvis_march;\n    use super::Point;\n\n    fn test_jarvis(convex_hull: Vec<Point>, others: Vec<Point>) {\n        let mut points = others.clone();\n        points.append(&mut convex_hull.clone());\n        let jarvis = jarvis_march(points);\n        for point in convex_hull {\n            assert!(jarvis.contains(&point));\n        }\n        for point in others {\n            assert!(!jarvis.contains(&point));\n        }\n    }\n\n    #[test]\n    fn too_few_points() {\n        test_jarvis(vec![], vec![]);\n        test_jarvis(vec![], vec![Point::new(0.0, 0.0)]);\n    }\n\n    #[test]\n    fn duplicate_point() {\n        let p = Point::new(0.0, 0.0);\n        test_jarvis(vec![], vec![p.clone(), p.clone(), p.clone(), p.clone(), p]);\n    }\n\n    #[test]\n    fn points_same_line() {\n        let p1 = Point::new(1.0, 0.0);\n        let p2 = Point::new(2.0, 0.0);\n        let p3 = Point::new(3.0, 0.0);\n        let p4 = Point::new(4.0, 0.0);\n        let p5 = Point::new(5.0, 0.0);\n        // let p6 = Point::new(1.0, 1.0);\n        test_jarvis(vec![], vec![p1, p2, p3, p4, p5]);\n    }\n\n    #[test]\n    fn triangle() {\n        let p1 = Point::new(1.0, 1.0);\n        let p2 = Point::new(2.0, 1.0);\n        let p3 = Point::new(1.5, 2.0);\n        let points = vec![p1, p2, p3];\n        test_jarvis(points, vec![]);\n    }\n\n    #[test]\n    fn rectangle() {\n        let p1 = Point::new(1.0, 1.0);\n        let p2 = Point::new(2.0, 1.0);\n        let p3 = Point::new(2.0, 2.0);\n        let p4 = Point::new(1.0, 2.0);\n        let points = vec![p1, p2, p3, p4];\n        test_jarvis(points, vec![]);\n    }\n\n    #[test]\n    fn triangle_with_points_in_middle() {\n        let p1 = Point::new(1.0, 1.0);\n        let p2 = Point::new(2.0, 1.0);\n        let p3 = Point::new(1.5, 2.0);\n        let p4 = Point::new(1.5, 1.5);\n        let p5 = Point::new(1.2, 1.3);\n        let p6 = Point::new(1.8, 1.2);\n        let p7 = Point::new(1.5, 1.9);\n        let hull = vec![p1, p2, p3];\n        let others = vec![p4, p5, p6, p7];\n        test_jarvis(hull, others);\n    }\n\n    #[test]\n    fn rectangle_with_points_in_middle() {\n        let p1 = Point::new(1.0, 1.0);\n        let p2 = Point::new(2.0, 1.0);\n        let p3 = Point::new(2.0, 2.0);\n        let p4 = Point::new(1.0, 2.0);\n        let p5 = Point::new(1.5, 1.5);\n        let p6 = Point::new(1.2, 1.3);\n        let p7 = Point::new(1.8, 1.2);\n        let p8 = Point::new(1.9, 1.7);\n        let p9 = Point::new(1.4, 1.9);\n        let hull = vec![p1, p2, p3, p4];\n        let others = vec![p5, p6, p7, p8, p9];\n        test_jarvis(hull, others);\n    }\n\n    #[test]\n    fn star() {\n        // A single stroke star shape (kind of). Only the tips(p1-5) are part of the convex hull. The\n        // other points would create angles >180 degrees if they were part of the polygon.\n        let p1 = Point::new(-5.0, 6.0);\n        let p2 = Point::new(-11.0, 0.0);\n        let p3 = Point::new(-9.0, -8.0);\n        let p4 = Point::new(4.0, 4.0);\n        let p5 = Point::new(6.0, -7.0);\n        let p6 = Point::new(-7.0, -2.0);\n        let p7 = Point::new(-2.0, -4.0);\n        let p8 = Point::new(0.0, 1.0);\n        let p9 = Point::new(1.0, 0.0);\n        let p10 = Point::new(-6.0, 1.0);\n        let hull = vec![p1, p2, p3, p4, p5];\n        let others = vec![p6, p7, p8, p9, p10];\n        test_jarvis(hull, others);\n    }\n\n    #[test]\n    fn rectangle_with_points_on_same_line() {\n        let p1 = Point::new(1.0, 1.0);\n        let p2 = Point::new(2.0, 1.0);\n        let p3 = Point::new(2.0, 2.0);\n        let p4 = Point::new(1.0, 2.0);\n        let p5 = Point::new(1.5, 1.0);\n        let p6 = Point::new(1.0, 1.5);\n        let p7 = Point::new(2.0, 1.5);\n        let p8 = Point::new(1.5, 2.0);\n        let hull = vec![p1, p2, p3, p4];\n        let others = vec![p5, p6, p7, p8];\n        test_jarvis(hull, others);\n    }\n}\n"
  },
  {
    "path": "src/geometry/mod.rs",
    "content": "mod closest_points;\nmod graham_scan;\nmod jarvis_scan;\nmod point;\nmod polygon_points;\nmod ramer_douglas_peucker;\nmod segment;\n\npub use self::closest_points::closest_points;\npub use self::graham_scan::graham_scan;\npub use self::jarvis_scan::jarvis_march;\npub use self::point::Point;\npub use self::polygon_points::lattice_points;\npub use self::ramer_douglas_peucker::ramer_douglas_peucker;\npub use self::segment::Segment;\n"
  },
  {
    "path": "src/geometry/point.rs",
    "content": "use std::ops::Sub;\n\n#[derive(Clone, Debug, PartialEq)]\npub struct Point {\n    pub x: f64,\n    pub y: f64,\n}\n\nimpl Point {\n    pub fn new(x: f64, y: f64) -> Point {\n        Point { x, y }\n    }\n\n    // Returns the orientation of consecutive segments ab and bc.\n    pub fn consecutive_orientation(&self, b: &Point, c: &Point) -> f64 {\n        let p1 = b - self;\n        let p2 = c - self;\n        p1.cross_prod(&p2)\n    }\n\n    pub fn cross_prod(&self, other: &Point) -> f64 {\n        self.x * other.y - self.y * other.x\n    }\n\n    pub fn euclidean_distance(&self, other: &Point) -> f64 {\n        ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt()\n    }\n}\n\nimpl Sub for &Point {\n    type Output = Point;\n\n    fn sub(self, other: Self) -> Point {\n        let x = self.x - other.x;\n        let y = self.y - other.y;\n        Point::new(x, y)\n    }\n}\n"
  },
  {
    "path": "src/geometry/polygon_points.rs",
    "content": "type Ll = i64;\ntype Pll = (Ll, Ll);\n\nfn cross(x1: Ll, y1: Ll, x2: Ll, y2: Ll) -> Ll {\n    x1 * y2 - x2 * y1\n}\n\npub fn polygon_area(pts: &[Pll]) -> Ll {\n    let mut ats = 0;\n    for i in 2..pts.len() {\n        ats += cross(\n            pts[i].0 - pts[0].0,\n            pts[i].1 - pts[0].1,\n            pts[i - 1].0 - pts[0].0,\n            pts[i - 1].1 - pts[0].1,\n        );\n    }\n    Ll::abs(ats / 2)\n}\n\nfn gcd(mut a: Ll, mut b: Ll) -> Ll {\n    while b != 0 {\n        let temp = b;\n        b = a % b;\n        a = temp;\n    }\n    a\n}\n\nfn boundary(pts: &[Pll]) -> Ll {\n    let mut ats = pts.len() as Ll;\n    for i in 0..pts.len() {\n        let deltax = pts[i].0 - pts[(i + 1) % pts.len()].0;\n        let deltay = pts[i].1 - pts[(i + 1) % pts.len()].1;\n        ats += Ll::abs(gcd(deltax, deltay)) - 1;\n    }\n    ats\n}\n\npub fn lattice_points(pts: &[Pll]) -> Ll {\n    let bounds = boundary(pts);\n    let area = polygon_area(pts);\n    area + 1 - bounds / 2\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_calculate_cross() {\n        assert_eq!(cross(1, 2, 3, 4), 4 - 3 * 2);\n    }\n\n    #[test]\n    fn test_polygon_3_coordinates() {\n        let pts = vec![(0, 0), (0, 3), (4, 0)];\n        assert_eq!(polygon_area(&pts), 6);\n    }\n\n    #[test]\n    fn test_polygon_4_coordinates() {\n        let pts = vec![(0, 0), (0, 2), (2, 2), (2, 0)];\n        assert_eq!(polygon_area(&pts), 4);\n    }\n\n    #[test]\n    fn test_gcd_multiple_of_common_factor() {\n        assert_eq!(gcd(14, 28), 14);\n    }\n\n    #[test]\n    fn test_boundary() {\n        let pts = vec![(0, 0), (0, 3), (0, 4), (2, 2)];\n        assert_eq!(boundary(&pts), 8);\n    }\n\n    #[test]\n    fn test_lattice_points() {\n        let pts = vec![(1, 1), (5, 1), (5, 4)];\n        let result = lattice_points(&pts);\n        assert_eq!(result, 3);\n    }\n}\n"
  },
  {
    "path": "src/geometry/ramer_douglas_peucker.rs",
    "content": "use crate::geometry::Point;\n\npub fn ramer_douglas_peucker(points: &[Point], epsilon: f64) -> Vec<Point> {\n    if points.len() < 3 {\n        return points.to_vec();\n    }\n    let mut dmax = 0.0;\n    let mut index = 0;\n    let end = points.len() - 1;\n\n    for i in 1..end {\n        let d = perpendicular_distance(&points[i], &points[0], &points[end]);\n        if d > dmax {\n            index = i;\n            dmax = d;\n        }\n    }\n\n    if dmax > epsilon {\n        let mut results = ramer_douglas_peucker(&points[..=index], epsilon);\n        results.pop();\n        results.extend(ramer_douglas_peucker(&points[index..], epsilon));\n        results\n    } else {\n        vec![points[0].clone(), points[end].clone()]\n    }\n}\n\nfn perpendicular_distance(p: &Point, a: &Point, b: &Point) -> f64 {\n    let num = (b.y - a.y) * p.x - (b.x - a.x) * p.y + b.x * a.y - b.y * a.x;\n    let den = a.euclidean_distance(b);\n    num.abs() / den\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_perpendicular_distance {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (p, a, b, expected) = $test_case;\n                    assert_eq!(perpendicular_distance(&p, &a, &b), expected);\n                    assert_eq!(perpendicular_distance(&p, &b, &a), expected);\n                }\n            )*\n        };\n    }\n\n    test_perpendicular_distance! {\n        basic: (Point::new(4.0, 0.0), Point::new(0.0, 0.0), Point::new(0.0, 3.0), 4.0),\n        basic_shifted_1: (Point::new(4.0, 1.0), Point::new(0.0, 1.0), Point::new(0.0, 4.0), 4.0),\n        basic_shifted_2: (Point::new(2.0, 1.0), Point::new(-2.0, 1.0), Point::new(-2.0, 4.0), 4.0),\n    }\n\n    #[test]\n    fn test_ramer_douglas_peucker_polygon() {\n        let a = Point::new(0.0, 0.0);\n        let b = Point::new(1.0, 0.0);\n        let c = Point::new(2.0, 0.0);\n        let d = Point::new(2.0, 1.0);\n        let e = Point::new(2.0, 2.0);\n        let f = Point::new(1.0, 2.0);\n        let g = Point::new(0.0, 2.0);\n        let h = Point::new(0.0, 1.0);\n        let polygon = vec![\n            a.clone(),\n            b,\n            c.clone(),\n            d,\n            e.clone(),\n            f,\n            g.clone(),\n            h.clone(),\n        ];\n        let epsilon = 0.7;\n        let result = ramer_douglas_peucker(&polygon, epsilon);\n        assert_eq!(result, vec![a, c, e, g, h]);\n    }\n\n    #[test]\n    fn test_ramer_douglas_peucker_polygonal_chain() {\n        let a = Point::new(0., 0.);\n        let b = Point::new(2., 0.5);\n        let c = Point::new(3., 3.);\n        let d = Point::new(6., 3.);\n        let e = Point::new(8., 4.);\n\n        let points = vec![a.clone(), b, c, d, e.clone()];\n\n        let epsilon = 3.; // The epsilon is quite large, so the result will be a single line\n        let result = ramer_douglas_peucker(&points, epsilon);\n        assert_eq!(result, vec![a, e]);\n    }\n\n    #[test]\n    fn test_less_than_three_points() {\n        let a = Point::new(0., 0.);\n        let b = Point::new(1., 1.);\n\n        let epsilon = 0.1;\n\n        assert_eq!(ramer_douglas_peucker(&[], epsilon), vec![]);\n        assert_eq!(\n            ramer_douglas_peucker(std::slice::from_ref(&a), epsilon),\n            vec![a.clone()]\n        );\n        assert_eq!(\n            ramer_douglas_peucker(&[a.clone(), b.clone()], epsilon),\n            vec![a, b]\n        );\n    }\n}\n"
  },
  {
    "path": "src/geometry/segment.rs",
    "content": "use super::Point;\n\nconst TOLERANCE: f64 = 0.0001;\n\npub struct Segment {\n    pub a: Point,\n    pub b: Point,\n}\n\nimpl Segment {\n    pub fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Segment {\n        Segment {\n            a: Point::new(x1, y1),\n            b: Point::new(x2, y2),\n        }\n    }\n\n    pub fn from_points(a: Point, b: Point) -> Segment {\n        Segment { a, b }\n    }\n\n    pub fn direction(&self, p: &Point) -> f64 {\n        let a = Point::new(p.x - self.a.x, p.y - self.a.y);\n        let b = Point::new(self.b.x - self.a.x, self.b.y - self.a.y);\n        a.cross_prod(&b)\n    }\n\n    pub fn is_vertical(&self) -> bool {\n        self.a.x == self.b.x\n    }\n\n    // returns (slope, y-intercept)\n    pub fn get_line_equation(&self) -> (f64, f64) {\n        let slope = (self.a.y - self.b.y) / (self.a.x - self.b.x);\n        let y_intercept = self.a.y - slope * self.a.x;\n        (slope, y_intercept)\n    }\n\n    // Compute the value of y at x. Uses the line equation, and assumes the segment\n    // has infinite length.\n    pub fn compute_y_at_x(&self, x: f64) -> f64 {\n        let (slope, y_intercept) = self.get_line_equation();\n        slope * x + y_intercept\n    }\n\n    pub fn is_colinear(&self, p: &Point) -> bool {\n        if self.is_vertical() {\n            p.x == self.a.x\n        } else {\n            (self.compute_y_at_x(p.x) - p.y).abs() < TOLERANCE\n        }\n    }\n\n    // p must be colinear with the segment\n    pub fn colinear_point_on_segment(&self, p: &Point) -> bool {\n        assert!(self.is_colinear(p), \"p must be colinear!\");\n        let (low_x, high_x) = if self.a.x < self.b.x {\n            (self.a.x, self.b.x)\n        } else {\n            (self.b.x, self.a.x)\n        };\n        let (low_y, high_y) = if self.a.y < self.b.y {\n            (self.a.y, self.b.y)\n        } else {\n            (self.b.y, self.a.y)\n        };\n\n        p.x >= low_x && p.x <= high_x && p.y >= low_y && p.y <= high_y\n    }\n\n    pub fn on_segment(&self, p: &Point) -> bool {\n        if !self.is_colinear(p) {\n            return false;\n        }\n        self.colinear_point_on_segment(p)\n    }\n\n    pub fn intersects(&self, other: &Segment) -> bool {\n        let direction1 = self.direction(&other.a);\n        let direction2 = self.direction(&other.b);\n        let direction3 = other.direction(&self.a);\n        let direction4 = other.direction(&self.b);\n\n        // If the segments saddle each others' endpoints, they intersect\n        if ((direction1 > 0.0 && direction2 < 0.0) || (direction1 < 0.0 && direction2 > 0.0))\n            && ((direction3 > 0.0 && direction4 < 0.0) || (direction3 < 0.0 && direction4 > 0.0))\n        {\n            return true;\n        }\n\n        // Edge cases where an endpoint lies on a segment\n        (direction1 == 0.0 && self.colinear_point_on_segment(&other.a))\n            || (direction2 == 0.0 && self.colinear_point_on_segment(&other.b))\n            || (direction3 == 0.0 && other.colinear_point_on_segment(&self.a))\n            || (direction4 == 0.0 && other.colinear_point_on_segment(&self.b))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::Point;\n    use super::Segment;\n\n    #[test]\n    fn colinear() {\n        let segment = Segment::new(2.0, 3.0, 6.0, 5.0);\n        assert_eq!((0.5, 2.0), segment.get_line_equation());\n\n        assert!(segment.is_colinear(&Point::new(2.0, 3.0)));\n        assert!(segment.is_colinear(&Point::new(6.0, 5.0)));\n        assert!(segment.is_colinear(&Point::new(0.0, 2.0)));\n        assert!(segment.is_colinear(&Point::new(-5.0, -0.5)));\n        assert!(segment.is_colinear(&Point::new(10.0, 7.0)));\n\n        assert!(!segment.is_colinear(&Point::new(0.0, 0.0)));\n        assert!(!segment.is_colinear(&Point::new(1.9, 3.0)));\n        assert!(!segment.is_colinear(&Point::new(2.1, 3.0)));\n        assert!(!segment.is_colinear(&Point::new(2.0, 2.9)));\n        assert!(!segment.is_colinear(&Point::new(2.0, 3.1)));\n        assert!(!segment.is_colinear(&Point::new(5.9, 5.0)));\n        assert!(!segment.is_colinear(&Point::new(6.1, 5.0)));\n        assert!(!segment.is_colinear(&Point::new(6.0, 4.9)));\n        assert!(!segment.is_colinear(&Point::new(6.0, 5.1)));\n    }\n\n    #[test]\n    fn colinear_vertical() {\n        let segment = Segment::new(2.0, 3.0, 2.0, 5.0);\n        assert!(segment.is_colinear(&Point::new(2.0, 1.0)));\n        assert!(segment.is_colinear(&Point::new(2.0, 3.0)));\n        assert!(segment.is_colinear(&Point::new(2.0, 4.0)));\n        assert!(segment.is_colinear(&Point::new(2.0, 5.0)));\n        assert!(segment.is_colinear(&Point::new(2.0, 6.0)));\n\n        assert!(!segment.is_colinear(&Point::new(1.0, 3.0)));\n        assert!(!segment.is_colinear(&Point::new(3.0, 3.0)));\n    }\n\n    fn test_intersect(s1: &Segment, s2: &Segment, result: bool) {\n        assert_eq!(s1.intersects(s2), result);\n        assert_eq!(s2.intersects(s1), result);\n    }\n\n    #[test]\n    fn intersects() {\n        let s1 = Segment::new(2.0, 3.0, 6.0, 5.0);\n        let s2 = Segment::new(-1.0, 9.0, 10.0, -3.0);\n        let s3 = Segment::new(-0.0, 10.0, 11.0, -2.0);\n        let s4 = Segment::new(100.0, 200.0, 40.0, 50.0);\n        test_intersect(&s1, &s2, true);\n        test_intersect(&s1, &s3, true);\n        test_intersect(&s2, &s3, false);\n        test_intersect(&s1, &s4, false);\n        test_intersect(&s2, &s4, false);\n        test_intersect(&s3, &s4, false);\n    }\n\n    #[test]\n    fn intersects_endpoint_on_segment() {\n        let s1 = Segment::new(2.0, 3.0, 6.0, 5.0);\n        let s2 = Segment::new(4.0, 4.0, -11.0, 20.0);\n        let s3 = Segment::new(4.0, 4.0, 14.0, -19.0);\n        test_intersect(&s1, &s2, true);\n        test_intersect(&s1, &s3, true);\n    }\n\n    #[test]\n    fn intersects_self() {\n        let s1 = Segment::new(2.0, 3.0, 6.0, 5.0);\n        let s2 = Segment::new(2.0, 3.0, 6.0, 5.0);\n        test_intersect(&s1, &s2, true);\n    }\n\n    #[test]\n    fn too_short_to_intersect() {\n        let s1 = Segment::new(2.0, 3.0, 6.0, 5.0);\n        let s2 = Segment::new(-1.0, 10.0, 3.0, 5.0);\n        let s3 = Segment::new(5.0, 3.0, 10.0, -11.0);\n        test_intersect(&s1, &s2, false);\n        test_intersect(&s1, &s3, false);\n        test_intersect(&s2, &s3, false);\n    }\n\n    #[test]\n    fn parallel_segments() {\n        let s1 = Segment::new(-5.0, 0.0, 5.0, 0.0);\n        let s2 = Segment::new(-5.0, 1.0, 5.0, 1.0);\n        let s3 = Segment::new(-5.0, -1.0, 5.0, -1.0);\n        test_intersect(&s1, &s2, false);\n        test_intersect(&s1, &s3, false);\n        test_intersect(&s2, &s3, false);\n    }\n}\n"
  },
  {
    "path": "src/graph/ant_colony_optimization.rs",
    "content": "//! Ant Colony Optimization (ACO) algorithm for solving the Travelling Salesman Problem (TSP).\n//!\n//! The Travelling Salesman Problem asks: \"Given a list of cities and the distances between\n//! each pair of cities, what is the shortest possible route that visits each city exactly\n//! once and returns to the origin city?\"\n//!\n//! The ACO algorithm uses artificial ants that build solutions iteratively. Each ant constructs\n//! a tour by probabilistically choosing the next city based on pheromone trails and heuristic\n//! information (distance). After all ants complete their tours, pheromone trails are updated,\n//! with stronger pheromones deposited on shorter routes. Over multiple iterations, this process\n//! converges toward finding good solutions to the TSP.\n//!\n//! # References\n//! - [Ant Colony Optimization Algorithms](https://en.wikipedia.org/wiki/Ant_colony_optimization_algorithms)\n//! - [Travelling Salesman Problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem)\n\nuse rand::RngExt;\nuse std::collections::HashSet;\n\n/// Represents a 2D city with coordinates\n#[derive(Debug, Clone, Copy, PartialEq)]\nstruct City {\n    x: f64,\n    y: f64,\n}\n\nimpl City {\n    /// Calculate Euclidean distance to another city\n    fn distance_to(&self, other: &City) -> f64 {\n        let dx = self.x - other.x;\n        let dy = self.y - other.y;\n        (dx * dx + dy * dy).sqrt()\n    }\n}\n\n/// Ant Colony Optimization solver for the Travelling Salesman Problem\nstruct AntColonyOptimization {\n    cities: Vec<City>,\n    pheromones: Vec<Vec<f64>>,\n    num_ants: usize,\n    num_iterations: usize,\n    evaporation_rate: f64,\n    pheromone_influence: f64,\n    distance_influence: f64,\n    pheromone_constant: f64,\n}\n\nimpl AntColonyOptimization {\n    /// Create a new ACO solver with the given cities and parameters\n    fn new(\n        cities: Vec<City>,\n        num_ants: usize,\n        num_iterations: usize,\n        evaporation_rate: f64,\n        pheromone_influence: f64,\n        distance_influence: f64,\n        pheromone_constant: f64,\n    ) -> Self {\n        let n = cities.len();\n        let pheromones = vec![vec![1.0; n]; n];\n        Self {\n            cities,\n            pheromones,\n            num_ants,\n            num_iterations,\n            evaporation_rate,\n            pheromone_influence,\n            distance_influence,\n            pheromone_constant,\n        }\n    }\n\n    /// Run the ACO algorithm and return the best solution found\n    fn solve(&mut self) -> Option<(Vec<usize>, f64)> {\n        if self.cities.is_empty() {\n            return None;\n        }\n\n        let mut best_route: Vec<usize> = Vec::new();\n        let mut best_distance = f64::INFINITY;\n\n        for _ in 0..self.num_iterations {\n            let routes = self.construct_solutions();\n\n            for route in &routes {\n                let distance = self.calculate_route_distance(route);\n                if distance < best_distance {\n                    best_distance = distance;\n                    best_route.clone_from(route);\n                }\n            }\n\n            self.update_pheromones(&routes);\n        }\n\n        if best_route.is_empty() {\n            None\n        } else {\n            Some((best_route, best_distance))\n        }\n    }\n\n    /// Construct solutions for all ants in one iteration\n    fn construct_solutions(&self) -> Vec<Vec<usize>> {\n        (0..self.num_ants)\n            .map(|_| self.construct_ant_solution())\n            .collect()\n    }\n\n    /// Construct a solution for a single ant\n    fn construct_ant_solution(&self) -> Vec<usize> {\n        let n = self.cities.len();\n        let mut route = Vec::with_capacity(n + 1);\n        let mut unvisited: HashSet<usize> = (0..n).collect();\n\n        // Start at city 0\n        let mut current = 0;\n        route.push(current);\n        unvisited.remove(&current);\n\n        // Visit remaining cities\n        while !unvisited.is_empty() {\n            current = self.select_next_city(current, &unvisited);\n            route.push(current);\n            unvisited.remove(&current);\n        }\n\n        // Return to starting city\n        route.push(0);\n        route\n    }\n\n    /// Select the next city to visit based on pheromone and distance\n    fn select_next_city(&self, current: usize, unvisited: &HashSet<usize>) -> usize {\n        let probabilities: Vec<(usize, f64)> = unvisited\n            .iter()\n            .map(|&city| {\n                let pheromone = self.pheromones[current][city];\n                let distance = self.cities[current].distance_to(&self.cities[city]);\n                let heuristic = 1.0 / distance;\n\n                let probability = pheromone.powf(self.pheromone_influence)\n                    * heuristic.powf(self.distance_influence);\n\n                (city, probability)\n            })\n            .collect();\n\n        // Roulette wheel selection\n        let total: f64 = probabilities.iter().map(|(_, p)| p).sum();\n        let mut rng = rand::rng();\n        let mut random_value = rng.random::<f64>() * total;\n\n        for (city, prob) in probabilities {\n            random_value -= prob;\n            if random_value <= 0.0 {\n                return city;\n            }\n        }\n\n        // Fallback to last city if rounding errors occur\n        *unvisited.iter().next().unwrap()\n    }\n\n    /// Calculate the total distance of a route\n    fn calculate_route_distance(&self, route: &[usize]) -> f64 {\n        route\n            .windows(2)\n            .map(|pair| self.cities[pair[0]].distance_to(&self.cities[pair[1]]))\n            .sum()\n    }\n\n    /// Update pheromone trails based on ant solutions\n    fn update_pheromones(&mut self, routes: &[Vec<usize>]) {\n        let n = self.cities.len();\n\n        // Evaporate pheromones\n        for i in 0..n {\n            for j in 0..n {\n                self.pheromones[i][j] *= self.evaporation_rate;\n            }\n        }\n\n        // Deposit new pheromones\n        for route in routes {\n            let distance = self.calculate_route_distance(route);\n            let deposit = self.pheromone_constant / distance;\n\n            for pair in route.windows(2) {\n                let (i, j) = (pair[0], pair[1]);\n                self.pheromones[i][j] += deposit;\n                self.pheromones[j][i] += deposit; // Symmetric for undirected graph\n            }\n        }\n    }\n}\n\n/// Solve the Travelling Salesman Problem using Ant Colony Optimization.\n///\n/// Given a list of cities (as (x, y) coordinates), finds a near-optimal route\n/// that visits each city exactly once and returns to the starting city.\n///\n/// # Arguments\n///\n/// * `cities` - Vector of (x, y) coordinate tuples representing city locations\n/// * `num_ants` - Number of ants per iteration (default: 10)\n/// * `num_iterations` - Number of iterations to run (default: 20)\n/// * `evaporation_rate` - Pheromone evaporation rate 0.0-1.0 (default: 0.7)\n/// * `alpha` - Influence of pheromone on decision making (default: 1.0)\n/// * `beta` - Influence of distance on decision making (default: 5.0)\n/// * `q` - Pheromone deposit constant (default: 10.0)\n///\n/// # Returns\n///\n/// `Some((route, distance))` where route is a vector of city indices and distance\n/// is the total route length, or `None` if the cities list is empty.\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::graph::ant_colony_optimization;\n///\n/// let cities = vec![\n///     (0.0, 0.0),\n///     (0.0, 5.0),\n///     (3.0, 8.0),\n///     (8.0, 10.0),\n/// ];\n///\n/// let result = ant_colony_optimization(cities, 10, 20, 0.7, 1.0, 5.0, 10.0);\n/// if let Some((route, distance)) = result {\n///     println!(\"Best route: {:?}\", route);\n///     println!(\"Distance: {}\", distance);\n/// }\n/// ```\npub fn ant_colony_optimization(\n    cities: Vec<(f64, f64)>,\n    num_ants: usize,\n    num_iterations: usize,\n    evaporation_rate: f64,\n    alpha: f64,\n    beta: f64,\n    q: f64,\n) -> Option<(Vec<usize>, f64)> {\n    if cities.is_empty() {\n        return None;\n    }\n\n    let city_structs: Vec<City> = cities.into_iter().map(|(x, y)| City { x, y }).collect();\n\n    let mut aco = AntColonyOptimization::new(\n        city_structs,\n        num_ants,\n        num_iterations,\n        evaporation_rate,\n        alpha,\n        beta,\n        q,\n    );\n\n    aco.solve()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_city_distance() {\n        let city1 = City { x: 0.0, y: 0.0 };\n        let city2 = City { x: 3.0, y: 4.0 };\n        assert!((city1.distance_to(&city2) - 5.0).abs() < 1e-10);\n    }\n\n    #[test]\n    fn test_city_distance_negative() {\n        let city1 = City { x: 0.0, y: 0.0 };\n        let city2 = City { x: -3.0, y: -4.0 };\n        assert!((city1.distance_to(&city2) - 5.0).abs() < 1e-10);\n    }\n\n    #[test]\n    fn test_aco_simple() {\n        let cities = vec![(0.0, 0.0), (2.0, 2.0)];\n\n        let result = ant_colony_optimization(cities, 5, 5, 0.7, 1.0, 5.0, 10.0);\n\n        assert!(result.is_some());\n        let (route, distance) = result.unwrap();\n\n        // Expected route: [0, 1, 0]\n        assert_eq!(route, vec![0, 1, 0]);\n\n        // Expected distance: 2 * sqrt(8) ≈ 5.656854\n        let expected_distance = 2.0 * (8.0_f64).sqrt();\n        assert!((distance - expected_distance).abs() < 0.001);\n    }\n\n    #[test]\n    fn test_aco_larger_problem() {\n        let cities = vec![\n            (0.0, 0.0),\n            (0.0, 5.0),\n            (3.0, 8.0),\n            (8.0, 10.0),\n            (12.0, 8.0),\n            (12.0, 4.0),\n            (8.0, 0.0),\n            (6.0, 2.0),\n        ];\n\n        let result = ant_colony_optimization(cities.clone(), 10, 20, 0.7, 1.0, 5.0, 10.0);\n\n        assert!(result.is_some());\n        let (route, distance) = result.unwrap();\n\n        // Verify the route visits all cities\n        assert_eq!(route.len(), cities.len() + 1);\n        assert_eq!(route.first(), Some(&0));\n        assert_eq!(route.last(), Some(&0));\n\n        // Verify all cities are visited exactly once (except start/end)\n        let mut visited = std::collections::HashSet::new();\n        for &city in &route[0..route.len() - 1] {\n            assert!(visited.insert(city), \"City {city} visited multiple times\");\n        }\n        assert_eq!(visited.len(), cities.len());\n\n        // Distance should be reasonable (not infinity)\n        assert!(distance > 0.0);\n        assert!(distance < f64::INFINITY);\n    }\n\n    #[test]\n    fn test_aco_empty_cities() {\n        let cities: Vec<(f64, f64)> = Vec::new();\n        let result = ant_colony_optimization(cities, 10, 20, 0.7, 1.0, 5.0, 10.0);\n        assert!(result.is_none());\n    }\n\n    #[test]\n    fn test_aco_single_city() {\n        let cities = vec![(0.0, 0.0)];\n        let result = ant_colony_optimization(cities, 10, 20, 0.7, 1.0, 5.0, 10.0);\n\n        assert!(result.is_some());\n        let (route, distance) = result.unwrap();\n        assert_eq!(route, vec![0, 0]);\n        assert!((distance - 0.0).abs() < 1e-10);\n    }\n\n    #[test]\n    fn test_default_parameters() {\n        let cities = vec![(0.0, 0.0), (1.0, 1.0), (2.0, 0.0)];\n        let result = ant_colony_optimization(cities, 10, 20, 0.7, 1.0, 5.0, 10.0);\n        assert!(result.is_some());\n    }\n\n    #[test]\n    fn test_zero_ants() {\n        // Test with zero ants - should return None as no solutions are constructed\n        let cities = vec![(0.0, 0.0), (1.0, 1.0), (2.0, 0.0)];\n        let result = ant_colony_optimization(cities, 0, 20, 0.7, 1.0, 5.0, 10.0);\n        assert!(result.is_none());\n    }\n\n    #[test]\n    fn test_zero_iterations() {\n        // Test with zero iterations - should return None as no solutions are found\n        let cities = vec![(0.0, 0.0), (1.0, 1.0), (2.0, 0.0)];\n        let result = ant_colony_optimization(cities, 10, 0, 0.7, 1.0, 5.0, 10.0);\n        assert!(result.is_none());\n    }\n\n    #[test]\n    fn test_extreme_parameters() {\n        // Test with extreme beta value and many iterations to potentially trigger\n        // the rounding fallback in select_next_city\n        let cities = vec![(0.0, 0.0), (1.0, 0.0), (2.0, 0.0), (3.0, 0.0), (4.0, 0.0)];\n        // Very high beta makes distance dominate, low alpha reduces pheromone influence\n        // This creates extreme probability distributions that may trigger rounding edge cases\n        let result = ant_colony_optimization(cities, 50, 100, 0.5, 0.1, 100.0, 10.0);\n        assert!(result.is_some());\n        let (route, _) = result.unwrap();\n        // Should still produce valid route\n        assert_eq!(route.len(), 6); // 5 cities + return to start\n    }\n}\n"
  },
  {
    "path": "src/graph/astar.rs",
    "content": "use std::{\n    collections::{BTreeMap, BinaryHeap},\n    ops::Add,\n};\n\nuse num_traits::Zero;\n\ntype Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;\n\n#[derive(Clone, Debug, Eq, PartialEq)]\nstruct Candidate<V, E> {\n    estimated_weight: E,\n    real_weight: E,\n    state: V,\n}\n\nimpl<V: Ord + Copy, E: Ord + Copy> PartialOrd for Candidate<V, E> {\n    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {\n        // Note the inverted order; we want nodes with lesser weight to have\n        // higher priority\n        Some(self.cmp(other))\n    }\n}\n\nimpl<V: Ord + Copy, E: Ord + Copy> Ord for Candidate<V, E> {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        // Note the inverted order; we want nodes with lesser weight to have\n        // higher priority\n        other.estimated_weight.cmp(&self.estimated_weight)\n    }\n}\n\npub fn astar<V: Ord + Copy, E: Ord + Copy + Add<Output = E> + Zero>(\n    graph: &Graph<V, E>,\n    start: V,\n    target: V,\n    heuristic: impl Fn(V) -> E,\n) -> Option<(E, Vec<V>)> {\n    // traversal front\n    let mut queue = BinaryHeap::new();\n    // maps each node to its predecessor in the final path\n    let mut previous = BTreeMap::new();\n    // weights[v] is the accumulated weight from start to v\n    let mut weights = BTreeMap::new();\n    // initialize traversal\n    weights.insert(start, E::zero());\n    queue.push(Candidate {\n        estimated_weight: heuristic(start),\n        real_weight: E::zero(),\n        state: start,\n    });\n    while let Some(Candidate {\n        real_weight,\n        state: current,\n        ..\n    }) = queue.pop()\n    {\n        if current == target {\n            break;\n        }\n        for (&next, &weight) in &graph[&current] {\n            let real_weight = real_weight + weight;\n            if weights\n                .get(&next)\n                .is_none_or(|&weight| real_weight < weight)\n            {\n                // current allows us to reach next with lower weight (or at all)\n                // add next to the front\n                let estimated_weight = real_weight + heuristic(next);\n                weights.insert(next, real_weight);\n                queue.push(Candidate {\n                    estimated_weight,\n                    real_weight,\n                    state: next,\n                });\n                previous.insert(next, current);\n            }\n        }\n    }\n    let weight = if let Some(&weight) = weights.get(&target) {\n        weight\n    } else {\n        // we did not reach target from start\n        return None;\n    };\n    // build path in reverse\n    let mut current = target;\n    let mut path = vec![current];\n    while current != start {\n        let prev = previous\n            .get(&current)\n            .copied()\n            .expect(\"We reached the target, but are unable to reconsistute the path\");\n        current = prev;\n        path.push(current);\n    }\n    path.reverse();\n    Some((weight, path))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{astar, Graph};\n    use num_traits::Zero;\n    use std::collections::BTreeMap;\n\n    // the null heuristic make A* equivalent to Dijkstra\n    fn null_heuristic<V, E: Zero>(_v: V) -> E {\n        E::zero()\n    }\n\n    fn add_edge<V: Ord + Copy, E: Ord>(graph: &mut Graph<V, E>, v1: V, v2: V, c: E) {\n        graph.entry(v1).or_default().insert(v2, c);\n        graph.entry(v2).or_default();\n    }\n\n    #[test]\n    fn single_vertex() {\n        let mut graph: Graph<usize, usize> = BTreeMap::new();\n        graph.insert(0, BTreeMap::new());\n\n        assert_eq!(astar(&graph, 0, 0, null_heuristic), Some((0, vec![0])));\n        assert_eq!(astar(&graph, 0, 1, null_heuristic), None);\n    }\n\n    #[test]\n    fn single_edge() {\n        let mut graph = BTreeMap::new();\n        add_edge(&mut graph, 0, 1, 2);\n\n        assert_eq!(astar(&graph, 0, 1, null_heuristic), Some((2, vec![0, 1])));\n        assert_eq!(astar(&graph, 1, 0, null_heuristic), None);\n    }\n\n    #[test]\n    fn graph_1() {\n        let mut graph = BTreeMap::new();\n        add_edge(&mut graph, 'a', 'c', 12);\n        add_edge(&mut graph, 'a', 'd', 60);\n        add_edge(&mut graph, 'b', 'a', 10);\n        add_edge(&mut graph, 'c', 'b', 20);\n        add_edge(&mut graph, 'c', 'd', 32);\n        add_edge(&mut graph, 'e', 'a', 7);\n\n        // from a\n        assert_eq!(\n            astar(&graph, 'a', 'a', null_heuristic),\n            Some((0, vec!['a']))\n        );\n        assert_eq!(\n            astar(&graph, 'a', 'b', null_heuristic),\n            Some((32, vec!['a', 'c', 'b']))\n        );\n        assert_eq!(\n            astar(&graph, 'a', 'c', null_heuristic),\n            Some((12, vec!['a', 'c']))\n        );\n        assert_eq!(\n            astar(&graph, 'a', 'd', null_heuristic),\n            Some((12 + 32, vec!['a', 'c', 'd']))\n        );\n        assert_eq!(astar(&graph, 'a', 'e', null_heuristic), None);\n\n        // from b\n        assert_eq!(\n            astar(&graph, 'b', 'a', null_heuristic),\n            Some((10, vec!['b', 'a']))\n        );\n        assert_eq!(\n            astar(&graph, 'b', 'b', null_heuristic),\n            Some((0, vec!['b']))\n        );\n        assert_eq!(\n            astar(&graph, 'b', 'c', null_heuristic),\n            Some((10 + 12, vec!['b', 'a', 'c']))\n        );\n        assert_eq!(\n            astar(&graph, 'b', 'd', null_heuristic),\n            Some((10 + 12 + 32, vec!['b', 'a', 'c', 'd']))\n        );\n        assert_eq!(astar(&graph, 'b', 'e', null_heuristic), None);\n\n        // from c\n        assert_eq!(\n            astar(&graph, 'c', 'a', null_heuristic),\n            Some((20 + 10, vec!['c', 'b', 'a']))\n        );\n        assert_eq!(\n            astar(&graph, 'c', 'b', null_heuristic),\n            Some((20, vec!['c', 'b']))\n        );\n        assert_eq!(\n            astar(&graph, 'c', 'c', null_heuristic),\n            Some((0, vec!['c']))\n        );\n        assert_eq!(\n            astar(&graph, 'c', 'd', null_heuristic),\n            Some((32, vec!['c', 'd']))\n        );\n        assert_eq!(astar(&graph, 'c', 'e', null_heuristic), None);\n\n        // from d\n        assert_eq!(astar(&graph, 'd', 'a', null_heuristic), None);\n        assert_eq!(astar(&graph, 'd', 'b', null_heuristic), None);\n        assert_eq!(astar(&graph, 'd', 'c', null_heuristic), None);\n        assert_eq!(\n            astar(&graph, 'd', 'd', null_heuristic),\n            Some((0, vec!['d']))\n        );\n        assert_eq!(astar(&graph, 'd', 'e', null_heuristic), None);\n\n        // from e\n        assert_eq!(\n            astar(&graph, 'e', 'a', null_heuristic),\n            Some((7, vec!['e', 'a']))\n        );\n        assert_eq!(\n            astar(&graph, 'e', 'b', null_heuristic),\n            Some((7 + 12 + 20, vec!['e', 'a', 'c', 'b']))\n        );\n        assert_eq!(\n            astar(&graph, 'e', 'c', null_heuristic),\n            Some((7 + 12, vec!['e', 'a', 'c']))\n        );\n        assert_eq!(\n            astar(&graph, 'e', 'd', null_heuristic),\n            Some((7 + 12 + 32, vec!['e', 'a', 'c', 'd']))\n        );\n        assert_eq!(\n            astar(&graph, 'e', 'e', null_heuristic),\n            Some((0, vec!['e']))\n        );\n    }\n\n    #[test]\n    fn test_heuristic() {\n        // make a grid\n        let mut graph = BTreeMap::new();\n        let rows = 100;\n        let cols = 100;\n        for row in 0..rows {\n            for col in 0..cols {\n                add_edge(&mut graph, (row, col), (row + 1, col), 1);\n                add_edge(&mut graph, (row, col), (row, col + 1), 1);\n                add_edge(&mut graph, (row, col), (row + 1, col + 1), 1);\n                add_edge(&mut graph, (row + 1, col), (row, col), 1);\n                add_edge(&mut graph, (row + 1, col + 1), (row, col), 1);\n            }\n        }\n\n        // Dijkstra would explore most of the 101 × 101 nodes\n        // the heuristic should allow exploring only about 200 nodes\n        let now = std::time::Instant::now();\n        let res = astar(&graph, (0, 0), (100, 90), |(i, j)| 100 - i + 90 - j);\n        assert!(now.elapsed() < std::time::Duration::from_millis(10));\n\n        let (weight, path) = res.unwrap();\n        assert_eq!(weight, 100);\n        assert_eq!(path.len(), 101);\n    }\n}\n"
  },
  {
    "path": "src/graph/bellman_ford.rs",
    "content": "use std::collections::BTreeMap;\nuse std::ops::Add;\n\nuse std::ops::Neg;\n\ntype Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;\n\n// performs the Bellman-Ford algorithm on the given graph from the given start\n// the graph is an undirected graph\n//\n// if there is a negative weighted loop it returns None\n// else it returns a map that for each reachable vertex associates the distance and the predecessor\n// since the start has no predecessor but is reachable, map[start] will be None\npub fn bellman_ford<\n    V: Ord + Copy,\n    E: Ord + Copy + Add<Output = E> + Neg<Output = E> + std::ops::Sub<Output = E>,\n>(\n    graph: &Graph<V, E>,\n    start: &V,\n) -> Option<BTreeMap<V, Option<(V, E)>>> {\n    let mut ans: BTreeMap<V, Option<(V, E)>> = BTreeMap::new();\n\n    ans.insert(*start, None);\n\n    for _ in 1..(graph.len()) {\n        for (u, edges) in graph {\n            let dist_u = match ans.get(u) {\n                Some(Some((_, d))) => Some(*d),\n                Some(None) => None,\n                None => continue,\n            };\n\n            for (v, d) in edges {\n                match ans.get(v) {\n                    Some(Some((_, dist)))\n                        // if this is a longer path, do nothing\n                        if match dist_u {\n                            Some(dist_u) => dist_u + *d >= *dist,\n                            None => d >= dist,\n                        } => {}\n                    Some(None) => {\n                        match dist_u {\n                            // if dist_u + d < 0 there is a negative loop going by start\n                            // else it's just a longer path\n                            Some(dist_u) if dist_u >= -*d => {}\n                            // negative self edge or negative loop\n                            _ => {\n                                if *d > *d + *d {\n                                    return None;\n                                }\n                            }\n                        };\n                    }\n                    // it's a shorter path: either dist_v was infinite or it was longer than dist_u + d\n                    _ => {\n                        ans.insert(\n                            *v,\n                            Some((\n                                *u,\n                                match dist_u {\n                                    Some(dist) => dist + *d,\n                                    None => *d,\n                                },\n                            )),\n                        );\n                    }\n                }\n            }\n        }\n    }\n\n    for (u, edges) in graph {\n        for (v, d) in edges {\n            match (ans.get(u), ans.get(v)) {\n                (Some(None), Some(None)) if *d > *d + *d => return None,\n                (Some(None), Some(Some((_, dv)))) if d < dv => return None,\n                (Some(Some((_, du))), Some(None)) if *du < -*d => return None,\n                (Some(Some((_, du))), Some(Some((_, dv)))) if *du + *d < *dv => return None,\n                (_, _) => {}\n            }\n        }\n    }\n\n    Some(ans)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{bellman_ford, Graph};\n    use std::collections::BTreeMap;\n\n    fn add_edge<V: Ord + Copy, E: Ord>(graph: &mut Graph<V, E>, v1: V, v2: V, c: E) {\n        graph.entry(v1).or_default().insert(v2, c);\n        graph.entry(v2).or_default();\n    }\n\n    #[test]\n    fn single_vertex() {\n        let mut graph: Graph<isize, isize> = BTreeMap::new();\n        graph.insert(0, BTreeMap::new());\n\n        let mut dists = BTreeMap::new();\n        dists.insert(0, None);\n\n        assert_eq!(bellman_ford(&graph, &0), Some(dists));\n    }\n\n    #[test]\n    fn single_edge() {\n        let mut graph = BTreeMap::new();\n        add_edge(&mut graph, 0, 1, 2);\n\n        let mut dists_0 = BTreeMap::new();\n        dists_0.insert(0, None);\n        dists_0.insert(1, Some((0, 2)));\n\n        assert_eq!(bellman_ford(&graph, &0), Some(dists_0));\n\n        let mut dists_1 = BTreeMap::new();\n        dists_1.insert(1, None);\n\n        assert_eq!(bellman_ford(&graph, &1), Some(dists_1));\n    }\n\n    #[test]\n    fn tree_1() {\n        let mut graph = BTreeMap::new();\n        let mut dists = BTreeMap::new();\n        dists.insert(1, None);\n        for i in 1..100 {\n            add_edge(&mut graph, i, i * 2, i * 2);\n            add_edge(&mut graph, i, i * 2 + 1, i * 2 + 1);\n\n            match dists[&i] {\n                Some((_, d)) => {\n                    dists.insert(i * 2, Some((i, d + i * 2)));\n                    dists.insert(i * 2 + 1, Some((i, d + i * 2 + 1)));\n                }\n                None => {\n                    dists.insert(i * 2, Some((i, i * 2)));\n                    dists.insert(i * 2 + 1, Some((i, i * 2 + 1)));\n                }\n            }\n        }\n\n        assert_eq!(bellman_ford(&graph, &1), Some(dists));\n    }\n\n    #[test]\n    fn graph_1() {\n        let mut graph = BTreeMap::new();\n        add_edge(&mut graph, 'a', 'c', 12);\n        add_edge(&mut graph, 'a', 'd', 60);\n        add_edge(&mut graph, 'b', 'a', 10);\n        add_edge(&mut graph, 'c', 'b', 20);\n        add_edge(&mut graph, 'c', 'd', 32);\n        add_edge(&mut graph, 'e', 'a', 7);\n\n        let mut dists_a = BTreeMap::new();\n        dists_a.insert('a', None);\n        dists_a.insert('c', Some(('a', 12)));\n        dists_a.insert('d', Some(('c', 44)));\n        dists_a.insert('b', Some(('c', 32)));\n        assert_eq!(bellman_ford(&graph, &'a'), Some(dists_a));\n\n        let mut dists_b = BTreeMap::new();\n        dists_b.insert('b', None);\n        dists_b.insert('a', Some(('b', 10)));\n        dists_b.insert('c', Some(('a', 22)));\n        dists_b.insert('d', Some(('c', 54)));\n        assert_eq!(bellman_ford(&graph, &'b'), Some(dists_b));\n\n        let mut dists_c = BTreeMap::new();\n        dists_c.insert('c', None);\n        dists_c.insert('b', Some(('c', 20)));\n        dists_c.insert('d', Some(('c', 32)));\n        dists_c.insert('a', Some(('b', 30)));\n        assert_eq!(bellman_ford(&graph, &'c'), Some(dists_c));\n\n        let mut dists_d = BTreeMap::new();\n        dists_d.insert('d', None);\n        assert_eq!(bellman_ford(&graph, &'d'), Some(dists_d));\n\n        let mut dists_e = BTreeMap::new();\n        dists_e.insert('e', None);\n        dists_e.insert('a', Some(('e', 7)));\n        dists_e.insert('c', Some(('a', 19)));\n        dists_e.insert('d', Some(('c', 51)));\n        dists_e.insert('b', Some(('c', 39)));\n        assert_eq!(bellman_ford(&graph, &'e'), Some(dists_e));\n    }\n\n    #[test]\n    fn graph_2() {\n        let mut graph = BTreeMap::new();\n        add_edge(&mut graph, 0, 1, 6);\n        add_edge(&mut graph, 0, 3, 7);\n        add_edge(&mut graph, 1, 2, 5);\n        add_edge(&mut graph, 1, 3, 8);\n        add_edge(&mut graph, 1, 4, -4);\n        add_edge(&mut graph, 2, 1, -2);\n        add_edge(&mut graph, 3, 2, -3);\n        add_edge(&mut graph, 3, 4, 9);\n        add_edge(&mut graph, 4, 0, 3);\n        add_edge(&mut graph, 4, 2, 7);\n\n        let mut dists_0 = BTreeMap::new();\n        dists_0.insert(0, None);\n        dists_0.insert(1, Some((2, 2)));\n        dists_0.insert(2, Some((3, 4)));\n        dists_0.insert(3, Some((0, 7)));\n        dists_0.insert(4, Some((1, -2)));\n        assert_eq!(bellman_ford(&graph, &0), Some(dists_0));\n\n        let mut dists_1 = BTreeMap::new();\n        dists_1.insert(0, Some((4, -1)));\n        dists_1.insert(1, None);\n        dists_1.insert(2, Some((4, 3)));\n        dists_1.insert(3, Some((0, 6)));\n        dists_1.insert(4, Some((1, -4)));\n        assert_eq!(bellman_ford(&graph, &1), Some(dists_1));\n\n        let mut dists_2 = BTreeMap::new();\n        dists_2.insert(0, Some((4, -3)));\n        dists_2.insert(1, Some((2, -2)));\n        dists_2.insert(2, None);\n        dists_2.insert(3, Some((0, 4)));\n        dists_2.insert(4, Some((1, -6)));\n        assert_eq!(bellman_ford(&graph, &2), Some(dists_2));\n\n        let mut dists_3 = BTreeMap::new();\n        dists_3.insert(0, Some((4, -6)));\n        dists_3.insert(1, Some((2, -5)));\n        dists_3.insert(2, Some((3, -3)));\n        dists_3.insert(3, None);\n        dists_3.insert(4, Some((1, -9)));\n        assert_eq!(bellman_ford(&graph, &3), Some(dists_3));\n\n        let mut dists_4 = BTreeMap::new();\n        dists_4.insert(0, Some((4, 3)));\n        dists_4.insert(1, Some((2, 5)));\n        dists_4.insert(2, Some((4, 7)));\n        dists_4.insert(3, Some((0, 10)));\n        dists_4.insert(4, None);\n        assert_eq!(bellman_ford(&graph, &4), Some(dists_4));\n    }\n\n    #[test]\n    fn graph_with_negative_loop() {\n        let mut graph = BTreeMap::new();\n        add_edge(&mut graph, 0, 1, 6);\n        add_edge(&mut graph, 0, 3, 7);\n        add_edge(&mut graph, 1, 2, 5);\n        add_edge(&mut graph, 1, 3, 8);\n        add_edge(&mut graph, 1, 4, -4);\n        add_edge(&mut graph, 2, 1, -4);\n        add_edge(&mut graph, 3, 2, -3);\n        add_edge(&mut graph, 3, 4, 9);\n        add_edge(&mut graph, 4, 0, 3);\n        add_edge(&mut graph, 4, 2, 7);\n\n        assert_eq!(bellman_ford(&graph, &0), None);\n        assert_eq!(bellman_ford(&graph, &1), None);\n        assert_eq!(bellman_ford(&graph, &2), None);\n        assert_eq!(bellman_ford(&graph, &3), None);\n        assert_eq!(bellman_ford(&graph, &4), None);\n    }\n}\n"
  },
  {
    "path": "src/graph/bipartite_matching.rs",
    "content": "// Adjacency List\nuse std::collections::VecDeque;\ntype Graph = Vec<Vec<usize>>;\n\npub struct BipartiteMatching {\n    pub adj: Graph,\n    pub num_vertices_grp1: usize,\n    pub num_vertices_grp2: usize,\n    // mt1[i] = v is the matching of i in grp1 to v in grp2\n    pub mt1: Vec<i32>,\n    pub mt2: Vec<i32>,\n    pub used: Vec<bool>,\n}\nimpl BipartiteMatching {\n    pub fn new(num_vertices_grp1: usize, num_vertices_grp2: usize) -> Self {\n        BipartiteMatching {\n            adj: vec![vec![]; num_vertices_grp1 + 1],\n            num_vertices_grp1,\n            num_vertices_grp2,\n            mt2: vec![-1; num_vertices_grp2 + 1],\n            mt1: vec![-1; num_vertices_grp1 + 1],\n            used: vec![false; num_vertices_grp1 + 1],\n        }\n    }\n    #[inline]\n    // Add an directed edge u->v in the graph\n    pub fn add_edge(&mut self, u: usize, v: usize) {\n        self.adj[u].push(v);\n    }\n\n    fn try_kuhn(&mut self, cur: usize) -> bool {\n        if self.used[cur] {\n            return false;\n        }\n        self.used[cur] = true;\n        for i in 0..self.adj[cur].len() {\n            let to = self.adj[cur][i];\n            if self.mt2[to] == -1 || self.try_kuhn(self.mt2[to] as usize) {\n                self.mt2[to] = cur as i32;\n                return true;\n            }\n        }\n        false\n    }\n    // Note: It does not modify self.mt1, it only works on self.mt2\n    pub fn kuhn(&mut self) {\n        self.mt2 = vec![-1; self.num_vertices_grp2 + 1];\n        for v in 1..=self.num_vertices_grp1 {\n            self.used = vec![false; self.num_vertices_grp1 + 1];\n            self.try_kuhn(v);\n        }\n    }\n    pub fn print_matching(&self) {\n        for i in 1..=self.num_vertices_grp2 {\n            if self.mt2[i] == -1 {\n                continue;\n            }\n            println!(\"Vertex {} in grp1 matched with {} grp2\", self.mt2[i], i)\n        }\n    }\n    fn bfs(&self, dist: &mut [i32]) -> bool {\n        let mut q = VecDeque::new();\n        for (u, d_i) in dist\n            .iter_mut()\n            .enumerate()\n            .skip(1)\n            .take(self.num_vertices_grp1)\n        {\n            if self.mt1[u] == 0 {\n                // u is not matched\n                *d_i = 0;\n                q.push_back(u);\n            } else {\n                // else set the vertex distance as infinite because it is matched\n                // this will be considered the next time\n\n                *d_i = i32::MAX;\n            }\n        }\n        dist[0] = i32::MAX;\n        while !q.is_empty() {\n            let u = *q.front().unwrap();\n            q.pop_front();\n            if dist[u] < dist[0] {\n                for i in 0..self.adj[u].len() {\n                    let v = self.adj[u][i];\n                    if dist[self.mt2[v] as usize] == i32::MAX {\n                        dist[self.mt2[v] as usize] = dist[u] + 1;\n                        q.push_back(self.mt2[v] as usize);\n                    }\n                }\n            }\n        }\n        dist[0] != i32::MAX\n    }\n    fn dfs(&mut self, u: i32, dist: &mut Vec<i32>) -> bool {\n        if u == 0 {\n            return true;\n        }\n        for i in 0..self.adj[u as usize].len() {\n            let v = self.adj[u as usize][i];\n            if dist[self.mt2[v] as usize] == dist[u as usize] + 1 && self.dfs(self.mt2[v], dist) {\n                self.mt2[v] = u;\n                self.mt1[u as usize] = v as i32;\n                return true;\n            }\n        }\n        dist[u as usize] = i32::MAX;\n        false\n    }\n    pub fn hopcroft_karp(&mut self) -> i32 {\n        // NOTE: how to use: https://cses.fi/paste/7558dba8d00436a847eab8/\n        self.mt2 = vec![0; self.num_vertices_grp2 + 1];\n        self.mt1 = vec![0; self.num_vertices_grp1 + 1];\n        let mut dist = vec![i32::MAX; self.num_vertices_grp1 + 1];\n        let mut res = 0;\n        while self.bfs(&mut dist) {\n            for u in 1..=self.num_vertices_grp1 {\n                if self.mt1[u] == 0 && self.dfs(u as i32, &mut dist) {\n                    res += 1;\n                }\n            }\n        }\n        // for x in self.mt2 change x to -1 if it is 0\n        for x in self.mt2.iter_mut() {\n            if *x == 0 {\n                *x = -1;\n            }\n        }\n        for x in self.mt1.iter_mut() {\n            if *x == 0 {\n                *x = -1;\n            }\n        }\n        res\n    }\n}\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn small_graph_kuhn() {\n        let n1 = 6;\n        let n2 = 6;\n        let mut g = BipartiteMatching::new(n1, n2);\n        // vertex 1 in grp1 to vertex 1 in grp 2\n        // denote the ith grp2 vertex as n1+i\n        g.add_edge(1, 2);\n        g.add_edge(1, 3);\n        // 2 is not connected to any vertex\n        g.add_edge(3, 4);\n        g.add_edge(3, 1);\n        g.add_edge(4, 3);\n        g.add_edge(5, 3);\n        g.add_edge(5, 4);\n        g.add_edge(6, 6);\n        g.kuhn();\n        g.print_matching();\n        let answer: Vec<i32> = vec![-1, 2, -1, 1, 3, 4, 6];\n        for i in 1..g.mt2.len() {\n            if g.mt2[i] == -1 {\n                // 5 in group2 has no pair\n                assert_eq!(i, 5);\n                continue;\n            }\n            // 2 in group1 has no pair\n            assert!(g.mt2[i] != 2);\n            assert_eq!(i as i32, answer[g.mt2[i] as usize]);\n        }\n    }\n    #[test]\n    fn small_graph_hopcroft() {\n        let n1 = 6;\n        let n2 = 6;\n        let mut g = BipartiteMatching::new(n1, n2);\n        // vertex 1 in grp1 to vertex 1 in grp 2\n        // denote the ith grp2 vertex as n1+i\n        g.add_edge(1, 2);\n        g.add_edge(1, 3);\n        // 2 is not connected to any vertex\n        g.add_edge(3, 4);\n        g.add_edge(3, 1);\n        g.add_edge(4, 3);\n        g.add_edge(5, 3);\n        g.add_edge(5, 4);\n        g.add_edge(6, 6);\n        let x = g.hopcroft_karp();\n        assert_eq!(x, 5);\n        g.print_matching();\n        let answer: Vec<i32> = vec![-1, 2, -1, 1, 3, 4, 6];\n        for i in 1..g.mt2.len() {\n            if g.mt2[i] == -1 {\n                // 5 in group2 has no pair\n                assert_eq!(i, 5);\n                continue;\n            }\n            // 2 in group1 has no pair\n            assert!(g.mt2[i] != 2);\n            assert_eq!(i as i32, answer[g.mt2[i] as usize]);\n        }\n    }\n    #[test]\n    fn super_small_graph_kuhn() {\n        let n1 = 1;\n        let n2 = 1;\n        let mut g = BipartiteMatching::new(n1, n2);\n        g.add_edge(1, 1);\n        g.kuhn();\n        g.print_matching();\n        assert_eq!(g.mt2[1], 1);\n    }\n    #[test]\n    fn super_small_graph_hopcroft() {\n        let n1 = 1;\n        let n2 = 1;\n        let mut g = BipartiteMatching::new(n1, n2);\n        g.add_edge(1, 1);\n        let x = g.hopcroft_karp();\n        assert_eq!(x, 1);\n        g.print_matching();\n        assert_eq!(g.mt2[1], 1);\n        assert_eq!(g.mt1[1], 1);\n    }\n\n    #[test]\n    fn only_one_vertex_graph_kuhn() {\n        let n1 = 10;\n        let n2 = 10;\n        let mut g = BipartiteMatching::new(n1, n2);\n        g.add_edge(1, 1);\n        g.add_edge(2, 1);\n        g.add_edge(3, 1);\n        g.add_edge(4, 1);\n        g.add_edge(5, 1);\n        g.add_edge(6, 1);\n        g.add_edge(7, 1);\n        g.add_edge(8, 1);\n        g.add_edge(9, 1);\n        g.add_edge(10, 1);\n        g.kuhn();\n        g.print_matching();\n        assert_eq!(g.mt2[1], 1);\n        for i in 2..g.mt2.len() {\n            assert!(g.mt2[i] == -1);\n        }\n    }\n    #[test]\n    fn only_one_vertex_graph_hopcroft() {\n        let n1 = 10;\n        let n2 = 10;\n        let mut g = BipartiteMatching::new(n1, n2);\n        g.add_edge(1, 1);\n        g.add_edge(2, 1);\n        g.add_edge(3, 1);\n        g.add_edge(4, 1);\n        g.add_edge(5, 1);\n        g.add_edge(6, 1);\n        g.add_edge(7, 1);\n        g.add_edge(8, 1);\n        g.add_edge(9, 1);\n        g.add_edge(10, 1);\n        let x = g.hopcroft_karp();\n        assert_eq!(x, 1);\n        g.print_matching();\n        assert_eq!(g.mt2[1], 1);\n        for i in 2..g.mt2.len() {\n            assert!(g.mt2[i] == -1);\n        }\n    }\n}\n"
  },
  {
    "path": "src/graph/breadth_first_search.rs",
    "content": "use std::collections::HashSet;\nuse std::collections::VecDeque;\n\n/// Perform a breadth-first search on Graph `graph`.\n///\n/// # Parameters\n///\n/// - `graph`: The graph to search.\n/// - `root`: The starting node of the graph from which to begin searching.\n/// - `target`: The target node for the search.\n///\n/// # Returns\n///\n/// If the target is found, an Optional vector is returned with the history\n/// of nodes visited as its contents.\n///\n/// If the target is not found or there is no path from the root,\n/// `None` is returned.\n///\npub fn breadth_first_search(graph: &Graph, root: Node, target: Node) -> Option<Vec<u32>> {\n    let mut visited: HashSet<Node> = HashSet::new();\n    let mut history: Vec<u32> = Vec::new();\n    let mut queue = VecDeque::new();\n\n    visited.insert(root);\n    queue.push_back(root);\n    while let Some(currentnode) = queue.pop_front() {\n        history.push(currentnode.value());\n\n        // If we reach the goal, return our travel history.\n        if currentnode == target {\n            return Some(history);\n        }\n\n        // Check the neighboring nodes for any that we've not visited yet.\n        for neighbor in currentnode.neighbors(graph) {\n            if visited.insert(neighbor) {\n                queue.push_back(neighbor);\n            }\n        }\n    }\n\n    // All nodes were visited, yet the target was not found.\n    None\n}\n\n// Data Structures\n\n#[derive(Copy, Clone, PartialEq, Eq, Hash)]\npub struct Node(u32);\n\n#[derive(Copy, Clone, PartialEq, Eq, Hash)]\npub struct Edge(u32, u32);\n\n#[derive(Clone)]\npub struct Graph {\n    #[allow(dead_code)]\n    nodes: Vec<Node>,\n    edges: Vec<Edge>,\n}\n\nimpl Graph {\n    pub fn new(nodes: Vec<Node>, edges: Vec<Edge>) -> Self {\n        Graph { nodes, edges }\n    }\n}\n\nimpl From<u32> for Node {\n    fn from(item: u32) -> Self {\n        Node(item)\n    }\n}\n\nimpl Node {\n    pub fn value(&self) -> u32 {\n        self.0\n    }\n\n    pub fn neighbors(&self, graph: &Graph) -> Vec<Node> {\n        graph\n            .edges\n            .iter()\n            .filter(|e| e.0 == self.0)\n            .map(|e| e.1.into())\n            .collect()\n    }\n}\n\nimpl From<(u32, u32)> for Edge {\n    fn from(item: (u32, u32)) -> Self {\n        Edge(item.0, item.1)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    /* Example graph #1:\n     *\n     *            (1)   <--- Root\n     *           /   \\\n     *         (2)   (3)\n     *        / |     | \\\n     *     (4) (5)   (6) (7)\n     *          |\n     *         (8)\n     */\n    fn graph1() -> Graph {\n        let nodes = vec![1, 2, 3, 4, 5, 6, 7];\n        let edges = vec![(1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7), (5, 8)];\n\n        Graph::new(\n            nodes.into_iter().map(|v| v.into()).collect(),\n            edges.into_iter().map(|e| e.into()).collect(),\n        )\n    }\n\n    #[test]\n    fn breadth_first_search_graph1_when_node_not_found_returns_none() {\n        let graph = graph1();\n        let root = 1;\n        let target = 10;\n\n        assert_eq!(\n            breadth_first_search(&graph, root.into(), target.into()),\n            None\n        );\n    }\n\n    #[test]\n    fn breadth_first_search_graph1_when_target_8_should_evaluate_all_nodes_first() {\n        let graph = graph1();\n        let root = 1;\n        let target = 8;\n\n        let expected_path = vec![1, 2, 3, 4, 5, 6, 7, 8];\n\n        assert_eq!(\n            breadth_first_search(&graph, root.into(), target.into()),\n            Some(expected_path)\n        );\n    }\n\n    /* Example graph #2:\n     *\n     *     (1) --- (2)     (3) --- (4)\n     *            / |     /       /\n     *          /   |   /       /\n     *        /     | /       /\n     *     (5)     (6) --- (7)     (8)\n     */\n    fn graph2() -> Graph {\n        let nodes = vec![1, 2, 3, 4, 5, 6, 7, 8];\n        let undirected_edges = vec![\n            (1, 2),\n            (2, 1),\n            (2, 5),\n            (5, 2),\n            (2, 6),\n            (6, 2),\n            (3, 4),\n            (4, 3),\n            (3, 6),\n            (6, 3),\n            (4, 7),\n            (7, 4),\n            (6, 7),\n            (7, 6),\n        ];\n\n        Graph::new(\n            nodes.into_iter().map(|v| v.into()).collect(),\n            undirected_edges.into_iter().map(|e| e.into()).collect(),\n        )\n    }\n\n    #[test]\n    fn breadth_first_search_graph2_when_no_path_to_node_returns_none() {\n        let graph = graph2();\n        let root = 8;\n        let target = 4;\n\n        assert_eq!(\n            breadth_first_search(&graph, root.into(), target.into()),\n            None\n        );\n    }\n\n    #[test]\n    fn breadth_first_search_graph2_should_find_path_from_4_to_1() {\n        let graph = graph2();\n        let root = 4;\n        let target = 1;\n\n        let expected_path = vec![4, 3, 7, 6, 2, 1];\n\n        assert_eq!(\n            breadth_first_search(&graph, root.into(), target.into()),\n            Some(expected_path)\n        );\n    }\n}\n"
  },
  {
    "path": "src/graph/centroid_decomposition.rs",
    "content": "type Adj = [Vec<usize>];\n\nconst IN_DECOMPOSITION: u64 = 1 << 63;\n\n/// Centroid Decomposition for a tree.\n///\n/// Given a tree, it can be recursively decomposed into centroids. Then the\n/// parent of a centroid `c` is the previous centroid that splitted its connected\n/// component into two or more components. It can be shown that in such\n/// decomposition, for each path `p` with starting and ending vertices `u`, `v`,\n/// the lowest common ancestor of `u` and `v` in centroid tree is a vertex of `p`.\n///\n/// The input tree should have its vertices numbered from 1 to n, and\n/// `graph_enumeration.rs` may help to convert other representations.\npub struct CentroidDecomposition {\n    /// The root of the centroid tree, should _not_ be set by the user\n    pub root: usize,\n    /// The result. `decomposition[v]` is the parent of `v` in centroid tree.\n    /// `decomposition[root]` is 0\n    pub decomposition: Vec<usize>,\n    /// Used internally to save the big_child of a vertex, and whether it has\n    /// been added to the centroid tree.\n    vert_state: Vec<u64>,\n    /// Used internally to save the subtree size of a vertex\n    vert_size: Vec<usize>,\n}\n\nimpl CentroidDecomposition {\n    pub fn new(mut num_vertices: usize) -> Self {\n        num_vertices += 1;\n        CentroidDecomposition {\n            root: 0,\n            decomposition: vec![0; num_vertices],\n            vert_state: vec![0; num_vertices],\n            vert_size: vec![0; num_vertices],\n        }\n    }\n    #[inline]\n    fn put_in_decomposition(&mut self, v: usize, parent: usize) {\n        self.decomposition[v] = parent;\n        self.vert_state[v] |= IN_DECOMPOSITION;\n    }\n    #[inline]\n    fn is_in_decomposition(&self, v: usize) -> bool {\n        (self.vert_state[v] & IN_DECOMPOSITION) != 0\n    }\n    fn dfs_size(&mut self, v: usize, parent: usize, adj: &Adj) -> usize {\n        self.vert_size[v] = 1;\n        let mut big_child = 0_usize;\n        let mut bc_size = 0_usize; // big child size\n        for &u in adj[v].iter() {\n            if u == parent || self.is_in_decomposition(u) {\n                continue;\n            }\n            let u_size = self.dfs_size(u, v, adj);\n            self.vert_size[v] += u_size;\n            if u_size > bc_size {\n                big_child = u;\n                bc_size = u_size;\n            }\n        }\n        self.vert_state[v] = big_child as u64;\n        self.vert_size[v]\n    }\n    fn dfs_centroid(&self, v: usize, size_thr: usize) -> usize {\n        // recurse until big child's size is <= `size_thr`\n        match self.vert_state[v] as usize {\n            u if self.vert_size[u] <= size_thr => v,\n            u => self.dfs_centroid(u, size_thr),\n        }\n    }\n    fn decompose_subtree(\n        &mut self,\n        v: usize,\n        centroid_parent: usize,\n        calculate_vert_size: bool,\n        adj: &Adj,\n    ) -> usize {\n        // `calculate_vert_size` determines if it is necessary to recalculate\n        // `self.vert_size`\n        if calculate_vert_size {\n            self.dfs_size(v, centroid_parent, adj);\n        }\n        let v_size = self.vert_size[v];\n        let centroid = self.dfs_centroid(v, v_size >> 1);\n        self.put_in_decomposition(centroid, centroid_parent);\n        for &u in adj[centroid].iter() {\n            if self.is_in_decomposition(u) {\n                continue;\n            }\n            self.decompose_subtree(\n                u,\n                centroid,\n                self.vert_size[u] > self.vert_size[centroid],\n                adj,\n            );\n        }\n        centroid\n    }\n    pub fn decompose_tree(&mut self, adj: &Adj) {\n        self.decompose_subtree(1, 0, true, adj);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::CentroidDecomposition;\n    use crate::{\n        graph::{enumerate_graph, prufer_code},\n        math::PCG32,\n    };\n    fn calculate_height(v: usize, heights: &mut [usize], parents: &mut [usize]) -> usize {\n        if heights[v] == 0 {\n            heights[v] = calculate_height(parents[v], heights, parents) + 1;\n        }\n        heights[v]\n    }\n    #[test]\n    fn single_path() {\n        let len = 16;\n        let mut adj: Vec<Vec<usize>> = vec![vec![]; len];\n        adj[1].push(2);\n        adj[15].push(14);\n        #[allow(clippy::needless_range_loop)]\n        for i in 2..15 {\n            adj[i].push(i + 1);\n            adj[i].push(i - 1);\n        }\n        let mut cd = CentroidDecomposition::new(len - 1);\n        cd.decompose_tree(&adj);\n        // We should get a complete binary tree\n        assert_eq!(\n            cd.decomposition,\n            vec![0, 2, 4, 2, 8, 6, 4, 6, 0, 10, 12, 10, 8, 14, 12, 14]\n        );\n    }\n    #[test]\n    #[ignore]\n    fn random_tree_height() {\n        // Do not run this test in debug mode! It takes > 30s to run without\n        // optimizations!\n        let n = 1e6 as usize;\n        let max_height = 1 + 20;\n        let len = n + 1;\n        let mut rng = PCG32::new_default(314159);\n        let mut tree_prufer_code: Vec<u32> = vec![0; n - 2];\n        tree_prufer_code.fill_with(|| (rng.get_u32() % (n as u32)) + 1);\n        let vertex_list: Vec<u32> = (1..=(n as u32)).collect();\n        let adj = enumerate_graph(&prufer_code::prufer_decode(&tree_prufer_code, &vertex_list));\n        let mut cd = CentroidDecomposition::new(n);\n        cd.decompose_tree(&adj);\n        let mut heights: Vec<usize> = vec![0; len];\n        heights[0] = 1;\n        for i in 1..=n {\n            let h = calculate_height(i, &mut heights, &mut cd.decomposition);\n            assert!(h <= max_height);\n        }\n    }\n}\n"
  },
  {
    "path": "src/graph/decremental_connectivity.rs",
    "content": "use std::collections::HashSet;\n\n/// A data-structure that, given a forest, allows dynamic-connectivity queries.\n/// Meaning deletion of an edge (u,v) and checking whether two vertecies are still connected.\n///\n/// # Complexity\n/// The preprocessing phase runs in O(n) time, where n is the number of vertecies in the forest.\n/// Deletion runs in O(log n) and checking for connectivity runs in O(1) time.\n///\n/// # Sources\n/// used Wikipedia as reference: <https://en.wikipedia.org/wiki/Dynamic_connectivity>\npub struct DecrementalConnectivity {\n    adjacent: Vec<HashSet<usize>>,\n    component: Vec<usize>,\n    count: usize,\n    visited: Vec<usize>,\n    dfs_id: usize,\n}\nimpl DecrementalConnectivity {\n    //expects the parent of a root to be itself\n    pub fn new(adjacent: Vec<HashSet<usize>>) -> Result<Self, String> {\n        let n = adjacent.len();\n        if !is_forest(&adjacent) {\n            return Err(\"input graph is not a forest!\".to_string());\n        }\n        let mut tmp = DecrementalConnectivity {\n            adjacent,\n            component: vec![0; n],\n            count: 0,\n            visited: vec![0; n],\n            dfs_id: 1,\n        };\n        tmp.component = tmp.calc_component();\n        Ok(tmp)\n    }\n\n    pub fn connected(&self, u: usize, v: usize) -> Option<bool> {\n        match (self.component.get(u), self.component.get(v)) {\n            (Some(a), Some(b)) => Some(a == b),\n            _ => None,\n        }\n    }\n\n    pub fn delete(&mut self, u: usize, v: usize) {\n        if !self.adjacent[u].contains(&v) || self.component[u] != self.component[v] {\n            panic!(\"delete called on the edge ({u}, {v}) which doesn't exist\");\n        }\n\n        self.adjacent[u].remove(&v);\n        self.adjacent[v].remove(&u);\n\n        let mut queue: Vec<usize> = Vec::new();\n        if self.is_smaller(u, v) {\n            queue.push(u);\n            self.dfs_id += 1;\n            self.visited[v] = self.dfs_id;\n        } else {\n            queue.push(v);\n            self.dfs_id += 1;\n            self.visited[u] = self.dfs_id;\n        }\n        while !queue.is_empty() {\n            let &current = queue.last().unwrap();\n            self.dfs_step(&mut queue, self.dfs_id);\n            self.component[current] = self.count;\n        }\n        self.count += 1;\n    }\n\n    fn calc_component(&mut self) -> Vec<usize> {\n        let mut visited: Vec<bool> = vec![false; self.adjacent.len()];\n        let mut comp: Vec<usize> = vec![0; self.adjacent.len()];\n\n        for i in 0..self.adjacent.len() {\n            if visited[i] {\n                continue;\n            }\n            let mut queue: Vec<usize> = vec![i];\n            while let Some(current) = queue.pop() {\n                if !visited[current] {\n                    for &neighbour in self.adjacent[current].iter() {\n                        queue.push(neighbour);\n                    }\n                }\n                visited[current] = true;\n                comp[current] = self.count;\n            }\n            self.count += 1;\n        }\n        comp\n    }\n\n    fn is_smaller(&mut self, u: usize, v: usize) -> bool {\n        let mut u_queue: Vec<usize> = vec![u];\n        let u_id = self.dfs_id;\n        self.visited[v] = u_id;\n        self.dfs_id += 1;\n\n        let mut v_queue: Vec<usize> = vec![v];\n        let v_id = self.dfs_id;\n        self.visited[u] = v_id;\n        self.dfs_id += 1;\n\n        // parallel depth first search\n        while !u_queue.is_empty() && !v_queue.is_empty() {\n            self.dfs_step(&mut u_queue, u_id);\n            self.dfs_step(&mut v_queue, v_id);\n        }\n        u_queue.is_empty()\n    }\n\n    fn dfs_step(&mut self, queue: &mut Vec<usize>, dfs_id: usize) {\n        let u = queue.pop().unwrap();\n        self.visited[u] = dfs_id;\n        for &v in self.adjacent[u].iter() {\n            if self.visited[v] == dfs_id {\n                continue;\n            }\n            queue.push(v);\n        }\n    }\n}\n\n// checks whether the given graph is a forest\n// also checks for all adjacent vertices a,b if adjacent[a].contains(b) && adjacent[b].contains(a)\nfn is_forest(adjacent: &Vec<HashSet<usize>>) -> bool {\n    let mut visited = vec![false; adjacent.len()];\n    for node in 0..adjacent.len() {\n        if visited[node] {\n            continue;\n        }\n        if has_cycle(adjacent, &mut visited, node, node) {\n            return false;\n        }\n    }\n    true\n}\n\nfn has_cycle(\n    adjacent: &Vec<HashSet<usize>>,\n    visited: &mut Vec<bool>,\n    node: usize,\n    parent: usize,\n) -> bool {\n    visited[node] = true;\n    for &neighbour in adjacent[node].iter() {\n        if !adjacent[neighbour].contains(&node) {\n            panic!(\"the given graph does not strictly contain bidirectional edges\\n {node} -> {neighbour} exists, but the other direction does not\");\n        }\n        if !visited[neighbour] {\n            if has_cycle(adjacent, visited, neighbour, node) {\n                return true;\n            }\n        } else if neighbour != parent {\n            return true;\n        }\n    }\n    false\n}\n\n#[cfg(test)]\nmod tests {\n    use std::collections::HashSet;\n\n    // test forest (remember the assumptoin that roots are adjacent to themselves)\n    //              _              _\n    //             \\ /            \\ /\n    //              0              7\n    //            / | \\            |\n    //           1  2  3           8\n    //         /   / \\\n    //        4   5   6\n    #[test]\n    fn construction_test() {\n        let mut adjacent = vec![\n            HashSet::from([0, 1, 2, 3]),\n            HashSet::from([0, 4]),\n            HashSet::from([0, 5, 6]),\n            HashSet::from([0]),\n            HashSet::from([1]),\n            HashSet::from([2]),\n            HashSet::from([2]),\n            HashSet::from([7, 8]),\n            HashSet::from([7]),\n        ];\n        let dec_con = super::DecrementalConnectivity::new(adjacent.clone()).unwrap();\n        assert_eq!(dec_con.component, vec![0, 0, 0, 0, 0, 0, 0, 1, 1]);\n\n        // add a cycle to the tree\n        adjacent[2].insert(4);\n        adjacent[4].insert(2);\n        assert!(super::DecrementalConnectivity::new(adjacent.clone()).is_err());\n    }\n    #[test]\n    #[should_panic(expected = \"2 -> 4 exists\")]\n    fn non_bidirectional_test() {\n        let adjacent = vec![\n            HashSet::from([0, 1, 2, 3]),\n            HashSet::from([0, 4]),\n            HashSet::from([0, 5, 6, 4]),\n            HashSet::from([0]),\n            HashSet::from([1]),\n            HashSet::from([2]),\n            HashSet::from([2]),\n            HashSet::from([7, 8]),\n            HashSet::from([7]),\n        ];\n\n        // should panic now since our graph is not bidirectional\n        super::DecrementalConnectivity::new(adjacent).unwrap();\n    }\n\n    #[test]\n    #[should_panic(expected = \"delete called on the edge (2, 4)\")]\n    fn delete_panic_test() {\n        let adjacent = vec![\n            HashSet::from([0, 1, 2, 3]),\n            HashSet::from([0, 4]),\n            HashSet::from([0, 5, 6]),\n            HashSet::from([0]),\n            HashSet::from([1]),\n            HashSet::from([2]),\n            HashSet::from([2]),\n            HashSet::from([7, 8]),\n            HashSet::from([7]),\n        ];\n        let mut dec_con = super::DecrementalConnectivity::new(adjacent).unwrap();\n        dec_con.delete(2, 4);\n    }\n\n    #[test]\n    fn query_test() {\n        let adjacent = vec![\n            HashSet::from([0, 1, 2, 3]),\n            HashSet::from([0, 4]),\n            HashSet::from([0, 5, 6]),\n            HashSet::from([0]),\n            HashSet::from([1]),\n            HashSet::from([2]),\n            HashSet::from([2]),\n            HashSet::from([7, 8]),\n            HashSet::from([7]),\n        ];\n        let mut dec_con1 = super::DecrementalConnectivity::new(adjacent.clone()).unwrap();\n        assert!(dec_con1.connected(3, 4).unwrap());\n        assert!(dec_con1.connected(5, 0).unwrap());\n        assert!(!dec_con1.connected(2, 7).unwrap());\n        assert!(dec_con1.connected(0, 9).is_none());\n        dec_con1.delete(0, 2);\n        assert!(dec_con1.connected(3, 4).unwrap());\n        assert!(!dec_con1.connected(5, 0).unwrap());\n        assert!(dec_con1.connected(5, 6).unwrap());\n        assert!(dec_con1.connected(8, 7).unwrap());\n        dec_con1.delete(7, 8);\n        assert!(!dec_con1.connected(8, 7).unwrap());\n        dec_con1.delete(1, 4);\n        assert!(!dec_con1.connected(1, 4).unwrap());\n\n        let mut dec_con2 = super::DecrementalConnectivity::new(adjacent.clone()).unwrap();\n        dec_con2.delete(4, 1);\n        assert!(!dec_con2.connected(1, 4).unwrap());\n\n        let mut dec_con3 = super::DecrementalConnectivity::new(adjacent).unwrap();\n        dec_con3.delete(1, 4);\n        assert!(!dec_con3.connected(4, 1).unwrap());\n    }\n}\n"
  },
  {
    "path": "src/graph/depth_first_search.rs",
    "content": "use std::collections::HashSet;\nuse std::collections::VecDeque;\n\n// Perform a Depth First Search Algorithm to find a element in a graph\n//\n// Return a Optional with a vector with history of vertex visiteds\n// or a None if the element not exists on the graph\npub fn depth_first_search(graph: &Graph, root: Vertex, objective: Vertex) -> Option<Vec<u32>> {\n    let mut visited: HashSet<Vertex> = HashSet::new();\n    let mut history: Vec<u32> = Vec::new();\n    let mut queue = VecDeque::new();\n    queue.push_back(root);\n\n    // While there is an element in the queue\n    // get the first element of the vertex queue\n    while let Some(current_vertex) = queue.pop_front() {\n        // Added current vertex in the history of visiteds vertex\n        history.push(current_vertex.value());\n\n        // Verify if this vertex is the objective\n        if current_vertex == objective {\n            // Return the Optional with the history of visiteds vertex\n            return Some(history);\n        }\n\n        // For each over the neighbors of current vertex\n        for neighbor in current_vertex.neighbors(graph).into_iter().rev() {\n            // Insert in the HashSet of visiteds if this value not exist yet\n            if visited.insert(neighbor) {\n                // Add the neighbor on front of queue\n                queue.push_front(neighbor);\n            }\n        }\n    }\n\n    // If all vertex is visited and the objective is not found\n    // return a Optional with None value\n    None\n}\n\n// Data Structures\n\n#[derive(Copy, Clone, PartialEq, Eq, Hash)]\npub struct Vertex(u32);\n#[derive(Copy, Clone, PartialEq, Eq, Hash)]\npub struct Edge(u32, u32);\n#[derive(Clone)]\npub struct Graph {\n    #[allow(dead_code)]\n    vertices: Vec<Vertex>,\n    edges: Vec<Edge>,\n}\n\nimpl Graph {\n    pub fn new(vertices: Vec<Vertex>, edges: Vec<Edge>) -> Self {\n        Graph { vertices, edges }\n    }\n}\n\nimpl From<u32> for Vertex {\n    fn from(item: u32) -> Self {\n        Vertex(item)\n    }\n}\n\nimpl Vertex {\n    pub fn value(&self) -> u32 {\n        self.0\n    }\n\n    pub fn neighbors(&self, graph: &Graph) -> VecDeque<Vertex> {\n        graph\n            .edges\n            .iter()\n            .filter(|e| e.0 == self.0)\n            .map(|e| e.1.into())\n            .collect()\n    }\n}\n\nimpl From<(u32, u32)> for Edge {\n    fn from(item: (u32, u32)) -> Self {\n        Edge(item.0, item.1)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn find_1_fail() {\n        let vertices = vec![1, 2, 3, 4, 5, 6, 7];\n        let edges = vec![(1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7)];\n\n        let root = 1;\n        let objective = 99;\n\n        let graph = Graph::new(\n            vertices.into_iter().map(|v| v.into()).collect(),\n            edges.into_iter().map(|e| e.into()).collect(),\n        );\n\n        assert_eq!(\n            depth_first_search(&graph, root.into(), objective.into()),\n            None\n        );\n    }\n\n    #[test]\n    fn find_1_sucess() {\n        let vertices = vec![1, 2, 3, 4, 5, 6, 7];\n        let edges = vec![(1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7)];\n\n        let root = 1;\n        let objective = 7;\n\n        let correct_path = vec![1, 2, 4, 5, 3, 6, 7];\n\n        let graph = Graph::new(\n            vertices.into_iter().map(|v| v.into()).collect(),\n            edges.into_iter().map(|e| e.into()).collect(),\n        );\n\n        assert_eq!(\n            depth_first_search(&graph, root.into(), objective.into()),\n            Some(correct_path)\n        );\n    }\n\n    #[test]\n    fn find_2_sucess() {\n        let vertices = vec![0, 1, 2, 3, 4, 5, 6, 7];\n        let edges = vec![\n            (0, 1),\n            (1, 3),\n            (3, 2),\n            (2, 1),\n            (3, 4),\n            (4, 5),\n            (5, 7),\n            (7, 6),\n            (6, 4),\n        ];\n\n        let root = 0;\n        let objective = 6;\n\n        let correct_path = vec![0, 1, 3, 2, 4, 5, 7, 6];\n\n        let graph = Graph::new(\n            vertices.into_iter().map(|v| v.into()).collect(),\n            edges.into_iter().map(|e| e.into()).collect(),\n        );\n\n        assert_eq!(\n            depth_first_search(&graph, root.into(), objective.into()),\n            Some(correct_path)\n        );\n    }\n\n    #[test]\n    fn find_3_sucess() {\n        let vertices = vec![0, 1, 2, 3, 4, 5, 6, 7];\n        let edges = vec![\n            (0, 1),\n            (1, 3),\n            (3, 2),\n            (2, 1),\n            (3, 4),\n            (4, 5),\n            (5, 7),\n            (7, 6),\n            (6, 4),\n        ];\n\n        let root = 0;\n        let objective = 4;\n\n        let correct_path = vec![0, 1, 3, 2, 4];\n\n        let graph = Graph::new(\n            vertices.into_iter().map(|v| v.into()).collect(),\n            edges.into_iter().map(|e| e.into()).collect(),\n        );\n\n        assert_eq!(\n            depth_first_search(&graph, root.into(), objective.into()),\n            Some(correct_path)\n        );\n    }\n}\n"
  },
  {
    "path": "src/graph/depth_first_search_tic_tac_toe.rs",
    "content": "/*\nTic-Tac-Toe Depth First Search Rust Demo\nCopyright 2021 David V. Makray\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#[allow(unused_imports)]\nuse std::io;\n\n//Interactive Tic-Tac-Toe play needs the \"rand = \"0.8.3\" crate.\n//#[cfg(not(test))]\n//extern crate rand;\n//#[cfg(not(test))]\n//use rand::Rng;\n\n#[derive(Copy, Clone, PartialEq, Eq, Debug)]\nstruct Position {\n    x: u8,\n    y: u8,\n}\n\n#[derive(Copy, Clone, PartialEq, Eq, Debug)]\npub enum Players {\n    Blank,\n    PlayerX,\n    PlayerO,\n}\n\n#[derive(Copy, Clone, PartialEq, Eq, Debug)]\nstruct SinglePlayAction {\n    position: Position,\n    side: Players,\n}\n\n#[derive(Clone, PartialEq, Eq, Debug)]\npub struct PlayActions {\n    positions: Vec<Position>,\n    side: Players,\n}\n\n#[allow(dead_code)]\n#[cfg(not(test))]\nfn main() {\n    let mut board = vec![vec![Players::Blank; 3]; 3];\n\n    while !available_positions(&board).is_empty()\n        && !win_check(Players::PlayerX, &board)\n        && !win_check(Players::PlayerO, &board)\n    {\n        display_board(&board);\n        println!(\"Type in coordinate for X mark to be played. ie. a1 etc.\");\n        let mut input = String::new();\n        io::stdin()\n            .read_line(&mut input)\n            .expect(\"Failed to read line\");\n\n        let mut move_position: Option<Position> = None;\n        input.make_ascii_lowercase();\n        let bytes = input.trim().trim_start().as_bytes();\n        if bytes.len() as u32 == 2\n            && (bytes[0] as char).is_alphabetic()\n            && (bytes[1] as char).is_numeric()\n        {\n            let column: u8 = bytes[0] - b'a';\n            let row: u8 = bytes[1] - b'1';\n\n            if column <= 2 && row <= 2 {\n                move_position = Some(Position { x: column, y: row });\n            }\n        }\n\n        //Take the validated user input coordinate and use it.\n        if let Some(move_pos) = move_position {\n            let open_positions = available_positions(&board);\n\n            let mut search = open_positions.iter();\n            let result = search.find(|&&x| x == move_pos);\n            if result.is_none() {\n                println!(\"Not a valid empty coordinate.\");\n                continue;\n            }\n            board[move_pos.y as usize][move_pos.x as usize] = Players::PlayerX;\n\n            if win_check(Players::PlayerX, &board) {\n                display_board(&board);\n                println!(\"Player X Wins!\");\n                return;\n            }\n\n            //Find the best game plays from the current board state\n            let recusion_result = minimax(Players::PlayerO, &board);\n            match recusion_result {\n                Some(x) => {\n                    //Interactive Tic-Tac-Toe play needs the \"rand = \"0.8.3\" crate.\n                    //#[cfg(not(test))]\n                    //let random_selection = rand::rng().gen_range(0..x.positions.len());\n                    let random_selection = 0;\n\n                    let response_pos = x.positions[random_selection];\n                    board[response_pos.y as usize][response_pos.x as usize] = Players::PlayerO;\n                    if win_check(Players::PlayerO, &board) {\n                        display_board(&board);\n                        println!(\"Player O Wins!\");\n                        return;\n                    }\n                }\n\n                None => {\n                    display_board(&board);\n                    println!(\"Draw game.\");\n                    return;\n                }\n            }\n        }\n    }\n}\n\n#[allow(dead_code)]\nfn display_board(board: &[Vec<Players>]) {\n    println!();\n    for (y, board_row) in board.iter().enumerate() {\n        print!(\"{} \", (y + 1));\n        for board_cell in board_row {\n            match board_cell {\n                Players::PlayerX => print!(\"X \"),\n                Players::PlayerO => print!(\"O \"),\n                Players::Blank => print!(\"_ \"),\n            }\n        }\n        println!();\n    }\n    println!(\"  a b c\");\n}\n\nfn available_positions(board: &[Vec<Players>]) -> Vec<Position> {\n    let mut available: Vec<Position> = Vec::new();\n    for (y, board_row) in board.iter().enumerate() {\n        for (x, board_cell) in board_row.iter().enumerate() {\n            if *board_cell == Players::Blank {\n                available.push(Position {\n                    x: x as u8,\n                    y: y as u8,\n                });\n            }\n        }\n    }\n    available\n}\n\nfn win_check(player: Players, board: &[Vec<Players>]) -> bool {\n    if player == Players::Blank {\n        return false;\n    }\n\n    //Check for a win on the diagonals.\n    if (board[0][0] == board[1][1]) && (board[1][1] == board[2][2]) && (board[2][2] == player)\n        || (board[2][0] == board[1][1]) && (board[1][1] == board[0][2]) && (board[0][2] == player)\n    {\n        return true;\n    }\n\n    for i in 0..3 {\n        //Check for a win on the horizontals.\n        if (board[i][0] == board[i][1]) && (board[i][1] == board[i][2]) && (board[i][2] == player) {\n            return true;\n        }\n\n        //Check for a win on the verticals.\n        if (board[0][i] == board[1][i]) && (board[1][i] == board[2][i]) && (board[2][i] == player) {\n            return true;\n        }\n    }\n\n    false\n}\n\n//Minimize the actions of the opponent while maximizing the game state of the current player.\npub fn minimax(side: Players, board: &[Vec<Players>]) -> Option<PlayActions> {\n    //Check that board is in a valid state.\n    if win_check(Players::PlayerX, board) || win_check(Players::PlayerO, board) {\n        return None;\n    }\n\n    let opposite = match side {\n        Players::PlayerX => Players::PlayerO,\n        Players::PlayerO => Players::PlayerX,\n        Players::Blank => panic!(\"Minimax can't operate when a player isn't specified.\"),\n    };\n\n    let positions = available_positions(board);\n    if positions.is_empty() {\n        return None;\n    }\n\n    //Play position\n    let mut best_move: Option<PlayActions> = None;\n\n    for pos in positions {\n        let mut board_next = board.to_owned();\n        board_next[pos.y as usize][pos.x as usize] = side;\n\n        //Check for a win condition before recursion to determine if this node is terminal.\n        if win_check(Players::PlayerX, &board_next) {\n            append_playaction(\n                side,\n                &mut best_move,\n                SinglePlayAction {\n                    position: pos,\n                    side: Players::PlayerX,\n                },\n            );\n            continue;\n        }\n\n        if win_check(Players::PlayerO, &board_next) {\n            append_playaction(\n                side,\n                &mut best_move,\n                SinglePlayAction {\n                    position: pos,\n                    side: Players::PlayerO,\n                },\n            );\n            continue;\n        }\n\n        let result = minimax(opposite, &board_next);\n        let current_score = match result {\n            Some(x) => x.side,\n            _ => Players::Blank,\n        };\n\n        append_playaction(\n            side,\n            &mut best_move,\n            SinglePlayAction {\n                position: pos,\n                side: current_score,\n            },\n        )\n    }\n    best_move\n}\n\n//Promote only better or collate equally scored game plays\nfn append_playaction(\n    current_side: Players,\n    opt_play_actions: &mut Option<PlayActions>,\n    appendee: SinglePlayAction,\n) {\n    if opt_play_actions.is_none() {\n        *opt_play_actions = Some(PlayActions {\n            positions: vec![appendee.position],\n            side: appendee.side,\n        });\n        return;\n    }\n\n    let play_actions = opt_play_actions.as_mut().unwrap();\n\n    //New game action is scored from the current side and the current saved best score against the new game action.\n    match (current_side, play_actions.side, appendee.side) {\n        (Players::Blank, _, _) => panic!(\"Unreachable state.\"),\n\n        //Winning scores\n        (Players::PlayerX, Players::PlayerX, Players::PlayerX)\n        | (Players::PlayerO, Players::PlayerO, Players::PlayerO) => {\n            play_actions.positions.push(appendee.position);\n        }\n\n        //Non-winning to Winning scores\n        (Players::PlayerX, _, Players::PlayerX) => {\n            play_actions.side = Players::PlayerX;\n            play_actions.positions.clear();\n            play_actions.positions.push(appendee.position);\n        }\n        (Players::PlayerO, _, Players::PlayerO) => {\n            play_actions.side = Players::PlayerO;\n            play_actions.positions.clear();\n            play_actions.positions.push(appendee.position);\n        }\n\n        //Losing to Neutral scores\n        (Players::PlayerX, Players::PlayerO, Players::Blank)\n        | (Players::PlayerO, Players::PlayerX, Players::Blank) => {\n            play_actions.side = Players::Blank;\n            play_actions.positions.clear();\n            play_actions.positions.push(appendee.position);\n        }\n\n        //Ignoring lower scored plays\n        (Players::PlayerX, Players::PlayerX, _)\n        | (Players::PlayerO, Players::PlayerO, _)\n        | (Players::PlayerX, Players::Blank, Players::PlayerO)\n        | (Players::PlayerO, Players::Blank, Players::PlayerX) => {}\n\n        //No change hence append only\n        (_, _, _) => {\n            assert!(play_actions.side == appendee.side);\n            play_actions.positions.push(appendee.position);\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn win_state_check() {\n        let mut board = vec![vec![Players::Blank; 3]; 3];\n        board[0][0] = Players::PlayerX;\n        board[0][1] = Players::PlayerX;\n        board[0][2] = Players::PlayerX;\n        let responses = minimax(Players::PlayerO, &board);\n        assert_eq!(responses, None);\n    }\n\n    #[test]\n    fn win_state_check2() {\n        let mut board = vec![vec![Players::Blank; 3]; 3];\n        board[0][0] = Players::PlayerX;\n        board[0][1] = Players::PlayerO;\n        board[1][0] = Players::PlayerX;\n        board[1][1] = Players::PlayerO;\n        board[2][1] = Players::PlayerO;\n        let responses = minimax(Players::PlayerO, &board);\n        assert_eq!(responses, None);\n    }\n\n    #[test]\n    fn block_win_move() {\n        let mut board = vec![vec![Players::Blank; 3]; 3];\n        board[0][0] = Players::PlayerX;\n        board[0][1] = Players::PlayerX;\n        board[1][2] = Players::PlayerO;\n        board[2][2] = Players::PlayerO;\n        let responses = minimax(Players::PlayerX, &board);\n        assert_eq!(\n            responses,\n            Some(PlayActions {\n                positions: vec![Position { x: 2, y: 0 }],\n                side: Players::PlayerX\n            })\n        );\n    }\n\n    #[test]\n    fn block_move() {\n        let mut board = vec![vec![Players::Blank; 3]; 3];\n        board[0][1] = Players::PlayerX;\n        board[0][2] = Players::PlayerO;\n        board[2][0] = Players::PlayerO;\n        let responses = minimax(Players::PlayerX, &board);\n        assert_eq!(\n            responses,\n            Some(PlayActions {\n                positions: vec![Position { x: 1, y: 1 }],\n                side: Players::Blank\n            })\n        );\n    }\n\n    #[test]\n    fn expected_loss() {\n        let mut board = vec![vec![Players::Blank; 3]; 3];\n        board[0][0] = Players::PlayerX;\n        board[0][2] = Players::PlayerO;\n        board[1][0] = Players::PlayerX;\n        board[2][0] = Players::PlayerO;\n        board[2][2] = Players::PlayerO;\n        let responses = minimax(Players::PlayerX, &board);\n        assert_eq!(\n            responses,\n            Some(PlayActions {\n                positions: vec![\n                    Position { x: 1, y: 0 },\n                    Position { x: 1, y: 1 },\n                    Position { x: 2, y: 1 },\n                    Position { x: 1, y: 2 }\n                ],\n                side: Players::PlayerO\n            })\n        );\n    }\n}\n"
  },
  {
    "path": "src/graph/detect_cycle.rs",
    "content": "use std::collections::{HashMap, HashSet, VecDeque};\n\nuse crate::data_structures::{graph::Graph, DirectedGraph, UndirectedGraph};\n\npub trait DetectCycle {\n    fn detect_cycle_dfs(&self) -> bool;\n    fn detect_cycle_bfs(&self) -> bool;\n}\n\n// Helper function to detect cycle in an undirected graph using DFS graph traversal\nfn undirected_graph_detect_cycle_dfs<'a>(\n    graph: &'a UndirectedGraph,\n    visited_node: &mut HashSet<&'a String>,\n    parent: Option<&'a String>,\n    u: &'a String,\n) -> bool {\n    visited_node.insert(u);\n    for (v, _) in graph.adjacency_table().get(u).unwrap() {\n        if matches!(parent, Some(parent) if v == parent) {\n            continue;\n        }\n        if visited_node.contains(v)\n            || undirected_graph_detect_cycle_dfs(graph, visited_node, Some(u), v)\n        {\n            return true;\n        }\n    }\n    false\n}\n\n// Helper function to detect cycle in an undirected graph using BFS graph traversal\nfn undirected_graph_detect_cycle_bfs<'a>(\n    graph: &'a UndirectedGraph,\n    visited_node: &mut HashSet<&'a String>,\n    u: &'a String,\n) -> bool {\n    visited_node.insert(u);\n\n    // Initialize the queue for BFS, storing (current node, parent node) tuples\n    let mut queue = VecDeque::<(&String, Option<&String>)>::new();\n    queue.push_back((u, None));\n\n    while let Some((u, parent)) = queue.pop_front() {\n        for (v, _) in graph.adjacency_table().get(u).unwrap() {\n            if matches!(parent, Some(parent) if v == parent) {\n                continue;\n            }\n            if visited_node.contains(v) {\n                return true;\n            }\n            visited_node.insert(v);\n            queue.push_back((v, Some(u)));\n        }\n    }\n    false\n}\n\nimpl DetectCycle for UndirectedGraph {\n    fn detect_cycle_dfs(&self) -> bool {\n        let mut visited_node = HashSet::<&String>::new();\n        let adj = self.adjacency_table();\n        for u in adj.keys() {\n            if !visited_node.contains(u)\n                && undirected_graph_detect_cycle_dfs(self, &mut visited_node, None, u)\n            {\n                return true;\n            }\n        }\n        false\n    }\n\n    fn detect_cycle_bfs(&self) -> bool {\n        let mut visited_node = HashSet::<&String>::new();\n        let adj = self.adjacency_table();\n        for u in adj.keys() {\n            if !visited_node.contains(u)\n                && undirected_graph_detect_cycle_bfs(self, &mut visited_node, u)\n            {\n                return true;\n            }\n        }\n        false\n    }\n}\n\n// Helper function to detect cycle in a directed graph using DFS graph traversal\nfn directed_graph_detect_cycle_dfs<'a>(\n    graph: &'a DirectedGraph,\n    visited_node: &mut HashSet<&'a String>,\n    in_stack_visited_node: &mut HashSet<&'a String>,\n    u: &'a String,\n) -> bool {\n    visited_node.insert(u);\n    in_stack_visited_node.insert(u);\n    for (v, _) in graph.adjacency_table().get(u).unwrap() {\n        if visited_node.contains(v) && in_stack_visited_node.contains(v) {\n            return true;\n        }\n        if !visited_node.contains(v)\n            && directed_graph_detect_cycle_dfs(graph, visited_node, in_stack_visited_node, v)\n        {\n            return true;\n        }\n    }\n    in_stack_visited_node.remove(u);\n    false\n}\n\nimpl DetectCycle for DirectedGraph {\n    fn detect_cycle_dfs(&self) -> bool {\n        let mut visited_node = HashSet::<&String>::new();\n        let mut in_stack_visited_node = HashSet::<&String>::new();\n        let adj = self.adjacency_table();\n        for u in adj.keys() {\n            if !visited_node.contains(u)\n                && directed_graph_detect_cycle_dfs(\n                    self,\n                    &mut visited_node,\n                    &mut in_stack_visited_node,\n                    u,\n                )\n            {\n                return true;\n            }\n        }\n        false\n    }\n\n    // detect cycle in a the graph using Kahn's algorithm\n    // https://www.geeksforgeeks.org/detect-cycle-in-a-directed-graph-using-bfs/\n    fn detect_cycle_bfs(&self) -> bool {\n        // Set 0 in-degree for each vertex\n        let mut in_degree: HashMap<&String, usize> =\n            self.adjacency_table().keys().map(|k| (k, 0)).collect();\n\n        // Calculate in-degree for each vertex\n        for u in self.adjacency_table().keys() {\n            for (v, _) in self.adjacency_table().get(u).unwrap() {\n                *in_degree.get_mut(v).unwrap() += 1;\n            }\n        }\n        // Initialize queue with vertex having 0 in-degree\n        let mut queue: VecDeque<&String> = in_degree\n            .iter()\n            .filter(|(_, &degree)| degree == 0)\n            .map(|(&k, _)| k)\n            .collect();\n\n        let mut count = 0;\n        while let Some(u) = queue.pop_front() {\n            count += 1;\n            for (v, _) in self.adjacency_table().get(u).unwrap() {\n                in_degree.entry(v).and_modify(|d| {\n                    *d -= 1;\n                    if *d == 0 {\n                        queue.push_back(v);\n                    }\n                });\n            }\n        }\n\n        // If count of processed vertices is not equal to the number of vertices,\n        // the graph has a cycle\n        count != self.adjacency_table().len()\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::DetectCycle;\n    use crate::data_structures::{graph::Graph, DirectedGraph, UndirectedGraph};\n    fn get_undirected_single_node_with_loop() -> UndirectedGraph {\n        let mut res = UndirectedGraph::new();\n        res.add_edge((\"a\", \"a\", 1));\n        res\n    }\n    fn get_directed_single_node_with_loop() -> DirectedGraph {\n        let mut res = DirectedGraph::new();\n        res.add_edge((\"a\", \"a\", 1));\n        res\n    }\n    fn get_undirected_two_nodes_connected() -> UndirectedGraph {\n        let mut res = UndirectedGraph::new();\n        res.add_edge((\"a\", \"b\", 1));\n        res\n    }\n    fn get_directed_two_nodes_connected() -> DirectedGraph {\n        let mut res = DirectedGraph::new();\n        res.add_edge((\"a\", \"b\", 1));\n        res.add_edge((\"b\", \"a\", 1));\n        res\n    }\n    fn get_directed_two_nodes() -> DirectedGraph {\n        let mut res = DirectedGraph::new();\n        res.add_edge((\"a\", \"b\", 1));\n        res\n    }\n    fn get_undirected_triangle() -> UndirectedGraph {\n        let mut res = UndirectedGraph::new();\n        res.add_edge((\"a\", \"b\", 1));\n        res.add_edge((\"b\", \"c\", 1));\n        res.add_edge((\"c\", \"a\", 1));\n        res\n    }\n    fn get_directed_triangle() -> DirectedGraph {\n        let mut res = DirectedGraph::new();\n        res.add_edge((\"a\", \"b\", 1));\n        res.add_edge((\"b\", \"c\", 1));\n        res.add_edge((\"c\", \"a\", 1));\n        res\n    }\n    fn get_undirected_triangle_with_tail() -> UndirectedGraph {\n        let mut res = get_undirected_triangle();\n        res.add_edge((\"c\", \"d\", 1));\n        res.add_edge((\"d\", \"e\", 1));\n        res.add_edge((\"e\", \"f\", 1));\n        res.add_edge((\"g\", \"h\", 1));\n        res\n    }\n    fn get_directed_triangle_with_tail() -> DirectedGraph {\n        let mut res = get_directed_triangle();\n        res.add_edge((\"c\", \"d\", 1));\n        res.add_edge((\"d\", \"e\", 1));\n        res.add_edge((\"e\", \"f\", 1));\n        res.add_edge((\"g\", \"h\", 1));\n        res\n    }\n    fn get_undirected_graph_with_cycle() -> UndirectedGraph {\n        let mut res = UndirectedGraph::new();\n        res.add_edge((\"a\", \"b\", 1));\n        res.add_edge((\"a\", \"c\", 1));\n        res.add_edge((\"b\", \"c\", 1));\n        res.add_edge((\"b\", \"d\", 1));\n        res.add_edge((\"c\", \"d\", 1));\n        res\n    }\n    fn get_undirected_graph_without_cycle() -> UndirectedGraph {\n        let mut res = UndirectedGraph::new();\n        res.add_edge((\"a\", \"b\", 1));\n        res.add_edge((\"a\", \"c\", 1));\n        res.add_edge((\"b\", \"d\", 1));\n        res.add_edge((\"c\", \"e\", 1));\n        res\n    }\n    fn get_directed_graph_with_cycle() -> DirectedGraph {\n        let mut res = DirectedGraph::new();\n        res.add_edge((\"b\", \"a\", 1));\n        res.add_edge((\"c\", \"a\", 1));\n        res.add_edge((\"b\", \"c\", 1));\n        res.add_edge((\"c\", \"d\", 1));\n        res.add_edge((\"d\", \"b\", 1));\n        res\n    }\n    fn get_directed_graph_without_cycle() -> DirectedGraph {\n        let mut res = DirectedGraph::new();\n        res.add_edge((\"b\", \"a\", 1));\n        res.add_edge((\"c\", \"a\", 1));\n        res.add_edge((\"b\", \"c\", 1));\n        res.add_edge((\"c\", \"d\", 1));\n        res.add_edge((\"b\", \"d\", 1));\n        res\n    }\n    macro_rules! test_detect_cycle {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (graph, has_cycle) = $test_case;\n                    println!(\"detect_cycle_dfs: {}\", graph.detect_cycle_dfs());\n                    println!(\"detect_cycle_bfs: {}\", graph.detect_cycle_bfs());\n                    assert_eq!(graph.detect_cycle_dfs(), has_cycle);\n                    assert_eq!(graph.detect_cycle_bfs(), has_cycle);\n                }\n            )*\n        };\n    }\n    test_detect_cycle! {\n        undirected_empty: (UndirectedGraph::new(), false),\n        directed_empty: (DirectedGraph::new(), false),\n        undirected_single_node_with_loop: (get_undirected_single_node_with_loop(), true),\n        directed_single_node_with_loop: (get_directed_single_node_with_loop(), true),\n        undirected_two_nodes_connected: (get_undirected_two_nodes_connected(), false),\n        directed_two_nodes_connected: (get_directed_two_nodes_connected(), true),\n        directed_two_nodes: (get_directed_two_nodes(), false),\n        undirected_triangle: (get_undirected_triangle(), true),\n        undirected_triangle_with_tail: (get_undirected_triangle_with_tail(), true),\n        directed_triangle: (get_directed_triangle(), true),\n        directed_triangle_with_tail: (get_directed_triangle_with_tail(), true),\n        undirected_graph_with_cycle: (get_undirected_graph_with_cycle(), true),\n        undirected_graph_without_cycle: (get_undirected_graph_without_cycle(), false),\n        directed_graph_with_cycle: (get_directed_graph_with_cycle(), true),\n        directed_graph_without_cycle: (get_directed_graph_without_cycle(), false),\n    }\n}\n"
  },
  {
    "path": "src/graph/dijkstra.rs",
    "content": "use std::collections::{BTreeMap, BTreeSet};\nuse std::ops::Add;\n\ntype Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;\n\n// performs Dijsktra's algorithm on the given graph from the given start\n// the graph is a positively-weighted directed graph\n//\n// returns a map that for each reachable vertex associates the distance and the predecessor\n// since the start has no predecessor but is reachable, map[start] will be None\n//\n// Time: O(E * logV). For each vertex, we traverse each edge, resulting in O(E). For each edge, we\n// insert a new shortest path for a vertex into the tree, resulting in O(E * logV).\n// Space: O(V). The tree holds up to V vertices.\npub fn dijkstra<V: Ord + Copy, E: Ord + Copy + Add<Output = E>>(\n    graph: &Graph<V, E>,\n    start: V,\n) -> BTreeMap<V, Option<(V, E)>> {\n    let mut ans = BTreeMap::new();\n    let mut prio = BTreeSet::new();\n\n    // start is the special case that doesn't have a predecessor\n    ans.insert(start, None);\n\n    for (new, weight) in &graph[&start] {\n        ans.insert(*new, Some((start, *weight)));\n        prio.insert((*weight, *new));\n    }\n\n    while let Some((path_weight, vertex)) = prio.pop_first() {\n        for (next, weight) in &graph[&vertex] {\n            let new_weight = path_weight + *weight;\n            match ans.get(next) {\n                // if ans[next] is a lower dist than the alternative one, we do nothing\n                Some(Some((_, dist_next))) if new_weight >= *dist_next => {}\n                // if ans[next] is None then next is start and so the distance won't be changed, it won't be added again in prio\n                Some(None) => {}\n                // the new path is shorter, either new was not in ans or it was farther\n                _ => {\n                    if let Some(Some((_, prev_weight))) =\n                        ans.insert(*next, Some((vertex, new_weight)))\n                    {\n                        prio.remove(&(prev_weight, *next));\n                    }\n                    prio.insert((new_weight, *next));\n                }\n            }\n        }\n    }\n\n    ans\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{dijkstra, Graph};\n    use std::collections::BTreeMap;\n\n    fn add_edge<V: Ord + Copy, E: Ord>(graph: &mut Graph<V, E>, v1: V, v2: V, c: E) {\n        graph.entry(v1).or_default().insert(v2, c);\n        graph.entry(v2).or_default();\n    }\n\n    #[test]\n    fn single_vertex() {\n        let mut graph: Graph<usize, usize> = BTreeMap::new();\n        graph.insert(0, BTreeMap::new());\n\n        let mut dists = BTreeMap::new();\n        dists.insert(0, None);\n\n        assert_eq!(dijkstra(&graph, 0), dists);\n    }\n\n    #[test]\n    fn single_edge() {\n        let mut graph = BTreeMap::new();\n        add_edge(&mut graph, 0, 1, 2);\n\n        let mut dists_0 = BTreeMap::new();\n        dists_0.insert(0, None);\n        dists_0.insert(1, Some((0, 2)));\n\n        assert_eq!(dijkstra(&graph, 0), dists_0);\n\n        let mut dists_1 = BTreeMap::new();\n        dists_1.insert(1, None);\n\n        assert_eq!(dijkstra(&graph, 1), dists_1);\n    }\n\n    #[test]\n    fn tree_1() {\n        let mut graph = BTreeMap::new();\n        let mut dists = BTreeMap::new();\n        dists.insert(1, None);\n        for i in 1..100 {\n            add_edge(&mut graph, i, i * 2, i * 2);\n            add_edge(&mut graph, i, i * 2 + 1, i * 2 + 1);\n\n            match dists[&i] {\n                Some((_, d)) => {\n                    dists.insert(i * 2, Some((i, d + i * 2)));\n                    dists.insert(i * 2 + 1, Some((i, d + i * 2 + 1)));\n                }\n                None => {\n                    dists.insert(i * 2, Some((i, i * 2)));\n                    dists.insert(i * 2 + 1, Some((i, i * 2 + 1)));\n                }\n            }\n        }\n\n        assert_eq!(dijkstra(&graph, 1), dists);\n    }\n\n    #[test]\n    fn graph_1() {\n        let mut graph = BTreeMap::new();\n        add_edge(&mut graph, 'a', 'c', 12);\n        add_edge(&mut graph, 'a', 'd', 60);\n        add_edge(&mut graph, 'b', 'a', 10);\n        add_edge(&mut graph, 'c', 'b', 20);\n        add_edge(&mut graph, 'c', 'd', 32);\n        add_edge(&mut graph, 'e', 'a', 7);\n\n        let mut dists_a = BTreeMap::new();\n        dists_a.insert('a', None);\n        dists_a.insert('c', Some(('a', 12)));\n        dists_a.insert('d', Some(('c', 44)));\n        dists_a.insert('b', Some(('c', 32)));\n        assert_eq!(dijkstra(&graph, 'a'), dists_a);\n\n        let mut dists_b = BTreeMap::new();\n        dists_b.insert('b', None);\n        dists_b.insert('a', Some(('b', 10)));\n        dists_b.insert('c', Some(('a', 22)));\n        dists_b.insert('d', Some(('c', 54)));\n        assert_eq!(dijkstra(&graph, 'b'), dists_b);\n\n        let mut dists_c = BTreeMap::new();\n        dists_c.insert('c', None);\n        dists_c.insert('b', Some(('c', 20)));\n        dists_c.insert('d', Some(('c', 32)));\n        dists_c.insert('a', Some(('b', 30)));\n        assert_eq!(dijkstra(&graph, 'c'), dists_c);\n\n        let mut dists_d = BTreeMap::new();\n        dists_d.insert('d', None);\n        assert_eq!(dijkstra(&graph, 'd'), dists_d);\n\n        let mut dists_e = BTreeMap::new();\n        dists_e.insert('e', None);\n        dists_e.insert('a', Some(('e', 7)));\n        dists_e.insert('c', Some(('a', 19)));\n        dists_e.insert('d', Some(('c', 51)));\n        dists_e.insert('b', Some(('c', 39)));\n        assert_eq!(dijkstra(&graph, 'e'), dists_e);\n    }\n}\n"
  },
  {
    "path": "src/graph/dinic_maxflow.rs",
    "content": "use std::collections::VecDeque;\nuse std::ops::{Add, AddAssign, Neg, Sub, SubAssign};\n\n// We assume that graph vertices are numbered from 1 to n.\n\n/// Adjacency matrix\ntype Graph = Vec<Vec<usize>>;\n\n/// We assume that T::default() gives \"zero\" flow and T supports negative values\npub struct FlowEdge<T> {\n    pub sink: usize,\n    pub capacity: T,\n    pub flow: T,\n}\n\npub struct FlowResultEdge<T> {\n    pub source: usize,\n    pub sink: usize,\n    pub flow: T,\n}\n\nimpl<T: Clone + Copy + Add + AddAssign + Sub<Output = T> + SubAssign + Ord + Neg + Default>\n    FlowEdge<T>\n{\n    pub fn new(sink: usize, capacity: T) -> Self {\n        FlowEdge {\n            sink,\n            capacity,\n            flow: T::default(),\n        }\n    }\n}\n\npub struct DinicMaxFlow<T> {\n    /// BFS Level of each vertex. starts from 1\n    level: Vec<usize>,\n\n    /// The index of the last visited edge connected to each vertex\n    pub last_edge: Vec<usize>,\n\n    /// Holds wether the solution has already been calculated\n    network_solved: bool,\n\n    pub source: usize,\n    pub sink: usize,\n\n    /// Number of edges added to the residual network\n    pub num_edges: usize,\n    pub num_vertices: usize,\n\n    pub adj: Graph,\n\n    /// The list of flow edges\n    pub edges: Vec<FlowEdge<T>>,\n}\n\nimpl<T: Clone + Copy + Add + AddAssign + Sub<Output = T> + SubAssign + Neg + Ord + Default>\n    DinicMaxFlow<T>\n{\n    pub fn new(source: usize, sink: usize, num_vertices: usize) -> Self {\n        DinicMaxFlow {\n            level: vec![0; num_vertices + 1],\n            last_edge: vec![0; num_vertices + 1],\n            network_solved: false,\n            source,\n            sink,\n            num_edges: 0,\n            num_vertices,\n            adj: vec![vec![]; num_vertices + 1],\n            edges: vec![],\n        }\n    }\n    #[inline]\n    pub fn add_edge(&mut self, source: usize, sink: usize, capacity: T) {\n        self.edges.push(FlowEdge::new(sink, capacity));\n        // Add the reverse edge with zero capacity\n        self.edges.push(FlowEdge::new(source, T::default()));\n        // We inserted the m'th edge from source to sink\n        self.adj[source].push(self.num_edges);\n        self.adj[sink].push(self.num_edges + 1);\n        self.num_edges += 2;\n    }\n\n    fn bfs(&mut self) -> bool {\n        let mut q: VecDeque<usize> = VecDeque::new();\n        q.push_back(self.source);\n\n        while !q.is_empty() {\n            let v = q.pop_front().unwrap();\n            for &e in self.adj[v].iter() {\n                if self.edges[e].capacity <= self.edges[e].flow {\n                    continue;\n                }\n                let u = self.edges[e].sink;\n                if self.level[u] != 0 {\n                    continue;\n                }\n                self.level[u] = self.level[v] + 1;\n                q.push_back(u);\n            }\n        }\n\n        self.level[self.sink] != 0\n    }\n\n    fn dfs(&mut self, v: usize, pushed: T) -> T {\n        // We have pushed nothing, or we are at the sink\n        if v == self.sink {\n            return pushed;\n        }\n        for e_pos in self.last_edge[v]..self.adj[v].len() {\n            let e = self.adj[v][e_pos];\n            let u = self.edges[e].sink;\n            if (self.level[v] + 1) != self.level[u] || self.edges[e].capacity <= self.edges[e].flow\n            {\n                continue;\n            }\n            let down_flow = self.dfs(\n                u,\n                std::cmp::min(pushed, self.edges[e].capacity - self.edges[e].flow),\n            );\n            if down_flow == T::default() {\n                continue;\n            }\n            self.last_edge[v] = e_pos;\n            self.edges[e].flow += down_flow;\n            self.edges[e ^ 1].flow -= down_flow;\n            return down_flow;\n        }\n        self.last_edge[v] = self.adj[v].len();\n        T::default()\n    }\n\n    pub fn find_maxflow(&mut self, infinite_flow: T) -> T {\n        self.network_solved = true;\n        let mut total_flow: T = T::default();\n        loop {\n            self.level.fill(0);\n            self.level[self.source] = 1;\n            // There is no longer a path from source to sink in the residual\n            // network\n            if !self.bfs() {\n                break;\n            }\n            self.last_edge.fill(0);\n            let mut next_flow = self.dfs(self.source, infinite_flow);\n            while next_flow != T::default() {\n                total_flow += next_flow;\n                next_flow = self.dfs(self.source, infinite_flow);\n            }\n        }\n        total_flow\n    }\n\n    pub fn get_flow_edges(&mut self, infinite_flow: T) -> Vec<FlowResultEdge<T>> {\n        if !self.network_solved {\n            self.find_maxflow(infinite_flow);\n        }\n        let mut result = Vec::new();\n        for v in 1..self.adj.len() {\n            for &e_ind in self.adj[v].iter() {\n                let e = &self.edges[e_ind];\n                // Make sure that reverse edges from residual network are not\n                // included\n                if e.flow > T::default() {\n                    result.push(FlowResultEdge {\n                        source: v,\n                        sink: e.sink,\n                        flow: e.flow,\n                    });\n                }\n            }\n        }\n        result\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn small_graph() {\n        let mut flow: DinicMaxFlow<i32> = DinicMaxFlow::new(1, 6, 6);\n        flow.add_edge(1, 2, 16);\n        flow.add_edge(1, 4, 13);\n        flow.add_edge(2, 3, 12);\n        flow.add_edge(3, 4, 9);\n        flow.add_edge(3, 6, 20);\n        flow.add_edge(4, 2, 4);\n        flow.add_edge(4, 5, 14);\n        flow.add_edge(5, 3, 7);\n        flow.add_edge(5, 6, 4);\n\n        let max_flow = flow.find_maxflow(i32::MAX);\n        assert_eq!(max_flow, 23);\n\n        let mut sm_out = [0; 7];\n        let mut sm_in = [0; 7];\n\n        let flow_edges = flow.get_flow_edges(i32::MAX);\n        for e in flow_edges {\n            sm_out[e.source] += e.flow;\n            sm_in[e.sink] += e.flow;\n        }\n        for i in 2..=5 {\n            assert_eq!(sm_in[i], sm_out[i]);\n        }\n        assert_eq!(sm_in[1], 0);\n        assert_eq!(sm_out[1], max_flow);\n        assert_eq!(sm_in[6], max_flow);\n        assert_eq!(sm_out[6], 0);\n    }\n}\n"
  },
  {
    "path": "src/graph/disjoint_set_union.rs",
    "content": "//! This module implements the Disjoint Set Union (DSU), also known as Union-Find,\n//! which is an efficient data structure for keeping track of a set of elements\n//! partitioned into disjoint (non-overlapping) subsets.\n\n/// Represents a node in the Disjoint Set Union (DSU) structure  which\n/// keep track of the parent-child relationships in the disjoint sets.\npub struct DSUNode {\n    /// The index of the node's parent, or itself if it's the root.\n    parent: usize,\n    /// The size of the set rooted at this node, used for union by size.\n    size: usize,\n}\n\n/// Disjoint Set Union (Union-Find) data structure, particularly useful for\n/// managing dynamic connectivity problems such as determining\n/// if two elements are in the same subset or merging two subsets.\npub struct DisjointSetUnion {\n    /// List of DSU nodes where each element's parent and size are tracked.\n    nodes: Vec<DSUNode>,\n}\n\nimpl DisjointSetUnion {\n    /// Initializes `n + 1` disjoint sets, each element is its own parent.\n    ///\n    /// # Parameters\n    ///\n    /// - `n`: The number of elements to manage (`0` to `n` inclusive).\n    ///\n    /// # Returns\n    ///\n    /// A new instance of `DisjointSetUnion` with `n + 1` independent sets.\n    pub fn new(num_elements: usize) -> DisjointSetUnion {\n        let mut nodes = Vec::with_capacity(num_elements + 1);\n        for idx in 0..=num_elements {\n            nodes.push(DSUNode {\n                parent: idx,\n                size: 1,\n            });\n        }\n\n        Self { nodes }\n    }\n\n    /// Finds the representative (root) of the set containing `element` with path compression.\n    ///\n    /// Path compression ensures that future queries are faster by directly linking\n    /// all nodes in the path to the root.\n    ///\n    /// # Parameters\n    ///\n    /// - `element`: The element whose set representative is being found.\n    ///\n    /// # Returns\n    ///\n    /// The root representative of the set containing `element`.\n    pub fn find_set(&mut self, element: usize) -> usize {\n        if element != self.nodes[element].parent {\n            self.nodes[element].parent = self.find_set(self.nodes[element].parent);\n        }\n        self.nodes[element].parent\n    }\n\n    /// Merges the sets containing `first_elem` and `sec_elem` using union by size.\n    ///\n    /// The smaller set is always attached to the root of the larger set to ensure balanced trees.\n    ///\n    /// # Parameters\n    ///\n    /// - `first_elem`: The first element whose set is to be merged.\n    /// - `sec_elem`: The second element whose set is to be merged.\n    ///\n    /// # Returns\n    ///\n    /// The root of the merged set, or `usize::MAX` if both elements are already in the same set.\n    pub fn merge(&mut self, first_elem: usize, sec_elem: usize) -> usize {\n        let mut first_root = self.find_set(first_elem);\n        let mut sec_root = self.find_set(sec_elem);\n\n        if first_root == sec_root {\n            // Already in the same set, no merge required\n            return usize::MAX;\n        }\n\n        // Union by size: attach the smaller tree under the larger tree\n        if self.nodes[first_root].size < self.nodes[sec_root].size {\n            std::mem::swap(&mut first_root, &mut sec_root);\n        }\n\n        self.nodes[sec_root].parent = first_root;\n        self.nodes[first_root].size += self.nodes[sec_root].size;\n\n        first_root\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_disjoint_set_union() {\n        let mut dsu = DisjointSetUnion::new(10);\n\n        dsu.merge(1, 2);\n        dsu.merge(2, 3);\n        dsu.merge(1, 9);\n        dsu.merge(4, 5);\n        dsu.merge(7, 8);\n        dsu.merge(4, 8);\n        dsu.merge(6, 9);\n\n        assert_eq!(dsu.find_set(1), dsu.find_set(2));\n        assert_eq!(dsu.find_set(1), dsu.find_set(3));\n        assert_eq!(dsu.find_set(1), dsu.find_set(6));\n        assert_eq!(dsu.find_set(1), dsu.find_set(9));\n\n        assert_eq!(dsu.find_set(4), dsu.find_set(5));\n        assert_eq!(dsu.find_set(4), dsu.find_set(7));\n        assert_eq!(dsu.find_set(4), dsu.find_set(8));\n\n        assert_ne!(dsu.find_set(1), dsu.find_set(10));\n        assert_ne!(dsu.find_set(4), dsu.find_set(10));\n\n        dsu.merge(3, 4);\n\n        assert_eq!(dsu.find_set(1), dsu.find_set(2));\n        assert_eq!(dsu.find_set(1), dsu.find_set(3));\n        assert_eq!(dsu.find_set(1), dsu.find_set(6));\n        assert_eq!(dsu.find_set(1), dsu.find_set(9));\n        assert_eq!(dsu.find_set(1), dsu.find_set(4));\n        assert_eq!(dsu.find_set(1), dsu.find_set(5));\n        assert_eq!(dsu.find_set(1), dsu.find_set(7));\n        assert_eq!(dsu.find_set(1), dsu.find_set(8));\n\n        assert_ne!(dsu.find_set(1), dsu.find_set(10));\n\n        dsu.merge(10, 1);\n        assert_eq!(dsu.find_set(10), dsu.find_set(1));\n        assert_eq!(dsu.find_set(10), dsu.find_set(2));\n        assert_eq!(dsu.find_set(10), dsu.find_set(3));\n        assert_eq!(dsu.find_set(10), dsu.find_set(4));\n        assert_eq!(dsu.find_set(10), dsu.find_set(5));\n        assert_eq!(dsu.find_set(10), dsu.find_set(6));\n        assert_eq!(dsu.find_set(10), dsu.find_set(7));\n        assert_eq!(dsu.find_set(10), dsu.find_set(8));\n        assert_eq!(dsu.find_set(10), dsu.find_set(9));\n    }\n}\n"
  },
  {
    "path": "src/graph/eulerian_path.rs",
    "content": "//! This module provides functionality to find an Eulerian path in a directed graph.\n//! An Eulerian path visits every edge exactly once. The algorithm checks if an Eulerian\n//! path exists and, if so, constructs and returns the path.\n\nuse std::collections::LinkedList;\n\n/// Finds an Eulerian path in a directed graph.\n///\n/// # Arguments\n///\n/// * `node_count` - The number of nodes in the graph.\n/// * `edge_list` - A vector of tuples representing directed edges, where each tuple is of the form `(start, end)`.\n///\n/// # Returns\n///\n/// An `Option<Vec<usize>>` containing the Eulerian path if it exists; otherwise, `None`.\npub fn find_eulerian_path(node_count: usize, edge_list: Vec<(usize, usize)>) -> Option<Vec<usize>> {\n    let mut adjacency_list = vec![Vec::new(); node_count];\n    for (start, end) in edge_list {\n        adjacency_list[start].push(end);\n    }\n\n    let mut eulerian_solver = EulerianPathSolver::new(adjacency_list);\n    eulerian_solver.find_path()\n}\n\n/// Struct to represent the solver for finding an Eulerian path in a directed graph.\npub struct EulerianPathSolver {\n    node_count: usize,\n    edge_count: usize,\n    in_degrees: Vec<usize>,\n    out_degrees: Vec<usize>,\n    eulerian_path: LinkedList<usize>,\n    adjacency_list: Vec<Vec<usize>>,\n}\n\nimpl EulerianPathSolver {\n    /// Creates a new instance of `EulerianPathSolver`.\n    ///\n    /// # Arguments\n    ///\n    /// * `adjacency_list` - The graph represented as an adjacency list.\n    ///\n    /// # Returns\n    ///\n    /// A new instance of `EulerianPathSolver`.\n    pub fn new(adjacency_list: Vec<Vec<usize>>) -> Self {\n        Self {\n            node_count: adjacency_list.len(),\n            edge_count: 0,\n            in_degrees: vec![0; adjacency_list.len()],\n            out_degrees: vec![0; adjacency_list.len()],\n            eulerian_path: LinkedList::new(),\n            adjacency_list,\n        }\n    }\n\n    /// Find the Eulerian path if it exists.\n    ///\n    /// # Returns\n    ///\n    /// An `Option<Vec<usize>>` containing the Eulerian path if found; otherwise, `None`.\n    ///\n    /// If multiple Eulerian paths exist, the one found will be returned, but it may not be unique.\n    fn find_path(&mut self) -> Option<Vec<usize>> {\n        self.initialize_degrees();\n\n        if !self.has_eulerian_path() {\n            return None;\n        }\n\n        let start_node = self.get_start_node();\n        self.depth_first_search(start_node);\n\n        if self.eulerian_path.len() != self.edge_count + 1 {\n            return None;\n        }\n\n        let mut path = Vec::with_capacity(self.edge_count + 1);\n        while let Some(node) = self.eulerian_path.pop_front() {\n            path.push(node);\n        }\n\n        Some(path)\n    }\n\n    /// Initializes in-degrees and out-degrees for each node and counts total edges.\n    fn initialize_degrees(&mut self) {\n        for (start_node, neighbors) in self.adjacency_list.iter().enumerate() {\n            for &end_node in neighbors {\n                self.in_degrees[end_node] += 1;\n                self.out_degrees[start_node] += 1;\n                self.edge_count += 1;\n            }\n        }\n    }\n\n    /// Checks if an Eulerian path exists in the graph.\n    ///\n    /// # Returns\n    ///\n    /// `true` if an Eulerian path exists; otherwise, `false`.\n    fn has_eulerian_path(&self) -> bool {\n        if self.edge_count == 0 {\n            return false;\n        }\n\n        let (mut start_nodes, mut end_nodes) = (0, 0);\n        for i in 0..self.node_count {\n            let (in_degree, out_degree) =\n                (self.in_degrees[i] as isize, self.out_degrees[i] as isize);\n            match out_degree - in_degree {\n                1 => start_nodes += 1,\n                -1 => end_nodes += 1,\n                degree_diff if degree_diff.abs() > 1 => return false,\n                _ => (),\n            }\n        }\n\n        (start_nodes == 0 && end_nodes == 0) || (start_nodes == 1 && end_nodes == 1)\n    }\n\n    /// Finds the starting node for the Eulerian path.\n    ///\n    /// # Returns\n    ///\n    /// The index of the starting node.\n    fn get_start_node(&self) -> usize {\n        for i in 0..self.node_count {\n            if self.out_degrees[i] > self.in_degrees[i] {\n                return i;\n            }\n        }\n        (0..self.node_count)\n            .find(|&i| self.out_degrees[i] > 0)\n            .unwrap_or(0)\n    }\n\n    /// Performs depth-first search to construct the Eulerian path.\n    ///\n    /// # Arguments\n    ///\n    /// * `curr_node` - The current node being visited in the DFS traversal.\n    fn depth_first_search(&mut self, curr_node: usize) {\n        while self.out_degrees[curr_node] > 0 {\n            let next_node = self.adjacency_list[curr_node][self.out_degrees[curr_node] - 1];\n            self.out_degrees[curr_node] -= 1;\n            self.depth_first_search(next_node);\n        }\n        self.eulerian_path.push_front(curr_node);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_cases {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (n, edges, expected) = $test_case;\n                    assert_eq!(find_eulerian_path(n, edges), expected);\n                }\n            )*\n        }\n    }\n\n    test_cases! {\n        test_eulerian_cycle: (\n            7,\n            vec![\n                (1, 2),\n                (1, 3),\n                (2, 2),\n                (2, 4),\n                (2, 4),\n                (3, 1),\n                (3, 2),\n                (3, 5),\n                (4, 3),\n                (4, 6),\n                (5, 6),\n                (6, 3)\n            ],\n            Some(vec![1, 3, 5, 6, 3, 2, 4, 3, 1, 2, 2, 4, 6])\n        ),\n        test_simple_path: (\n            5,\n            vec![\n                (0, 1),\n                (1, 2),\n                (1, 4),\n                (1, 3),\n                (2, 1),\n                (4, 1)\n            ],\n            Some(vec![0, 1, 4, 1, 2, 1, 3])\n        ),\n        test_disconnected_graph: (\n            4,\n            vec![\n                (0, 1),\n                (2, 3)\n            ],\n            None::<Vec<usize>>\n        ),\n        test_single_cycle: (\n            4,\n            vec![\n                (0, 1),\n                (1, 2),\n                (2, 3),\n                (3, 0)\n            ],\n            Some(vec![0, 1, 2, 3, 0])\n        ),\n        test_empty_graph: (\n            3,\n            vec![],\n            None::<Vec<usize>>\n        ),\n        test_unbalanced_path: (\n            3,\n            vec![\n                (0, 1),\n                (1, 2),\n                (2, 0),\n                (0, 2)\n            ],\n            Some(vec![0, 2, 0, 1, 2])\n        ),\n        test_no_eulerian_path: (\n            3,\n            vec![\n                (0, 1),\n                (0, 2)\n            ],\n            None::<Vec<usize>>\n        ),\n        test_complex_eulerian_path: (\n            6,\n            vec![\n                (0, 1),\n                (1, 2),\n                (2, 3),\n                (3, 4),\n                (4, 0),\n                (0, 5),\n                (5, 0),\n                (2, 0)\n            ],\n            Some(vec![2, 0, 5, 0, 1, 2, 3, 4, 0])\n        ),\n        test_single_node_self_loop: (\n            1,\n            vec![(0, 0)],\n            Some(vec![0, 0])\n        ),\n        test_complete_graph: (\n            3,\n            vec![\n                (0, 1),\n                (0, 2),\n                (1, 0),\n                (1, 2),\n                (2, 0),\n                (2, 1)\n            ],\n            Some(vec![0, 2, 1, 2, 0, 1, 0])\n        ),\n        test_multiple_disconnected_components: (\n            6,\n            vec![\n                (0, 1),\n                (2, 3),\n                (4, 5)\n            ],\n            None::<Vec<usize>>\n        ),\n        test_unbalanced_graph_with_path: (\n            4,\n            vec![\n                (0, 1),\n                (1, 2),\n                (2, 3),\n                (3, 1)\n            ],\n            Some(vec![0, 1, 2, 3, 1])\n        ),\n        test_node_with_no_edges: (\n            4,\n            vec![\n                (0, 1),\n                (1, 2)\n            ],\n            Some(vec![0, 1, 2])\n        ),\n        test_multiple_edges_between_same_nodes: (\n            3,\n            vec![\n                (0, 1),\n                (1, 2),\n                (1, 2),\n                (2, 0)\n            ],\n            Some(vec![1, 2, 0, 1, 2])\n        ),\n        test_larger_graph_with_eulerian_path: (\n            10,\n            vec![\n                (0, 1),\n                (1, 2),\n                (2, 3),\n                (3, 4),\n                (4, 5),\n                (5, 6),\n                (6, 7),\n                (7, 8),\n                (8, 9),\n                (9, 0),\n                (1, 6),\n                (6, 3),\n                (3, 8)\n            ],\n            Some(vec![1, 6, 3, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8])\n        ),\n        test_no_edges_multiple_nodes: (\n            5,\n            vec![],\n            None::<Vec<usize>>\n        ),\n        test_multiple_start_and_end_nodes: (\n            4,\n            vec![\n                (0, 1),\n                (1, 2),\n                (2, 0),\n                (0, 2),\n                (1, 3)\n            ],\n            None::<Vec<usize>>\n        ),\n        test_single_edge: (\n            2,\n            vec![(0, 1)],\n            Some(vec![0, 1])\n        ),\n        test_multiple_eulerian_paths: (\n            4,\n            vec![\n                (0, 1),\n                (1, 2),\n                (2, 0),\n                (0, 3),\n                (3, 0)\n            ],\n            Some(vec![0, 3, 0, 1, 2, 0])\n        ),\n        test_dag_path: (\n            4,\n            vec![\n                (0, 1),\n                (1, 2),\n                (2, 3)\n            ],\n            Some(vec![0, 1, 2, 3])\n        ),\n        test_parallel_edges_case: (\n            2,\n            vec![\n                (0, 1),\n                (0, 1),\n                (1, 0)\n            ],\n            Some(vec![0, 1, 0, 1])\n        ),\n    }\n}\n"
  },
  {
    "path": "src/graph/floyd_warshall.rs",
    "content": "use num_traits::Zero;\nuse std::collections::BTreeMap;\nuse std::ops::Add;\n\ntype Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;\n\n/// Performs the Floyd-Warshall algorithm on the input graph.\\\n/// The graph is a weighted, directed graph with no negative cycles.\n///\n/// Returns a map storing the distance from each node to all the others.\\\n/// i.e. For each vertex `u`, `map[u][v] == Some(distance)` means\n/// distance is the sum of the weights of the edges on the shortest path\n/// from `u` to `v`.\n///\n/// For a key `v`, if `map[v].len() == 0`, then `v` cannot reach any other vertex, but is in the graph\n/// (island node, or sink in the case of a directed graph)\npub fn floyd_warshall<V: Ord + Copy, E: Ord + Copy + Add<Output = E> + num_traits::Zero>(\n    graph: &Graph<V, E>,\n) -> BTreeMap<V, BTreeMap<V, E>> {\n    let mut map: BTreeMap<V, BTreeMap<V, E>> = BTreeMap::new();\n    for (u, edges) in graph.iter() {\n        if !map.contains_key(u) {\n            map.insert(*u, BTreeMap::new());\n        }\n        map.entry(*u).or_default().insert(*u, Zero::zero());\n        for (v, weight) in edges.iter() {\n            if !map.contains_key(v) {\n                map.insert(*v, BTreeMap::new());\n            }\n            map.entry(*v).or_default().insert(*v, Zero::zero());\n            map.entry(*u).and_modify(|mp| {\n                mp.insert(*v, *weight);\n            });\n        }\n    }\n    let keys = map.keys().copied().collect::<Vec<_>>();\n    for &k in &keys {\n        for &i in &keys {\n            if !map[&i].contains_key(&k) {\n                continue;\n            }\n            for &j in &keys {\n                if i == j {\n                    continue;\n                }\n                if !map[&k].contains_key(&j) {\n                    continue;\n                }\n                let entry_i_j = map[&i].get(&j);\n                let entry_i_k = map[&i][&k];\n                let entry_k_j = map[&k][&j];\n                match entry_i_j {\n                    Some(&e) => {\n                        if e > entry_i_k + entry_k_j {\n                            map.entry(i).or_default().insert(j, entry_i_k + entry_k_j);\n                        }\n                    }\n                    None => {\n                        map.entry(i).or_default().insert(j, entry_i_k + entry_k_j);\n                    }\n                };\n            }\n        }\n    }\n    map\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{floyd_warshall, Graph};\n    use std::collections::BTreeMap;\n\n    fn add_edge<V: Ord + Copy, E: Ord + Copy>(graph: &mut Graph<V, E>, v1: V, v2: V, c: E) {\n        graph.entry(v1).or_default().insert(v2, c);\n    }\n\n    fn bi_add_edge<V: Ord + Copy, E: Ord + Copy>(graph: &mut Graph<V, E>, v1: V, v2: V, c: E) {\n        add_edge(graph, v1, v2, c);\n        add_edge(graph, v2, v1, c);\n    }\n\n    #[test]\n    fn single_vertex() {\n        let mut graph: Graph<usize, usize> = BTreeMap::new();\n        graph.insert(0, BTreeMap::new());\n\n        let mut dists = BTreeMap::new();\n        dists.insert(0, BTreeMap::new());\n        dists.get_mut(&0).unwrap().insert(0, 0);\n        assert_eq!(floyd_warshall(&graph), dists);\n    }\n\n    #[test]\n    fn single_edge() {\n        let mut graph = BTreeMap::new();\n        bi_add_edge(&mut graph, 0, 1, 2);\n        bi_add_edge(&mut graph, 1, 2, 3);\n\n        let mut dists_0 = BTreeMap::new();\n        dists_0.insert(0, BTreeMap::new());\n        dists_0.insert(1, BTreeMap::new());\n        dists_0.insert(2, BTreeMap::new());\n        dists_0.get_mut(&0).unwrap().insert(0, 0);\n        dists_0.get_mut(&1).unwrap().insert(1, 0);\n        dists_0.get_mut(&2).unwrap().insert(2, 0);\n        dists_0.get_mut(&1).unwrap().insert(0, 2);\n        dists_0.get_mut(&0).unwrap().insert(1, 2);\n        dists_0.get_mut(&1).unwrap().insert(2, 3);\n        dists_0.get_mut(&2).unwrap().insert(1, 3);\n        dists_0.get_mut(&2).unwrap().insert(0, 5);\n        dists_0.get_mut(&0).unwrap().insert(2, 5);\n\n        assert_eq!(floyd_warshall(&graph), dists_0);\n    }\n\n    #[test]\n    fn graph_1() {\n        let mut graph = BTreeMap::new();\n        add_edge(&mut graph, 'a', 'c', 12);\n        add_edge(&mut graph, 'a', 'd', 60);\n        add_edge(&mut graph, 'b', 'a', 10);\n        add_edge(&mut graph, 'c', 'b', 20);\n        add_edge(&mut graph, 'c', 'd', 32);\n        add_edge(&mut graph, 'e', 'a', 7);\n\n        let mut dists_a = BTreeMap::new();\n        dists_a.insert('d', BTreeMap::new());\n\n        dists_a.entry('a').or_insert(BTreeMap::new()).insert('a', 0);\n        dists_a.entry('b').or_insert(BTreeMap::new()).insert('b', 0);\n        dists_a.entry('c').or_insert(BTreeMap::new()).insert('c', 0);\n        dists_a.entry('d').or_insert(BTreeMap::new()).insert('d', 0);\n        dists_a.entry('e').or_insert(BTreeMap::new()).insert('e', 0);\n        dists_a\n            .entry('a')\n            .or_insert(BTreeMap::new())\n            .insert('c', 12);\n        dists_a\n            .entry('c')\n            .or_insert(BTreeMap::new())\n            .insert('a', 30);\n        dists_a\n            .entry('c')\n            .or_insert(BTreeMap::new())\n            .insert('b', 20);\n        dists_a\n            .entry('c')\n            .or_insert(BTreeMap::new())\n            .insert('d', 32);\n        dists_a.entry('e').or_insert(BTreeMap::new()).insert('a', 7);\n        dists_a\n            .entry('b')\n            .or_insert(BTreeMap::new())\n            .insert('a', 10);\n        dists_a\n            .entry('a')\n            .or_insert(BTreeMap::new())\n            .insert('d', 44);\n        dists_a\n            .entry('a')\n            .or_insert(BTreeMap::new())\n            .insert('b', 32);\n        dists_a\n            .entry('a')\n            .or_insert(BTreeMap::new())\n            .insert('b', 32);\n        dists_a\n            .entry('b')\n            .or_insert(BTreeMap::new())\n            .insert('c', 22);\n\n        dists_a\n            .entry('b')\n            .or_insert(BTreeMap::new())\n            .insert('d', 54);\n        dists_a\n            .entry('e')\n            .or_insert(BTreeMap::new())\n            .insert('c', 19);\n        dists_a\n            .entry('e')\n            .or_insert(BTreeMap::new())\n            .insert('d', 51);\n        dists_a\n            .entry('e')\n            .or_insert(BTreeMap::new())\n            .insert('b', 39);\n\n        assert_eq!(floyd_warshall(&graph), dists_a);\n    }\n}\n"
  },
  {
    "path": "src/graph/ford_fulkerson.rs",
    "content": "//! The Ford-Fulkerson algorithm is a widely used algorithm to solve the maximum flow problem in a flow network.\n//!\n//! The maximum flow problem involves determining the maximum amount of flow that can be sent from a source vertex to a sink vertex\n//! in a directed weighted graph, subject to capacity constraints on the edges.\n\nuse std::collections::VecDeque;\n\n/// Enum representing the possible errors that can occur when running the Ford-Fulkerson algorithm.\n#[derive(Debug, PartialEq)]\npub enum FordFulkersonError {\n    EmptyGraph,\n    ImproperGraph,\n    SourceOutOfBounds,\n    SinkOutOfBounds,\n}\n\n/// Performs a Breadth-First Search (BFS) on the residual graph to find an augmenting path\n/// from the source vertex `source` to the sink vertex `sink`.\n///\n/// # Arguments\n///\n/// * `graph` - A reference to the residual graph represented as an adjacency matrix.\n/// * `source` - The source vertex.\n/// * `sink` - The sink vertex.\n/// * `parent` - A mutable reference to the parent array used to store the augmenting path.\n///\n/// # Returns\n///\n/// Returns `true` if an augmenting path is found from `source` to `sink`, `false` otherwise.\nfn bfs(graph: &[Vec<usize>], source: usize, sink: usize, parent: &mut [usize]) -> bool {\n    let mut visited = vec![false; graph.len()];\n    visited[source] = true;\n    parent[source] = usize::MAX;\n\n    let mut queue = VecDeque::new();\n    queue.push_back(source);\n\n    while let Some(current_vertex) = queue.pop_front() {\n        for (previous_vertex, &capacity) in graph[current_vertex].iter().enumerate() {\n            if !visited[previous_vertex] && capacity > 0 {\n                visited[previous_vertex] = true;\n                parent[previous_vertex] = current_vertex;\n                if previous_vertex == sink {\n                    return true;\n                }\n                queue.push_back(previous_vertex);\n            }\n        }\n    }\n\n    false\n}\n\n/// Validates the input parameters for the Ford-Fulkerson algorithm.\n///\n/// This function checks if the provided graph, source vertex, and sink vertex\n/// meet the requirements for the Ford-Fulkerson algorithm. It ensures the graph\n/// is non-empty, square (each row has the same length as the number of rows), and\n/// that the source and sink vertices are within the valid range of vertex indices.\n///\n/// # Arguments\n///\n/// * `graph` - A reference to the flow network represented as an adjacency matrix.\n/// * `source` - The source vertex.\n/// * `sink` - The sink vertex.\n///\n/// # Returns\n///\n/// Returns `Ok(())` if the input parameters are valid, otherwise returns an appropriate\n/// `FordFulkersonError`.\nfn validate_ford_fulkerson_input(\n    graph: &[Vec<usize>],\n    source: usize,\n    sink: usize,\n) -> Result<(), FordFulkersonError> {\n    if graph.is_empty() {\n        return Err(FordFulkersonError::EmptyGraph);\n    }\n\n    if graph.iter().any(|row| row.len() != graph.len()) {\n        return Err(FordFulkersonError::ImproperGraph);\n    }\n\n    if source >= graph.len() {\n        return Err(FordFulkersonError::SourceOutOfBounds);\n    }\n\n    if sink >= graph.len() {\n        return Err(FordFulkersonError::SinkOutOfBounds);\n    }\n\n    Ok(())\n}\n\n/// Applies the Ford-Fulkerson algorithm to find the maximum flow in a flow network\n/// represented by a weighted directed graph.\n///\n/// # Arguments\n///\n/// * `graph` - A mutable reference to the flow network represented as an adjacency matrix.\n/// * `source` - The source vertex.\n/// * `sink` - The sink vertex.\n///\n/// # Returns\n///\n/// Returns the maximum flow and the residual graph\npub fn ford_fulkerson(\n    graph: &[Vec<usize>],\n    source: usize,\n    sink: usize,\n) -> Result<usize, FordFulkersonError> {\n    validate_ford_fulkerson_input(graph, source, sink)?;\n\n    let mut residual_graph = graph.to_owned();\n    let mut parent = vec![usize::MAX; graph.len()];\n    let mut max_flow = 0;\n\n    while bfs(&residual_graph, source, sink, &mut parent) {\n        let mut path_flow = usize::MAX;\n        let mut previous_vertex = sink;\n\n        while previous_vertex != source {\n            let current_vertex = parent[previous_vertex];\n            path_flow = path_flow.min(residual_graph[current_vertex][previous_vertex]);\n            previous_vertex = current_vertex;\n        }\n\n        previous_vertex = sink;\n        while previous_vertex != source {\n            let current_vertex = parent[previous_vertex];\n            residual_graph[current_vertex][previous_vertex] -= path_flow;\n            residual_graph[previous_vertex][current_vertex] += path_flow;\n            previous_vertex = current_vertex;\n        }\n\n        max_flow += path_flow;\n    }\n\n    Ok(max_flow)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_max_flow {\n        ($($name:ident: $tc:expr,)* ) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (graph, source, sink, expected_result) = $tc;\n                    assert_eq!(ford_fulkerson(&graph, source, sink), expected_result);\n                }\n            )*\n        };\n    }\n\n    test_max_flow! {\n        test_empty_graph: (\n            vec![],\n            0,\n            0,\n            Err(FordFulkersonError::EmptyGraph),\n        ),\n        test_source_out_of_bound: (\n            vec![\n                vec![0, 8, 0, 0, 3, 0],\n                vec![0, 0, 9, 0, 0, 0],\n                vec![0, 0, 0, 0, 7, 2],\n                vec![0, 0, 0, 0, 0, 5],\n                vec![0, 0, 7, 4, 0, 0],\n                vec![0, 0, 0, 0, 0, 0],\n            ],\n            6,\n            5,\n            Err(FordFulkersonError::SourceOutOfBounds),\n        ),\n        test_sink_out_of_bound: (\n            vec![\n                vec![0, 8, 0, 0, 3, 0],\n                vec![0, 0, 9, 0, 0, 0],\n                vec![0, 0, 0, 0, 7, 2],\n                vec![0, 0, 0, 0, 0, 5],\n                vec![0, 0, 7, 4, 0, 0],\n                vec![0, 0, 0, 0, 0, 0],\n            ],\n            0,\n            6,\n            Err(FordFulkersonError::SinkOutOfBounds),\n        ),\n        test_improper_graph: (\n            vec![\n                vec![0, 8],\n                vec![0],\n            ],\n            0,\n            1,\n            Err(FordFulkersonError::ImproperGraph),\n        ),\n        test_graph_with_small_flow: (\n            vec![\n                vec![0, 8, 0, 0, 3, 0],\n                vec![0, 0, 9, 0, 0, 0],\n                vec![0, 0, 0, 0, 7, 2],\n                vec![0, 0, 0, 0, 0, 5],\n                vec![0, 0, 7, 4, 0, 0],\n                vec![0, 0, 0, 0, 0, 0],\n            ],\n            0,\n            5,\n            Ok(6),\n        ),\n        test_graph_with_medium_flow: (\n            vec![\n                vec![0, 10, 0, 10, 0, 0],\n                vec![0, 0, 4, 2, 8, 0],\n                vec![0, 0, 0, 0, 0, 10],\n                vec![0, 0, 0, 0, 9, 0],\n                vec![0, 0, 6, 0, 0, 10],\n                vec![0, 0, 0, 0, 0, 0],\n            ],\n            0,\n            5,\n            Ok(19),\n        ),\n        test_graph_with_large_flow: (\n            vec![\n                vec![0, 12, 0, 13, 0, 0],\n                vec![0, 0, 10, 0, 0, 0],\n                vec![0, 0, 0, 13, 3, 15],\n                vec![0, 0, 7, 0, 15, 0],\n                vec![0, 0, 6, 0, 0, 17],\n                vec![0, 0, 0, 0, 0, 0],\n            ],\n            0,\n            5,\n            Ok(23),\n        ),\n        test_complex_graph: (\n            vec![\n                vec![0, 16, 13, 0, 0, 0],\n                vec![0, 0, 10, 12, 0, 0],\n                vec![0, 4, 0, 0, 14, 0],\n                vec![0, 0, 9, 0, 0, 20],\n                vec![0, 0, 0, 7, 0, 4],\n                vec![0, 0, 0, 0, 0, 0],\n            ],\n            0,\n            5,\n            Ok(23),\n        ),\n        test_disconnected_graph: (\n            vec![\n                vec![0, 0, 0, 0],\n                vec![0, 0, 0, 1],\n                vec![0, 0, 0, 1],\n                vec![0, 0, 0, 0],\n            ],\n            0,\n            3,\n            Ok(0),\n        ),\n        test_unconnected_sink: (\n            vec![\n                vec![0, 4, 0, 3, 0, 0],\n                vec![0, 0, 4, 0, 8, 0],\n                vec![0, 0, 0, 3, 0, 2],\n                vec![0, 0, 0, 0, 6, 0],\n                vec![0, 0, 6, 0, 0, 6],\n                vec![0, 0, 0, 0, 0, 0],\n            ],\n            0,\n            5,\n            Ok(7),\n        ),\n        test_no_edges: (\n            vec![\n                vec![0, 0, 0],\n                vec![0, 0, 0],\n                vec![0, 0, 0],\n            ],\n            0,\n            2,\n            Ok(0),\n        ),\n        test_single_vertex: (\n            vec![\n                vec![0],\n            ],\n            0,\n            0,\n            Ok(0),\n        ),\n        test_self_loop: (\n            vec![\n                vec![10, 0],\n                vec![0, 0],\n            ],\n            0,\n            1,\n            Ok(0),\n        ),\n        test_same_source_sink: (\n            vec![\n                vec![0, 10, 10],\n                vec![0, 0, 10],\n                vec![0, 0, 0],\n            ],\n            0,\n            0,\n            Ok(0),\n        ),\n    }\n}\n"
  },
  {
    "path": "src/graph/graph_enumeration.rs",
    "content": "use std::collections::BTreeMap;\n\ntype Graph<Vertex> = BTreeMap<Vertex, Vec<Vertex>>;\n\n/*\nThis function creates a graph with vertices numbered from 1 to n for any input\n`Graph<V>`. The result is in the form of Vec<Vec<usize> to make implementing\nother algorithms on the graph easier and help with performance.\n\nWe expect that all vertices, even the isolated ones, to have an entry in `adj`\n(possibly an empty vector)\n*/\npub fn enumerate_graph<V: Ord + Clone>(adj: &Graph<V>) -> Vec<Vec<usize>> {\n    let mut result = vec![vec![]; adj.len() + 1];\n    let ordering: Vec<V> = adj.keys().cloned().collect();\n    for (zero_idx, edges) in adj.values().enumerate() {\n        let idx = zero_idx + 1;\n        result[idx] = edges\n            .iter()\n            .map(|x| ordering.binary_search(x).unwrap() + 1)\n            .collect();\n    }\n    result\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    fn add_edge<V: Ord + Clone>(graph: &mut Graph<V>, a: V, b: V) {\n        graph.entry(a.clone()).or_default().push(b.clone());\n        graph.entry(b).or_default().push(a);\n    }\n\n    #[test]\n    fn string_vertices() {\n        let mut graph = Graph::new();\n        add_edge(&mut graph, \"a\", \"b\");\n        add_edge(&mut graph, \"b\", \"c\");\n        add_edge(&mut graph, \"c\", \"a\");\n        add_edge(&mut graph, \"b\", \"d\");\n        let mut result = enumerate_graph(&graph);\n        let expected = vec![vec![], vec![2, 3], vec![1, 3, 4], vec![1, 2], vec![2]];\n\n        for v in result.iter_mut() {\n            v.sort_unstable();\n        }\n        assert_eq!(result, expected);\n    }\n\n    #[test]\n    fn integer_vertices() {\n        let mut graph = Graph::new();\n        add_edge(&mut graph, 1001, 1002);\n        add_edge(&mut graph, 1002, 1003);\n        add_edge(&mut graph, 1003, 1001);\n        add_edge(&mut graph, 1004, 1002);\n        let mut result = enumerate_graph(&graph);\n        let expected = vec![vec![], vec![2, 3], vec![1, 3, 4], vec![1, 2], vec![2]];\n\n        for v in result.iter_mut() {\n            v.sort_unstable();\n        }\n        assert_eq!(result, expected);\n    }\n}\n"
  },
  {
    "path": "src/graph/heavy_light_decomposition.rs",
    "content": "/*\nHeavy Light Decomposition:\nIt partitions a tree into disjoint paths such that:\n1. Each path is a part of some leaf's path to root\n2. The number of paths from any vertex to the root is of O(lg(n))\nSuch a decomposition can be used to answer many types of queries about vertices\nor edges on a particular path. It is often used with some sort of binary tree\nto handle different operations on the paths, for example segment tree or\nfenwick tree.\n\nMany members of this struct are made public, because they can either be\nsupplied by the developer, or can be useful for other parts of the code.\n\nThe implementation assumes that the tree vertices are numbered from 1 to n\nand it is represented using (compressed) adjacency matrix. If this is not true,\nmaybe `graph_enumeration.rs` can help.\n*/\n\ntype Adj = [Vec<usize>];\n\npub struct HeavyLightDecomposition {\n    // Each vertex is assigned a number from 1 to n. For `v` and `u` such that\n    // u is parent of v, and both are in path `p`, it is true that:\n    // position[u] = position[v] - 1\n    pub position: Vec<usize>,\n\n    // The first (closest to root) vertex of the path containing each vertex\n    pub head: Vec<usize>,\n\n    // The \"heaviest\" child of each vertex, its subtree is at least as big as\n    // the other ones. If `v` is a leaf, big_child[v] = 0\n    pub big_child: Vec<usize>,\n\n    // Used internally to fill `position` Vec\n    current_position: usize,\n}\n\nimpl HeavyLightDecomposition {\n    pub fn new(mut num_vertices: usize) -> Self {\n        num_vertices += 1;\n        HeavyLightDecomposition {\n            position: vec![0; num_vertices],\n            head: vec![0; num_vertices],\n            big_child: vec![0; num_vertices],\n            current_position: 1,\n        }\n    }\n    fn dfs(&mut self, v: usize, parent: usize, adj: &Adj) -> usize {\n        let mut big_child = 0usize;\n        let mut bc_size = 0usize; // big child size\n        let mut subtree_size = 1usize; // size of this subtree\n        for &u in adj[v].iter() {\n            if u == parent {\n                continue;\n            }\n            let u_size = self.dfs(u, v, adj);\n            subtree_size += u_size;\n            if u_size > bc_size {\n                big_child = u;\n                bc_size = u_size;\n            }\n        }\n        self.big_child[v] = big_child;\n        subtree_size\n    }\n    pub fn decompose(&mut self, root: usize, adj: &Adj) {\n        self.current_position = 1;\n        self.dfs(root, 0, adj);\n        self.decompose_path(root, 0, root, adj);\n    }\n    fn decompose_path(&mut self, v: usize, parent: usize, head: usize, adj: &Adj) {\n        self.head[v] = head;\n        self.position[v] = self.current_position;\n        self.current_position += 1;\n        let bc = self.big_child[v];\n        if bc != 0 {\n            // Continue this path\n            self.decompose_path(bc, v, head, adj);\n        }\n        for &u in adj[v].iter() {\n            if u == parent || u == bc {\n                continue;\n            }\n            // Start a new path\n            self.decompose_path(u, v, u, adj);\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    struct LinearCongruenceGenerator {\n        // modulus as 2 ^ 32\n        multiplier: u32,\n        increment: u32,\n        state: u32,\n    }\n\n    impl LinearCongruenceGenerator {\n        fn new(multiplier: u32, increment: u32, state: u32) -> Self {\n            Self {\n                multiplier,\n                increment,\n                state,\n            }\n        }\n        fn next(&mut self) -> u32 {\n            self.state =\n                (self.multiplier as u64 * self.state as u64 + self.increment as u64) as u32;\n            self.state\n        }\n    }\n\n    fn get_num_paths(\n        hld: &HeavyLightDecomposition,\n        mut v: usize,\n        parent: &[usize],\n    ) -> (usize, usize) {\n        // Return height and number of paths\n        let mut ans = 0usize;\n        let mut height = 0usize;\n        let mut prev_head = 0usize;\n        loop {\n            height += 1;\n            let head = hld.head[v];\n            if head != prev_head {\n                ans += 1;\n                prev_head = head;\n            }\n            v = parent[v];\n            if v == 0 {\n                break;\n            }\n        }\n        (ans, height)\n    }\n\n    #[test]\n    fn single_path() {\n        let mut adj = vec![vec![], vec![2], vec![3], vec![4], vec![5], vec![6], vec![]];\n        let mut hld = HeavyLightDecomposition::new(6);\n        hld.decompose(1, &adj);\n        assert_eq!(hld.head, vec![0, 1, 1, 1, 1, 1, 1]);\n        assert_eq!(hld.position, vec![0, 1, 2, 3, 4, 5, 6]);\n        assert_eq!(hld.big_child, vec![0, 2, 3, 4, 5, 6, 0]);\n\n        adj[3].push(2);\n        adj[2].push(1);\n        hld.decompose(3, &adj);\n        assert_eq!(hld.head, vec![0, 2, 2, 3, 3, 3, 3]);\n        assert_eq!(hld.position, vec![0, 6, 5, 1, 2, 3, 4]);\n        assert_eq!(hld.big_child, vec![0, 0, 1, 4, 5, 6, 0]);\n    }\n\n    #[test]\n    fn random_tree() {\n        // Let it have 1e4 vertices. It should finish under 100ms even with\n        // 1e5 vertices\n        let n = 1e4 as usize;\n        let threshold = 14; // 2 ^ 14 = 16384 > n\n        let mut adj: Vec<Vec<usize>> = vec![vec![]; n + 1];\n        let mut parent: Vec<usize> = vec![0; n + 1];\n        let mut hld = HeavyLightDecomposition::new(n);\n        let mut lcg = LinearCongruenceGenerator::new(1103515245, 12345, 314);\n        parent[2] = 1;\n        adj[1].push(2);\n        #[allow(clippy::needless_range_loop)]\n        for i in 3..=n {\n            // randomly determine the parent of each vertex.\n            // There will be modulus bias, but it isn't important\n            let par_max = i - 1;\n            let par_min = (10 * par_max + 1) / 11;\n            // Bring par_min closer to par_max to increase expected tree height\n            let par = (lcg.next() as usize % (par_max - par_min + 1)) + par_min;\n            adj[par].push(i);\n            parent[i] = par;\n        }\n        // let's get a few leaves\n        let leaves: Vec<usize> = (1..=n)\n            .rev()\n            .filter(|&v| adj[v].is_empty())\n            .take(100)\n            .collect();\n        hld.decompose(1, &adj);\n        for l in leaves {\n            let (p, _h) = get_num_paths(&hld, l, &parent);\n            assert!(p <= threshold);\n        }\n    }\n}\n"
  },
  {
    "path": "src/graph/kosaraju.rs",
    "content": "// Kosaraju algorithm, a linear-time algorithm to find the strongly connected components (SCCs) of a directed graph, in Rust.\npub struct Graph {\n    vertices: usize,\n    adj_list: Vec<Vec<usize>>,\n    transpose_adj_list: Vec<Vec<usize>>,\n}\n\nimpl Graph {\n    pub fn new(vertices: usize) -> Self {\n        Graph {\n            vertices,\n            adj_list: vec![vec![]; vertices],\n            transpose_adj_list: vec![vec![]; vertices],\n        }\n    }\n\n    pub fn add_edge(&mut self, u: usize, v: usize) {\n        self.adj_list[u].push(v);\n        self.transpose_adj_list[v].push(u);\n    }\n\n    pub fn dfs(&self, node: usize, visited: &mut Vec<bool>, stack: &mut Vec<usize>) {\n        visited[node] = true;\n        for &neighbor in &self.adj_list[node] {\n            if !visited[neighbor] {\n                self.dfs(neighbor, visited, stack);\n            }\n        }\n        stack.push(node);\n    }\n\n    pub fn dfs_scc(&self, node: usize, visited: &mut Vec<bool>, scc: &mut Vec<usize>) {\n        visited[node] = true;\n        scc.push(node);\n        for &neighbor in &self.transpose_adj_list[node] {\n            if !visited[neighbor] {\n                self.dfs_scc(neighbor, visited, scc);\n            }\n        }\n    }\n}\n\npub fn kosaraju(graph: &Graph) -> Vec<Vec<usize>> {\n    let mut visited = vec![false; graph.vertices];\n    let mut stack = Vec::new();\n\n    for i in 0..graph.vertices {\n        if !visited[i] {\n            graph.dfs(i, &mut visited, &mut stack);\n        }\n    }\n\n    let mut sccs = Vec::new();\n    visited = vec![false; graph.vertices];\n\n    while let Some(node) = stack.pop() {\n        if !visited[node] {\n            let mut scc = Vec::new();\n            graph.dfs_scc(node, &mut visited, &mut scc);\n            sccs.push(scc);\n        }\n    }\n\n    sccs\n}\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_kosaraju_single_sccs() {\n        let vertices = 5;\n        let mut graph = Graph::new(vertices);\n\n        graph.add_edge(0, 1);\n        graph.add_edge(1, 2);\n        graph.add_edge(2, 3);\n        graph.add_edge(2, 4);\n        graph.add_edge(3, 0);\n        graph.add_edge(4, 2);\n\n        let sccs = kosaraju(&graph);\n        assert_eq!(sccs.len(), 1);\n        assert!(sccs.contains(&vec![0, 3, 2, 1, 4]));\n    }\n\n    #[test]\n    fn test_kosaraju_multiple_sccs() {\n        let vertices = 8;\n        let mut graph = Graph::new(vertices);\n\n        graph.add_edge(1, 0);\n        graph.add_edge(0, 1);\n        graph.add_edge(1, 2);\n        graph.add_edge(2, 0);\n        graph.add_edge(2, 3);\n        graph.add_edge(3, 4);\n        graph.add_edge(4, 5);\n        graph.add_edge(5, 6);\n        graph.add_edge(6, 7);\n        graph.add_edge(4, 7);\n        graph.add_edge(6, 4);\n\n        let sccs = kosaraju(&graph);\n        assert_eq!(sccs.len(), 4);\n        assert!(sccs.contains(&vec![0, 1, 2]));\n        assert!(sccs.contains(&vec![3]));\n        assert!(sccs.contains(&vec![4, 6, 5]));\n        assert!(sccs.contains(&vec![7]));\n    }\n\n    #[test]\n    fn test_kosaraju_multiple_sccs1() {\n        let vertices = 8;\n        let mut graph = Graph::new(vertices);\n        graph.add_edge(0, 2);\n        graph.add_edge(1, 0);\n        graph.add_edge(2, 3);\n        graph.add_edge(3, 4);\n        graph.add_edge(4, 7);\n        graph.add_edge(5, 2);\n        graph.add_edge(5, 6);\n        graph.add_edge(6, 5);\n        graph.add_edge(7, 6);\n\n        let sccs = kosaraju(&graph);\n        assert_eq!(sccs.len(), 3);\n        assert!(sccs.contains(&vec![0]));\n        assert!(sccs.contains(&vec![1]));\n        assert!(sccs.contains(&vec![2, 5, 6, 7, 4, 3]));\n    }\n\n    #[test]\n    fn test_kosaraju_no_scc() {\n        let vertices = 4;\n        let mut graph = Graph::new(vertices);\n\n        graph.add_edge(0, 1);\n        graph.add_edge(1, 2);\n        graph.add_edge(2, 3);\n\n        let sccs = kosaraju(&graph);\n        assert_eq!(sccs.len(), 4);\n        for (i, _) in sccs.iter().enumerate().take(vertices) {\n            assert_eq!(sccs[i], vec![i]);\n        }\n    }\n\n    #[test]\n    fn test_kosaraju_empty_graph() {\n        let vertices = 0;\n        let graph = Graph::new(vertices);\n\n        let sccs = kosaraju(&graph);\n        assert_eq!(sccs.len(), 0);\n    }\n}\n"
  },
  {
    "path": "src/graph/lee_breadth_first_search.rs",
    "content": "use std::collections::VecDeque;\n\n// All four potential movements from a cell are listed here.\n\nfn validate(matrix: &[Vec<i32>], visited: &[Vec<bool>], row: isize, col: isize) -> bool {\n    // Check if it is possible to move to the position (row, col) from the current cell.\n    let (row, col) = (row as usize, col as usize);\n    row < matrix.len() && col < matrix[0].len() && matrix[row][col] == 1 && !visited[row][col]\n}\n\npub fn lee(matrix: Vec<Vec<i32>>, source: (usize, usize), destination: (usize, usize)) -> isize {\n    const ROW: [isize; 4] = [-1, 0, 0, 1];\n    const COL: [isize; 4] = [0, -1, 1, 0];\n    let (i, j) = source;\n    let (x, y) = destination;\n\n    // Base case: invalid input\n    if matrix.is_empty() || matrix[i][j] == 0 || matrix[x][y] == 0 {\n        return -1;\n    }\n\n    let (m, n) = (matrix.len(), matrix[0].len());\n    let mut visited = vec![vec![false; n]; m];\n    let mut q = VecDeque::new();\n    visited[i][j] = true;\n    q.push_back((i, j, 0));\n    let mut min_dist = isize::MAX;\n\n    // Loop until the queue is empty\n    while let Some((i, j, dist)) = q.pop_front() {\n        if i == x && j == y {\n            // If the destination is found, update `min_dist` and stop\n            min_dist = dist;\n            break;\n        }\n\n        // Check for all four possible movements from the current cell\n        for k in 0..ROW.len() {\n            let row = i as isize + ROW[k];\n            let col = j as isize + COL[k];\n            if validate(&matrix, &visited, row, col) {\n                // Mark the next cell as visited and enqueue it\n                let (row, col) = (row as usize, col as usize);\n                visited[row][col] = true;\n                q.push_back((row, col, dist + 1));\n            }\n        }\n    }\n\n    if min_dist == isize::MAX {\n        -1\n    } else {\n        min_dist\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn test_lee_exists() {\n        let mat: Vec<Vec<i32>> = vec![\n            vec![1, 0, 1, 1, 1],\n            vec![1, 0, 1, 0, 1],\n            vec![1, 1, 1, 0, 1],\n            vec![0, 0, 0, 0, 1],\n            vec![1, 1, 1, 0, 1],\n        ];\n        let source = (0, 0);\n        let dest = (2, 1);\n        assert_eq!(lee(mat, source, dest), 3);\n    }\n\n    #[test]\n    fn test_lee_does_not_exist() {\n        let mat: Vec<Vec<i32>> = vec![\n            vec![1, 0, 1, 1, 1],\n            vec![1, 0, 0, 0, 1],\n            vec![1, 1, 1, 0, 1],\n            vec![0, 0, 0, 0, 1],\n            vec![1, 1, 1, 0, 1],\n        ];\n        let source = (0, 0);\n        let dest = (3, 4);\n        assert_eq!(lee(mat, source, dest), -1);\n    }\n\n    #[test]\n    fn test_source_equals_destination() {\n        let mat: Vec<Vec<i32>> = vec![\n            vec![1, 0, 1, 1, 1],\n            vec![1, 0, 1, 0, 1],\n            vec![1, 1, 1, 0, 1],\n            vec![0, 0, 0, 0, 1],\n            vec![1, 1, 1, 0, 1],\n        ];\n        let source = (2, 1);\n        let dest = (2, 1);\n        assert_eq!(lee(mat, source, dest), 0);\n    }\n\n    #[test]\n    fn test_lee_exists_2() {\n        let mat: Vec<Vec<i32>> = vec![\n            vec![1, 1, 1, 1, 1, 0, 0],\n            vec![1, 1, 1, 1, 1, 1, 0],\n            vec![1, 0, 1, 0, 1, 1, 1],\n            vec![1, 1, 1, 1, 1, 0, 1],\n            vec![0, 0, 0, 1, 0, 0, 0],\n            vec![1, 0, 1, 1, 1, 0, 0],\n            vec![0, 0, 0, 0, 1, 0, 0],\n        ];\n        let source = (0, 0);\n        let dest = (3, 2);\n        assert_eq!(lee(mat, source, dest), 5);\n    }\n}\n"
  },
  {
    "path": "src/graph/lowest_common_ancestor.rs",
    "content": "/*\n Note: We will assume that here tree vertices are numbered from 1 to n.\nIf a tree is not enumerated that way or its vertices are not represented\nusing numbers, it can trivially be converted using Depth First Search\nmanually or by using `src/graph/graph_enumeration.rs`\n\n Here we implement two different algorithms:\n- The online one is implemented using Sparse Table and has O(n.lg(n))\ntime complexity and memory usage. It answers each query in O(lg(n)).\n- The offline algorithm was discovered by Robert Tarjan. At first each\nquery should be determined and saved. Then, vertices are visited in\nDepth First Search order and queries are answered using Disjoint\nSet Union algorithm. The time complexity is O(n.alpha(n) + q) and\nmemory usage is O(n + q), but time complexity can be considered to be O(n + q),\nbecause alpha(n) < 5 for n < 10 ^ 600\n */\n\nuse super::DisjointSetUnion;\npub struct LowestCommonAncestorOnline {\n    // Make members public to allow the user to fill them themself.\n    pub parents_sparse_table: Vec<Vec<usize>>,\n    pub height: Vec<usize>,\n}\n\nimpl LowestCommonAncestorOnline {\n    // Should be called once as:\n    // fill_sparse_table(tree_root, 0, 0, adjacency_list)\n    #[inline]\n    fn get_parent(&self, v: usize, i: usize) -> usize {\n        self.parents_sparse_table[v][i]\n    }\n    #[inline]\n    fn num_parents(&self, v: usize) -> usize {\n        self.parents_sparse_table[v].len()\n    }\n    pub fn new(num_vertices: usize) -> Self {\n        let mut pars = vec![vec![0]; num_vertices + 1];\n        pars[0].clear();\n        LowestCommonAncestorOnline {\n            parents_sparse_table: pars,\n            height: vec![0; num_vertices + 1],\n        }\n    }\n    pub fn fill_sparse_table(\n        &mut self,\n        vertex: usize,\n        parent: usize,\n        height: usize,\n        adj: &[Vec<usize>],\n    ) {\n        self.parents_sparse_table[vertex][0] = parent;\n        self.height[vertex] = height;\n        let mut level = 1;\n        let mut current_parent = parent;\n        while self.num_parents(current_parent) >= level {\n            current_parent = self.get_parent(current_parent, level - 1);\n            level += 1;\n            self.parents_sparse_table[vertex].push(current_parent);\n        }\n        for &child in adj[vertex].iter() {\n            if child == parent {\n                // It isn't a child!\n                continue;\n            }\n            self.fill_sparse_table(child, vertex, height + 1, adj);\n        }\n    }\n\n    pub fn get_ancestor(&self, mut v: usize, mut u: usize) -> usize {\n        if self.height[v] < self.height[u] {\n            std::mem::swap(&mut v, &mut u);\n        }\n        // Bring v up to so that it has the same height as u\n        let height_diff = self.height[v] - self.height[u];\n        for i in 0..63 {\n            let bit = 1 << i;\n            if bit > height_diff {\n                break;\n            }\n            if height_diff & bit != 0 {\n                v = self.get_parent(v, i);\n            }\n        }\n        if u == v {\n            return u;\n        }\n        // `self.num_parents` of u and v should be equal\n        for i in (0..self.num_parents(v)).rev() {\n            let nv = self.get_parent(v, i);\n            let nu = self.get_parent(u, i);\n            if nv != nu {\n                u = nu;\n                v = nv;\n            }\n        }\n        self.get_parent(v, 0)\n    }\n}\n\n#[derive(Clone, Copy)]\npub struct LCAQuery {\n    other: usize,\n    query_id: usize,\n}\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub struct QueryAnswer {\n    query_id: usize,\n    answer: usize,\n}\n\npub struct LowestCommonAncestorOffline {\n    pub queries: Vec<Vec<LCAQuery>>,\n    dsu: DisjointSetUnion,\n    /*\n    The LSB of dsu_parent[v] determines whether it was visited or not.\n    The rest of the number determines the vertex that represents a\n    particular set in DSU.\n    */\n    dsu_parent: Vec<u64>,\n}\n\nimpl LowestCommonAncestorOffline {\n    pub fn new(num_vertices: usize) -> Self {\n        LowestCommonAncestorOffline {\n            queries: vec![vec![]; num_vertices + 1],\n            dsu: DisjointSetUnion::new(num_vertices),\n            dsu_parent: vec![0; num_vertices + 1],\n        }\n    }\n    pub fn add_query(&mut self, u: usize, v: usize, query_id: usize) {\n        // We should add this query to both vertices, and it will be answered\n        // the second time it is seen in DFS.\n        self.queries[u].push(LCAQuery { other: v, query_id });\n        if u == v {\n            return;\n        }\n        self.queries[v].push(LCAQuery { other: u, query_id });\n    }\n\n    fn calculate_answers(\n        &mut self,\n        vertex: usize,\n        parent: usize,\n        adj: &[Vec<usize>],\n        answers: &mut Vec<QueryAnswer>,\n    ) {\n        self.dsu_parent[vertex] = (vertex as u64) << 1;\n        for &child in adj[vertex].iter() {\n            if child == parent {\n                continue;\n            }\n            self.calculate_answers(child, vertex, adj, answers);\n            self.dsu.merge(child, vertex);\n            let set = self.dsu.find_set(vertex);\n            self.dsu_parent[set] = ((vertex as u64) << 1) | (self.dsu_parent[set] & 1);\n        }\n        self.dsu_parent[vertex] |= 0b1;\n        for &query in self.queries[vertex].iter() {\n            if self.dsu_parent[query.other] & 1 != 0 {\n                // It has been visited\n                answers.push(QueryAnswer {\n                    query_id: query.query_id,\n                    answer: (self.dsu_parent[self.dsu.find_set(query.other)] >> 1) as usize,\n                });\n            }\n        }\n    }\n    pub fn answer_queries(&mut self, root: usize, adj: &[Vec<usize>]) -> Vec<QueryAnswer> {\n        let mut answers = Vec::new();\n        self.calculate_answers(root, 0, adj, &mut answers);\n        answers\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn small_binary_tree() {\n        let num_verts = 127;\n        let mut tree: Vec<Vec<usize>> = vec![vec![]; num_verts + 1];\n        for i in 1..=num_verts >> 1 {\n            let left_child = i << 1;\n            let right_child = left_child + 1;\n            tree[i].push(left_child);\n            tree[i].push(right_child);\n            tree[left_child].push(i);\n            tree[right_child].push(i);\n        }\n        let mut online_answers: Vec<QueryAnswer> = Vec::new();\n        let mut online = LowestCommonAncestorOnline::new(num_verts);\n        let mut offline = LowestCommonAncestorOffline::new(num_verts);\n        let mut query_id = 314; // A random number, doesn't matter\n        online.fill_sparse_table(1, 0, 0, &tree);\n        for i in 1..=num_verts {\n            for j in 1..i {\n                // Query every possible pair\n                online_answers.push(QueryAnswer {\n                    query_id,\n                    answer: online.get_ancestor(i, j),\n                });\n                offline.add_query(i, j, query_id);\n                query_id += 1;\n            }\n        }\n        let mut offline_answers = offline.answer_queries(1, &tree);\n        offline_answers.sort_unstable_by(|a1, a2| a1.query_id.cmp(&a2.query_id));\n        assert_eq!(offline_answers, online_answers);\n    }\n}\n"
  },
  {
    "path": "src/graph/minimum_spanning_tree.rs",
    "content": "//! This module implements Kruskal's algorithm to find the Minimum Spanning Tree (MST)\n//! of an undirected, weighted graph using a Disjoint Set Union (DSU) for cycle detection.\n\nuse crate::graph::DisjointSetUnion;\n\n/// Represents an edge in the graph with a source, destination, and associated cost.\n#[derive(Debug, PartialEq, Eq)]\npub struct Edge {\n    /// The starting vertex of the edge.\n    source: usize,\n    /// The ending vertex of the edge.\n    destination: usize,\n    /// The cost associated with the edge.\n    cost: usize,\n}\n\nimpl Edge {\n    /// Creates a new edge with the specified source, destination, and cost.\n    pub fn new(source: usize, destination: usize, cost: usize) -> Self {\n        Self {\n            source,\n            destination,\n            cost,\n        }\n    }\n}\n\n/// Executes Kruskal's algorithm to compute the Minimum Spanning Tree (MST) of a graph.\n///\n/// # Parameters\n///\n/// - `edges`: A vector of `Edge` instances representing all edges in the graph.\n/// - `num_vertices`: The total number of vertices in the graph.\n///\n/// # Returns\n///\n/// An `Option` containing a tuple with:\n///\n/// - The total cost of the MST (usize).\n/// - A vector of edges that are included in the MST.\n///\n/// Returns `None` if the graph is disconnected.\n///\n/// # Complexity\n///\n/// The time complexity is O(E log E), where E is the number of edges.\npub fn kruskal(mut edges: Vec<Edge>, num_vertices: usize) -> Option<(usize, Vec<Edge>)> {\n    let mut dsu = DisjointSetUnion::new(num_vertices);\n    let mut mst_cost: usize = 0;\n    let mut mst_edges: Vec<Edge> = Vec::with_capacity(num_vertices - 1);\n\n    // Sort edges by cost in ascending order\n    edges.sort_unstable_by_key(|edge| edge.cost);\n\n    for edge in edges {\n        if mst_edges.len() == num_vertices - 1 {\n            break;\n        }\n\n        // Attempt to merge the sets containing the edge’s vertices\n        if dsu.merge(edge.source, edge.destination) != usize::MAX {\n            mst_cost += edge.cost;\n            mst_edges.push(edge);\n        }\n    }\n\n    // Return MST if it includes exactly num_vertices - 1 edges, otherwise None for disconnected graphs\n    (mst_edges.len() == num_vertices - 1).then_some((mst_cost, mst_edges))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_cases {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (edges, num_vertices, expected_result) = $test_case;\n                    let actual_result = kruskal(edges, num_vertices);\n                    assert_eq!(actual_result, expected_result);\n                }\n            )*\n        };\n    }\n\n    test_cases! {\n        test_seven_vertices_eleven_edges: (\n            vec![\n                Edge::new(0, 1, 7),\n                Edge::new(0, 3, 5),\n                Edge::new(1, 2, 8),\n                Edge::new(1, 3, 9),\n                Edge::new(1, 4, 7),\n                Edge::new(2, 4, 5),\n                Edge::new(3, 4, 15),\n                Edge::new(3, 5, 6),\n                Edge::new(4, 5, 8),\n                Edge::new(4, 6, 9),\n                Edge::new(5, 6, 11),\n            ],\n            7,\n            Some((39, vec![\n                Edge::new(0, 3, 5),\n                Edge::new(2, 4, 5),\n                Edge::new(3, 5, 6),\n                Edge::new(0, 1, 7),\n                Edge::new(1, 4, 7),\n                Edge::new(4, 6, 9),\n            ]))\n        ),\n        test_ten_vertices_twenty_edges: (\n            vec![\n                Edge::new(0, 1, 3),\n                Edge::new(0, 3, 6),\n                Edge::new(0, 4, 9),\n                Edge::new(1, 2, 2),\n                Edge::new(1, 3, 4),\n                Edge::new(1, 4, 9),\n                Edge::new(2, 3, 2),\n                Edge::new(2, 5, 8),\n                Edge::new(2, 6, 9),\n                Edge::new(3, 6, 9),\n                Edge::new(4, 5, 8),\n                Edge::new(4, 9, 18),\n                Edge::new(5, 6, 7),\n                Edge::new(5, 8, 9),\n                Edge::new(5, 9, 10),\n                Edge::new(6, 7, 4),\n                Edge::new(6, 8, 5),\n                Edge::new(7, 8, 1),\n                Edge::new(7, 9, 4),\n                Edge::new(8, 9, 3),\n            ],\n            10,\n            Some((38, vec![\n                Edge::new(7, 8, 1),\n                Edge::new(1, 2, 2),\n                Edge::new(2, 3, 2),\n                Edge::new(0, 1, 3),\n                Edge::new(8, 9, 3),\n                Edge::new(6, 7, 4),\n                Edge::new(5, 6, 7),\n                Edge::new(2, 5, 8),\n                Edge::new(4, 5, 8),\n            ]))\n        ),\n        test_disconnected_graph: (\n            vec![\n                Edge::new(0, 1, 4),\n                Edge::new(0, 2, 6),\n                Edge::new(3, 4, 2),\n            ],\n            5,\n            None\n        ),\n    }\n}\n"
  },
  {
    "path": "src/graph/mod.rs",
    "content": "mod ant_colony_optimization;\nmod astar;\nmod bellman_ford;\nmod bipartite_matching;\nmod breadth_first_search;\nmod centroid_decomposition;\nmod decremental_connectivity;\nmod depth_first_search;\nmod depth_first_search_tic_tac_toe;\nmod detect_cycle;\nmod dijkstra;\nmod dinic_maxflow;\nmod disjoint_set_union;\nmod eulerian_path;\nmod floyd_warshall;\nmod ford_fulkerson;\nmod graph_enumeration;\nmod heavy_light_decomposition;\nmod kosaraju;\nmod lee_breadth_first_search;\nmod lowest_common_ancestor;\nmod minimum_spanning_tree;\nmod prim;\nmod prufer_code;\nmod strongly_connected_components;\nmod tarjans_ssc;\nmod topological_sort;\nmod two_satisfiability;\n\npub use self::ant_colony_optimization::ant_colony_optimization;\npub use self::astar::astar;\npub use self::bellman_ford::bellman_ford;\npub use self::bipartite_matching::BipartiteMatching;\npub use self::breadth_first_search::breadth_first_search;\npub use self::centroid_decomposition::CentroidDecomposition;\npub use self::decremental_connectivity::DecrementalConnectivity;\npub use self::depth_first_search::depth_first_search;\npub use self::depth_first_search_tic_tac_toe::minimax;\npub use self::detect_cycle::DetectCycle;\npub use self::dijkstra::dijkstra;\npub use self::dinic_maxflow::DinicMaxFlow;\npub use self::disjoint_set_union::DisjointSetUnion;\npub use self::eulerian_path::find_eulerian_path;\npub use self::floyd_warshall::floyd_warshall;\npub use self::ford_fulkerson::ford_fulkerson;\npub use self::graph_enumeration::enumerate_graph;\npub use self::heavy_light_decomposition::HeavyLightDecomposition;\npub use self::kosaraju::kosaraju;\npub use self::lee_breadth_first_search::lee;\npub use self::lowest_common_ancestor::{LowestCommonAncestorOffline, LowestCommonAncestorOnline};\npub use self::minimum_spanning_tree::kruskal;\npub use self::prim::{prim, prim_with_start};\npub use self::prufer_code::{prufer_decode, prufer_encode};\npub use self::strongly_connected_components::StronglyConnectedComponents;\npub use self::tarjans_ssc::tarjan_scc;\npub use self::topological_sort::topological_sort;\npub use self::two_satisfiability::solve_two_satisfiability;\n"
  },
  {
    "path": "src/graph/prim.rs",
    "content": "use std::cmp::Reverse;\nuse std::collections::{BTreeMap, BinaryHeap};\nuse std::ops::Add;\n\ntype Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;\n\nfn add_edge<V: Ord + Copy, E: Ord + Add + Copy>(graph: &mut Graph<V, E>, v1: V, v2: V, c: E) {\n    graph.entry(v1).or_default().insert(v2, c);\n    graph.entry(v2).or_default().insert(v1, c);\n}\n\n// selects a start and run the algorithm from it\npub fn prim<V: Ord + Copy + std::fmt::Debug, E: Ord + Add + Copy + std::fmt::Debug>(\n    graph: &Graph<V, E>,\n) -> Graph<V, E> {\n    match graph.keys().next() {\n        Some(v) => prim_with_start(graph, *v),\n        None => BTreeMap::new(),\n    }\n}\n\n// only works for a connected graph\n// if the given graph is not connected it will return the MST of the connected subgraph\npub fn prim_with_start<V: Ord + Copy, E: Ord + Add + Copy>(\n    graph: &Graph<V, E>,\n    start: V,\n) -> Graph<V, E> {\n    // will contain the MST\n    let mut mst: Graph<V, E> = Graph::new();\n    // a priority queue based on a binary heap, used to get the cheapest edge\n    // the elements are an edge: the cost, destination and source\n    let mut prio = BinaryHeap::new();\n\n    mst.insert(start, BTreeMap::new());\n\n    for (v, c) in &graph[&start] {\n        // the heap is a max heap, we have to use Reverse when adding to simulate a min heap\n        prio.push(Reverse((*c, v, start)));\n    }\n\n    while let Some(Reverse((dist, t, prev))) = prio.pop() {\n        // the destination of the edge has already been seen\n        if mst.contains_key(t) {\n            continue;\n        }\n\n        // the destination is a new vertex\n        add_edge(&mut mst, prev, *t, dist);\n\n        for (v, c) in &graph[t] {\n            if !mst.contains_key(v) {\n                prio.push(Reverse((*c, v, *t)));\n            }\n        }\n    }\n\n    mst\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{add_edge, prim, Graph};\n    use std::collections::BTreeMap;\n\n    #[test]\n    fn empty() {\n        assert_eq!(prim::<usize, usize>(&BTreeMap::new()), BTreeMap::new());\n    }\n\n    #[test]\n    fn single_vertex() {\n        let mut graph: Graph<usize, usize> = BTreeMap::new();\n        graph.insert(42, BTreeMap::new());\n\n        assert_eq!(prim(&graph), graph);\n    }\n\n    #[test]\n    fn single_edge() {\n        let mut graph = BTreeMap::new();\n\n        add_edge(&mut graph, 42, 666, 12);\n\n        assert_eq!(prim(&graph), graph);\n    }\n\n    #[test]\n    fn tree_1() {\n        let mut graph = BTreeMap::new();\n\n        add_edge(&mut graph, 0, 1, 10);\n        add_edge(&mut graph, 0, 2, 11);\n        add_edge(&mut graph, 2, 3, 12);\n        add_edge(&mut graph, 2, 4, 13);\n        add_edge(&mut graph, 1, 5, 14);\n        add_edge(&mut graph, 1, 6, 15);\n        add_edge(&mut graph, 3, 7, 16);\n\n        assert_eq!(prim(&graph), graph);\n    }\n\n    #[test]\n    fn tree_2() {\n        let mut graph = BTreeMap::new();\n\n        add_edge(&mut graph, 1, 2, 11);\n        add_edge(&mut graph, 2, 3, 12);\n        add_edge(&mut graph, 2, 4, 13);\n        add_edge(&mut graph, 4, 5, 14);\n        add_edge(&mut graph, 4, 6, 15);\n        add_edge(&mut graph, 6, 7, 16);\n\n        assert_eq!(prim(&graph), graph);\n    }\n\n    #[test]\n    fn tree_3() {\n        let mut graph = BTreeMap::new();\n\n        for i in 1..100 {\n            add_edge(&mut graph, i, 2 * i, i);\n            add_edge(&mut graph, i, 2 * i + 1, -i);\n        }\n\n        assert_eq!(prim(&graph), graph);\n    }\n\n    #[test]\n    fn graph_1() {\n        let mut graph = BTreeMap::new();\n        add_edge(&mut graph, 'a', 'b', 6);\n        add_edge(&mut graph, 'a', 'c', 7);\n        add_edge(&mut graph, 'a', 'e', 2);\n        add_edge(&mut graph, 'a', 'f', 3);\n        add_edge(&mut graph, 'b', 'c', 5);\n        add_edge(&mut graph, 'c', 'e', 5);\n        add_edge(&mut graph, 'd', 'e', 4);\n        add_edge(&mut graph, 'd', 'f', 1);\n        add_edge(&mut graph, 'e', 'f', 2);\n\n        let mut ans = BTreeMap::new();\n        add_edge(&mut ans, 'd', 'f', 1);\n        add_edge(&mut ans, 'e', 'f', 2);\n        add_edge(&mut ans, 'a', 'e', 2);\n        add_edge(&mut ans, 'b', 'c', 5);\n        add_edge(&mut ans, 'c', 'e', 5);\n\n        assert_eq!(prim(&graph), ans);\n    }\n\n    #[test]\n    fn graph_2() {\n        let mut graph = BTreeMap::new();\n        add_edge(&mut graph, 1, 2, 6);\n        add_edge(&mut graph, 1, 3, 1);\n        add_edge(&mut graph, 1, 4, 5);\n        add_edge(&mut graph, 2, 3, 5);\n        add_edge(&mut graph, 2, 5, 3);\n        add_edge(&mut graph, 3, 4, 5);\n        add_edge(&mut graph, 3, 5, 6);\n        add_edge(&mut graph, 3, 6, 4);\n        add_edge(&mut graph, 4, 6, 2);\n        add_edge(&mut graph, 5, 6, 6);\n\n        let mut ans = BTreeMap::new();\n        add_edge(&mut ans, 1, 3, 1);\n        add_edge(&mut ans, 4, 6, 2);\n        add_edge(&mut ans, 2, 5, 3);\n        add_edge(&mut ans, 2, 3, 5);\n        add_edge(&mut ans, 3, 6, 4);\n\n        assert_eq!(prim(&graph), ans);\n    }\n\n    #[test]\n    fn graph_3() {\n        let mut graph = BTreeMap::new();\n        add_edge(&mut graph, \"v1\", \"v2\", 1);\n        add_edge(&mut graph, \"v1\", \"v3\", 3);\n        add_edge(&mut graph, \"v1\", \"v5\", 6);\n        add_edge(&mut graph, \"v2\", \"v3\", 2);\n        add_edge(&mut graph, \"v2\", \"v4\", 3);\n        add_edge(&mut graph, \"v2\", \"v5\", 5);\n        add_edge(&mut graph, \"v3\", \"v4\", 5);\n        add_edge(&mut graph, \"v3\", \"v6\", 2);\n        add_edge(&mut graph, \"v4\", \"v5\", 2);\n        add_edge(&mut graph, \"v4\", \"v6\", 4);\n        add_edge(&mut graph, \"v5\", \"v6\", 1);\n\n        let mut ans = BTreeMap::new();\n        add_edge(&mut ans, \"v1\", \"v2\", 1);\n        add_edge(&mut ans, \"v5\", \"v6\", 1);\n        add_edge(&mut ans, \"v2\", \"v3\", 2);\n        add_edge(&mut ans, \"v3\", \"v6\", 2);\n        add_edge(&mut ans, \"v4\", \"v5\", 2);\n\n        assert_eq!(prim(&graph), ans);\n    }\n}\n"
  },
  {
    "path": "src/graph/prufer_code.rs",
    "content": "use std::collections::{BTreeMap, BTreeSet, BinaryHeap};\n\ntype Graph<V> = BTreeMap<V, Vec<V>>;\n\npub fn prufer_encode<V: Ord + Copy>(tree: &Graph<V>) -> Vec<V> {\n    if tree.len() <= 2 {\n        return vec![];\n    }\n    let mut result: Vec<V> = Vec::with_capacity(tree.len() - 2);\n    let mut queue = BinaryHeap::new();\n    let mut in_tree = BTreeSet::new();\n    let mut degree = BTreeMap::new();\n    for (vertex, adj) in tree {\n        in_tree.insert(*vertex);\n        degree.insert(*vertex, adj.len());\n        if adj.len() == 1 {\n            queue.push(*vertex);\n        }\n    }\n    for _ in 2..tree.len() {\n        let v = queue.pop().unwrap();\n        in_tree.remove(&v);\n        let u = tree[&v].iter().find(|u| in_tree.contains(u)).unwrap();\n        result.push(*u);\n        *degree.get_mut(u).unwrap() -= 1;\n        if degree[u] == 1 {\n            queue.push(*u);\n        }\n    }\n    result\n}\n\n#[inline]\nfn add_directed_edge<V: Ord + Copy>(tree: &mut Graph<V>, a: V, b: V) {\n    tree.entry(a).or_default().push(b);\n}\n\n#[inline]\nfn add_edge<V: Ord + Copy>(tree: &mut Graph<V>, a: V, b: V) {\n    add_directed_edge(tree, a, b);\n    add_directed_edge(tree, b, a);\n}\n\npub fn prufer_decode<V: Ord + Copy>(code: &[V], vertex_list: &[V]) -> Graph<V> {\n    // For many cases, this function won't fail even if given unsuitable code\n    // array. As such, returning really unlikely errors doesn't make much sense.\n    let mut result = BTreeMap::new();\n    let mut list_count: BTreeMap<V, usize> = BTreeMap::new();\n    for vertex in code {\n        *list_count.entry(*vertex).or_insert(0) += 1;\n    }\n    let mut queue = BinaryHeap::from(\n        vertex_list\n            .iter()\n            .filter(|v| !list_count.contains_key(v))\n            .cloned()\n            .collect::<Vec<V>>(),\n    );\n    for vertex in code {\n        let child = queue.pop().unwrap();\n        add_edge(&mut result, child, *vertex);\n        let cnt = list_count.get_mut(vertex).unwrap();\n        *cnt -= 1;\n        if *cnt == 0 {\n            queue.push(*vertex);\n        }\n    }\n    let u = queue.pop().unwrap();\n    let v = queue.pop().unwrap();\n    add_edge(&mut result, u, v);\n    result\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{add_edge, prufer_decode, prufer_encode, Graph};\n\n    fn equal_graphs<V: Ord + Copy>(g1: &mut Graph<V>, g2: &mut Graph<V>) -> bool {\n        for adj in g1.values_mut() {\n            adj.sort();\n        }\n        for adj in g2.values_mut() {\n            adj.sort();\n        }\n        g1 == g2\n    }\n\n    #[test]\n    fn small_trees() {\n        let mut g: Graph<u32> = Graph::new();\n        // Binary tree with 7 vertices\n        let edges = vec![(1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7)];\n        for (u, v) in edges {\n            add_edge(&mut g, u, v);\n        }\n        let code = prufer_encode(&g);\n        let vertices = g.keys().cloned().collect::<Vec<u32>>();\n        let mut decoded = prufer_decode(&code, &vertices);\n        assert_eq!(code, vec![3, 3, 2, 2, 1]);\n        assert!(equal_graphs(&mut g, &mut decoded));\n\n        g.clear();\n        // A path of length 10\n        for v in 2..=9 {\n            g.insert(v, vec![v - 1, v + 1]);\n        }\n        g.insert(1, vec![2]);\n        g.insert(10, vec![9]);\n        let code = prufer_encode(&g);\n        let vertices = g.keys().cloned().collect::<Vec<u32>>();\n        let mut decoded = prufer_decode(&code, &vertices);\n        assert_eq!(code, vec![9, 8, 7, 6, 5, 4, 3, 2]);\n        assert!(equal_graphs(&mut g, &mut decoded));\n\n        g.clear();\n        // 7-5-3-1-2-4-6\n        let edges = vec![(1, 2), (2, 4), (4, 6), (1, 3), (3, 5), (5, 7)];\n        for (u, v) in edges {\n            add_edge(&mut g, u, v);\n        }\n        let code = prufer_encode(&g);\n        let vertices = g.keys().cloned().collect::<Vec<u32>>();\n        let mut decoded = prufer_decode(&code, &vertices);\n        assert_eq!(code, vec![5, 4, 3, 2, 1]);\n        assert!(equal_graphs(&mut g, &mut decoded));\n    }\n}\n"
  },
  {
    "path": "src/graph/strongly_connected_components.rs",
    "content": "/*\nTarjan's algorithm to find Strongly Connected Components (SCCs):\nIt runs in O(n + m) (so it is optimal) and as a by-product, it returns the\ncomponents in some (reverse) topologically sorted order.\n\nWe assume that graph is represented using (compressed) adjacency matrix\nand its vertices are numbered from 1 to n. If this is not the case, one\ncan use `src/graph/graph_enumeration.rs` to convert their graph.\n*/\n\npub struct StronglyConnectedComponents {\n    // The number of the SCC the vertex is in, starting from 1\n    pub component: Vec<usize>,\n\n    // The discover time of the vertex with minimum discover time reachable\n    // from this vertex. The MSB of the numbers are used to save whether the\n    // vertex has been visited (but the MSBs are cleared after\n    // the algorithm is done)\n    pub state: Vec<u64>,\n\n    // The total number of SCCs\n    pub num_components: usize,\n\n    // The stack of vertices that DFS has seen (used internally)\n    stack: Vec<usize>,\n    // Used internally during DFS to know the current discover time\n    current_time: usize,\n}\n\n// Some functions to help with DRY and code readability\nconst NOT_DONE: u64 = 1 << 63;\n\n#[inline]\nfn set_done(vertex_state: &mut u64) {\n    *vertex_state ^= NOT_DONE;\n}\n\n#[inline]\nfn is_in_stack(vertex_state: u64) -> bool {\n    vertex_state != 0 && (vertex_state & NOT_DONE) != 0\n}\n\n#[inline]\nfn is_unvisited(vertex_state: u64) -> bool {\n    vertex_state == NOT_DONE\n}\n\n#[inline]\nfn get_discover_time(vertex_state: u64) -> u64 {\n    vertex_state ^ NOT_DONE\n}\n\nimpl StronglyConnectedComponents {\n    pub fn new(mut num_vertices: usize) -> Self {\n        num_vertices += 1; // Vertices are numbered from 1, not 0\n        StronglyConnectedComponents {\n            component: vec![0; num_vertices],\n            state: vec![NOT_DONE; num_vertices],\n            num_components: 0,\n            stack: vec![],\n            current_time: 1,\n        }\n    }\n    fn dfs(&mut self, v: usize, adj: &[Vec<usize>]) -> u64 {\n        let mut min_disc = self.current_time as u64;\n        // self.state[v] = NOT_DONE + min_disc\n        self.state[v] ^= min_disc;\n        self.current_time += 1;\n        self.stack.push(v);\n\n        for &u in adj[v].iter() {\n            if is_unvisited(self.state[u]) {\n                min_disc = std::cmp::min(self.dfs(u, adj), min_disc);\n            } else if is_in_stack(self.state[u]) {\n                min_disc = std::cmp::min(get_discover_time(self.state[u]), min_disc);\n            }\n        }\n\n        // No vertex with a lower discovery time is reachable from this one\n        // So it should be \"the head\" of a new SCC.\n        if min_disc == get_discover_time(self.state[v]) {\n            self.num_components += 1;\n            loop {\n                let u = self.stack.pop().unwrap();\n                self.component[u] = self.num_components;\n                set_done(&mut self.state[u]);\n                if u == v {\n                    break;\n                }\n            }\n        }\n\n        min_disc\n    }\n    pub fn find_components(&mut self, adj: &[Vec<usize>]) {\n        self.state[0] = 0;\n        for v in 1..adj.len() {\n            if is_unvisited(self.state[v]) {\n                self.dfs(v, adj);\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn acyclic() {\n        let mut sccs = StronglyConnectedComponents::new(5);\n        let adj = vec![vec![], vec![2, 4], vec![3, 4], vec![5], vec![5], vec![]];\n        sccs.find_components(&adj);\n        assert_eq!(sccs.component, vec![0, 5, 4, 2, 3, 1]);\n        assert_eq!(sccs.state, vec![0, 1, 2, 3, 5, 4]);\n        assert_eq!(sccs.num_components, 5);\n    }\n\n    #[test]\n    fn cycle() {\n        let mut sccs = StronglyConnectedComponents::new(4);\n        let adj = vec![vec![], vec![2], vec![3], vec![4], vec![1]];\n        sccs.find_components(&adj);\n        assert_eq!(sccs.component, vec![0, 1, 1, 1, 1]);\n        assert_eq!(sccs.state, vec![0, 1, 2, 3, 4]);\n        assert_eq!(sccs.num_components, 1);\n    }\n\n    #[test]\n    fn dumbbell() {\n        let mut sccs = StronglyConnectedComponents::new(6);\n        let adj = vec![\n            vec![],\n            vec![2],\n            vec![3, 4],\n            vec![1],\n            vec![5],\n            vec![6],\n            vec![4],\n        ];\n        sccs.find_components(&adj);\n        assert_eq!(sccs.component, vec![0, 2, 2, 2, 1, 1, 1]);\n        assert_eq!(sccs.state, vec![0, 1, 2, 3, 4, 5, 6]);\n        assert_eq!(sccs.num_components, 2);\n    }\n\n    #[test]\n    fn connected_dumbbell() {\n        let mut sccs = StronglyConnectedComponents::new(6);\n        let adj = vec![\n            vec![],\n            vec![2],\n            vec![3, 4],\n            vec![1],\n            vec![5, 1],\n            vec![6],\n            vec![4],\n        ];\n        sccs.find_components(&adj);\n        assert_eq!(sccs.component, vec![0, 1, 1, 1, 1, 1, 1]);\n        assert_eq!(sccs.state, vec![0, 1, 2, 3, 4, 5, 6]);\n        assert_eq!(sccs.num_components, 1);\n    }\n}\n"
  },
  {
    "path": "src/graph/tarjans_ssc.rs",
    "content": "pub struct Graph {\n    n: usize,\n    adj_list: Vec<Vec<usize>>,\n}\n\nimpl Graph {\n    pub fn new(n: usize) -> Self {\n        Self {\n            n,\n            adj_list: vec![vec![]; n],\n        }\n    }\n\n    pub fn add_edge(&mut self, u: usize, v: usize) {\n        self.adj_list[u].push(v);\n    }\n}\npub fn tarjan_scc(graph: &Graph) -> Vec<Vec<usize>> {\n    struct TarjanState {\n        index: i32,\n        stack: Vec<usize>,\n        on_stack: Vec<bool>,\n        index_of: Vec<i32>,\n        lowlink_of: Vec<i32>,\n        components: Vec<Vec<usize>>,\n    }\n\n    let mut state = TarjanState {\n        index: 0,\n        stack: Vec::new(),\n        on_stack: vec![false; graph.n],\n        index_of: vec![-1; graph.n],\n        lowlink_of: vec![-1; graph.n],\n        components: Vec::new(),\n    };\n\n    fn strong_connect(v: usize, graph: &Graph, state: &mut TarjanState) {\n        state.index_of[v] = state.index;\n        state.lowlink_of[v] = state.index;\n        state.index += 1;\n        state.stack.push(v);\n        state.on_stack[v] = true;\n\n        for &w in &graph.adj_list[v] {\n            if state.index_of[w] == -1 {\n                strong_connect(w, graph, state);\n                state.lowlink_of[v] = state.lowlink_of[v].min(state.lowlink_of[w]);\n            } else if state.on_stack[w] {\n                state.lowlink_of[v] = state.lowlink_of[v].min(state.index_of[w]);\n            }\n        }\n\n        if state.lowlink_of[v] == state.index_of[v] {\n            let mut component: Vec<usize> = Vec::new();\n            while let Some(w) = state.stack.pop() {\n                state.on_stack[w] = false;\n                component.push(w);\n                if w == v {\n                    break;\n                }\n            }\n            state.components.push(component);\n        }\n    }\n\n    for v in 0..graph.n {\n        if state.index_of[v] == -1 {\n            strong_connect(v, graph, &mut state);\n        }\n    }\n\n    state.components\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_tarjan_scc() {\n        // Test 1: A graph with multiple strongly connected components\n        let n_vertices = 11;\n        let edges = vec![\n            (0, 1),\n            (0, 3),\n            (1, 2),\n            (1, 4),\n            (2, 0),\n            (2, 6),\n            (3, 2),\n            (4, 5),\n            (4, 6),\n            (5, 6),\n            (5, 7),\n            (5, 8),\n            (5, 9),\n            (6, 4),\n            (7, 9),\n            (8, 9),\n            (9, 8),\n        ];\n        let mut graph = Graph::new(n_vertices);\n\n        for &(u, v) in &edges {\n            graph.add_edge(u, v);\n        }\n\n        let components = tarjan_scc(&graph);\n        assert_eq!(\n            components,\n            vec![\n                vec![8, 9],\n                vec![7],\n                vec![5, 4, 6],\n                vec![3, 2, 1, 0],\n                vec![10],\n            ]\n        );\n\n        // Test 2: A graph with no edges\n        let n_vertices = 5;\n        let edges: Vec<(usize, usize)> = vec![];\n        let mut graph = Graph::new(n_vertices);\n\n        for &(u, v) in &edges {\n            graph.add_edge(u, v);\n        }\n\n        let components = tarjan_scc(&graph);\n\n        // Each node is its own SCC\n        assert_eq!(\n            components,\n            vec![vec![0], vec![1], vec![2], vec![3], vec![4]]\n        );\n\n        // Test 3: A graph with single strongly connected component\n        let n_vertices = 5;\n        let edges = vec![(0, 1), (1, 2), (2, 3), (2, 4), (3, 0), (4, 2)];\n        let mut graph = Graph::new(n_vertices);\n\n        for &(u, v) in &edges {\n            graph.add_edge(u, v);\n        }\n\n        let components = tarjan_scc(&graph);\n        assert_eq!(components, vec![vec![4, 3, 2, 1, 0]]);\n\n        // Test 4: A graph with multiple strongly connected component\n        let n_vertices = 7;\n        let edges = vec![\n            (0, 1),\n            (1, 2),\n            (2, 0),\n            (1, 3),\n            (1, 4),\n            (1, 6),\n            (3, 5),\n            (4, 5),\n        ];\n        let mut graph = Graph::new(n_vertices);\n\n        for &(u, v) in &edges {\n            graph.add_edge(u, v);\n        }\n\n        let components = tarjan_scc(&graph);\n        assert_eq!(\n            components,\n            vec![vec![5], vec![3], vec![4], vec![6], vec![2, 1, 0],]\n        );\n    }\n}\n"
  },
  {
    "path": "src/graph/topological_sort.rs",
    "content": "use std::collections::HashMap;\nuse std::collections::VecDeque;\nuse std::hash::Hash;\n\n#[derive(Debug, Eq, PartialEq)]\npub enum TopoligicalSortError {\n    CycleDetected,\n}\n\ntype TopologicalSortResult<Node> = Result<Vec<Node>, TopoligicalSortError>;\n\n/// Given a directed graph, modeled as a list of edges from source to destination\n/// Uses Kahn's algorithm to either:\n///     return the topological sort of the graph\n///     or detect if there's any cycle\npub fn topological_sort<Node: Hash + Eq + Copy>(\n    edges: &Vec<(Node, Node)>,\n) -> TopologicalSortResult<Node> {\n    // Preparation:\n    //  Build a map of edges, organised from source to destinations\n    //  Also, count the number of incoming edges by node\n    let mut edges_by_source: HashMap<Node, Vec<Node>> = HashMap::default();\n    let mut incoming_edges_count: HashMap<Node, usize> = HashMap::default();\n    for (source, destination) in edges {\n        incoming_edges_count.entry(*source).or_insert(0); // if we haven't seen this node yet, mark it as having 0 incoming nodes\n        edges_by_source // add destination to the list of outgoing edges from source\n            .entry(*source)\n            .or_default()\n            .push(*destination);\n        // then make destination have one more incoming edge\n        *incoming_edges_count.entry(*destination).or_insert(0) += 1;\n    }\n\n    // Now Kahn's algorithm:\n    // Add nodes that have no incoming edges to a queue\n    let mut no_incoming_edges_q = VecDeque::default();\n    for (node, count) in &incoming_edges_count {\n        if *count == 0 {\n            no_incoming_edges_q.push_back(*node);\n        }\n    }\n    // For each node in this \"O-incoming-edge-queue\"\n    let mut sorted = Vec::default();\n    while let Some(no_incoming_edges) = no_incoming_edges_q.pop_back() {\n        sorted.push(no_incoming_edges); // since the node has no dependency, it can be safely pushed to the sorted result\n        incoming_edges_count.remove(&no_incoming_edges);\n        // For each node having this one as dependency\n        for neighbour in edges_by_source.get(&no_incoming_edges).unwrap_or(&vec![]) {\n            if let Some(count) = incoming_edges_count.get_mut(neighbour) {\n                *count -= 1; // decrement the count of incoming edges for the dependent node\n                if *count == 0 {\n                    // `node` was the last node `neighbour` was dependent on\n                    incoming_edges_count.remove(neighbour); // let's remove it from the map, so that we can know if we covered the whole graph\n                    no_incoming_edges_q.push_front(*neighbour); // it has no incoming edges anymore => push it to the queue\n                }\n            }\n        }\n    }\n    if incoming_edges_count.is_empty() {\n        // we have visited every node\n        Ok(sorted)\n    } else {\n        // some nodes haven't been visited, meaning there's a cycle in the graph\n        Err(TopoligicalSortError::CycleDetected)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::topological_sort;\n    use crate::graph::topological_sort::TopoligicalSortError;\n\n    fn is_valid_sort<Node: Eq>(sorted: &[Node], graph: &[(Node, Node)]) -> bool {\n        for (source, dest) in graph {\n            let source_pos = sorted.iter().position(|node| node == source);\n            let dest_pos = sorted.iter().position(|node| node == dest);\n            match (source_pos, dest_pos) {\n                (Some(src), Some(dst)) if src < dst => {}\n                _ => {\n                    return false;\n                }\n            };\n        }\n        true\n    }\n\n    #[test]\n    fn it_works() {\n        let graph = vec![(1, 2), (1, 3), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)];\n        let sort = topological_sort(&graph);\n        assert!(sort.is_ok());\n        let sort = sort.unwrap();\n        assert!(is_valid_sort(&sort, &graph));\n        assert_eq!(sort, vec![1, 2, 3, 4, 5, 6, 7]);\n    }\n\n    #[test]\n    fn test_wikipedia_example() {\n        let graph = vec![\n            (5, 11),\n            (7, 11),\n            (7, 8),\n            (3, 8),\n            (3, 10),\n            (11, 2),\n            (11, 9),\n            (11, 10),\n            (8, 9),\n        ];\n        let sort = topological_sort(&graph);\n        assert!(sort.is_ok());\n        let sort = sort.unwrap();\n        assert!(is_valid_sort(&sort, &graph));\n    }\n\n    #[test]\n    fn test_cyclic_graph() {\n        let graph = vec![(1, 2), (2, 3), (3, 4), (4, 5), (4, 2)];\n        let sort = topological_sort(&graph);\n        assert!(sort.is_err());\n        assert_eq!(sort.err().unwrap(), TopoligicalSortError::CycleDetected);\n    }\n}\n"
  },
  {
    "path": "src/graph/two_satisfiability.rs",
    "content": "use super::strongly_connected_components::StronglyConnectedComponents as SCCs;\n\npub type Condition = (i64, i64);\ntype Graph = Vec<Vec<usize>>;\n\n#[inline]\nfn variable(var: i64) -> usize {\n    if var < 0 {\n        (((-var) << 1) + 1) as usize\n    } else {\n        (var << 1) as usize\n    }\n}\n\n/// Returns an assignment that satisfies all the constraints, or a variable that makes such an assignment impossible.\\\n/// Variables should be numbered from 1 to `n`, and a negative number `-m` corresponds to the negated variable `m`.\\\n/// For more information about this problem, please visit: <https://en.wikipedia.org/wiki/2-satisfiability>\npub fn solve_two_satisfiability(\n    expression: &[Condition],\n    num_variables: usize,\n) -> Result<Vec<bool>, i64> {\n    let num_verts = (num_variables + 1) << 1;\n    let mut result = Vec::new();\n    let mut sccs = SCCs::new(num_verts);\n    let mut adj = Graph::new();\n    adj.resize(num_verts, vec![]);\n    for cond in expression.iter() {\n        let v1 = variable(cond.0);\n        let v2 = variable(cond.1);\n        adj[v1 ^ 1].push(v2);\n        adj[v2 ^ 1].push(v1);\n    }\n    sccs.find_components(&adj);\n    result.resize(num_variables + 1, false);\n    for var in (2..num_verts).step_by(2) {\n        if sccs.component[var] == sccs.component[var ^ 1] {\n            return Err((var >> 1) as i64);\n        }\n        // if a variable isn't\n        if sccs.component[var] < sccs.component[var ^ 1] {\n            result[var >> 1] = true;\n        }\n    }\n    Ok(result)\n}\n\n#[cfg(test)]\nmod tests {\n    use std::thread;\n\n    use super::*;\n\n    fn check_answer(expression: &[Condition], answers: &[bool]) -> bool {\n        let mut ok = true;\n        for &(c1, c2) in expression {\n            let mut cv = false;\n            if c1 < 0 {\n                cv |= !answers[-c1 as usize];\n            } else {\n                cv |= answers[c1 as usize];\n            }\n            if c2 < 0 {\n                cv |= !answers[-c2 as usize];\n            } else {\n                cv |= answers[c2 as usize];\n            }\n            ok &= cv;\n        }\n        ok\n    }\n    #[test]\n    fn basic_test() {\n        let conds = vec![(1, 1), (2, 2)];\n        let res = solve_two_satisfiability(&conds, 2);\n        assert!(res.is_ok());\n        assert!(check_answer(&conds, &res.unwrap()));\n\n        let conds = vec![(1, 2), (-2, -2)];\n        let res = solve_two_satisfiability(&conds, 2);\n        assert!(res.is_ok());\n        assert!(check_answer(&conds, &res.unwrap()));\n\n        let conds = vec![];\n        let res = solve_two_satisfiability(&conds, 2);\n        assert!(res.is_ok());\n        assert!(check_answer(&conds, &res.unwrap()));\n\n        let conds = vec![(-1, -1), (-2, -2), (1, 2)];\n        let res = solve_two_satisfiability(&conds, 2);\n        assert!(res.is_err());\n    }\n\n    #[test]\n    #[ignore]\n    fn big_test() {\n        // We should spawn a new thread and set its stack size to something\n        // big (256MB in this case), because doing DFS (for finding SCCs) is\n        // a stack-intensive operation. 256MB should be enough for 3e5\n        // variables though.\n        let builder = thread::Builder::new().stack_size(256 * 1024 * 1024);\n        let handler = builder\n            .spawn(|| {\n                let num_conds = 3e5 as i64;\n                let mut conds = vec![];\n                for i in 1..num_conds {\n                    conds.push((i, -(i + 1)));\n                }\n                conds.push((num_conds, num_conds));\n                let res = solve_two_satisfiability(&conds, num_conds as usize);\n                assert!(res.is_ok());\n                assert!(check_answer(&conds, &res.unwrap()));\n            })\n            .unwrap();\n        handler.join().unwrap();\n    }\n}\n"
  },
  {
    "path": "src/greedy/minimum_coin_change.rs",
    "content": "//! # Minimum Coin Change (Greedy Algorithm)\n//!\n//! This module implements a greedy algorithm to find the minimum number of coins\n//! needed to make change for a given amount using specified denominations.\n//!\n//! ## Algorithm\n//!\n//! The greedy approach works by always selecting the largest denomination possible\n//! at each step. While this approach doesn't guarantee an optimal solution for all\n//! denomination systems, it works correctly for canonical coin systems (like most\n//! real-world currencies including USD, EUR, INR, etc.).\n//!\n//! ## Time Complexity\n//!\n//! O(n) where n is the number of denominations\n//!\n//! ## Space Complexity\n//!\n//! O(m) where m is the number of coins in the result\n//!\n//! ## Example\n//!\n//! ```\n//! # fn find_minimum_change(denominations: &[i32], value: i32) -> Vec<i32> {\n//! #     if value <= 0 || denominations.is_empty() {\n//! #         return Vec::new();\n//! #     }\n//! #     let mut remaining_value = value;\n//! #     let mut result = Vec::new();\n//! #     let mut sorted_denominations = denominations.to_vec();\n//! #     sorted_denominations.sort_unstable_by(|a, b| b.cmp(a));\n//! #     for &denomination in &sorted_denominations {\n//! #         while remaining_value >= denomination {\n//! #             remaining_value -= denomination;\n//! #             result.push(denomination);\n//! #         }\n//! #     }\n//! #     result\n//! # }\n//! let denominations = vec![1, 2, 5, 10, 20, 50, 100, 500, 2000];\n//! let result = find_minimum_change(&denominations, 987);\n//! assert_eq!(result, vec![500, 100, 100, 100, 100, 50, 20, 10, 5, 2]);\n//! ```\n\n/// Finds the minimum number of coins needed to make change for a given value\n/// using a greedy algorithm.\n///\n/// # Arguments\n///\n/// * `denominations` - A slice of available coin denominations (must be positive integers)\n/// * `value` - The target value to make change for (must be non-negative)\n///\n/// # Returns\n///\n/// A vector containing the coins used, in descending order. Returns an empty vector\n/// if the value is zero or negative, or if denominations is empty.\n///\n/// # Examples\n///\n/// ```\n/// # fn find_minimum_change(denominations: &[i32], value: i32) -> Vec<i32> {\n/// #     if value <= 0 || denominations.is_empty() { return Vec::new(); }\n/// #     let mut remaining_value = value;\n/// #     let mut result = Vec::new();\n/// #     let mut sorted_denominations = denominations.to_vec();\n/// #     sorted_denominations.sort_unstable_by(|a, b| b.cmp(a));\n/// #     for &denomination in &sorted_denominations {\n/// #         while remaining_value >= denomination {\n/// #             remaining_value -= denomination;\n/// #             result.push(denomination);\n/// #         }\n/// #     }\n/// #     result\n/// # }\n/// // Indian currency example\n/// let denominations = vec![1, 2, 5, 10, 20, 50, 100, 500, 2000];\n/// let result = find_minimum_change(&denominations, 987);\n/// assert_eq!(result, vec![500, 100, 100, 100, 100, 50, 20, 10, 5, 2]);\n/// ```\n///\n/// ```\n/// # fn find_minimum_change(denominations: &[i32], value: i32) -> Vec<i32> {\n/// #     if value <= 0 || denominations.is_empty() { return Vec::new(); }\n/// #     let mut remaining_value = value;\n/// #     let mut result = Vec::new();\n/// #     let mut sorted_denominations = denominations.to_vec();\n/// #     sorted_denominations.sort_unstable_by(|a, b| b.cmp(a));\n/// #     for &denomination in &sorted_denominations {\n/// #         while remaining_value >= denomination {\n/// #             remaining_value -= denomination;\n/// #             result.push(denomination);\n/// #         }\n/// #     }\n/// #     result\n/// # }\n/// // Large amount example\n/// let denominations = vec![1, 5, 10, 20, 50, 100, 200, 500, 1000, 2000];\n/// let result = find_minimum_change(&denominations, 18745);\n/// assert_eq!(\n///     result,\n///     vec![2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 500, 200, 20, 20, 5]\n/// );\n/// ```\n///\n/// ```\n/// # fn find_minimum_change(denominations: &[i32], value: i32) -> Vec<i32> {\n/// #     if value <= 0 || denominations.is_empty() { return Vec::new(); }\n/// #     let mut remaining_value = value;\n/// #     let mut result = Vec::new();\n/// #     let mut sorted_denominations = denominations.to_vec();\n/// #     sorted_denominations.sort_unstable_by(|a, b| b.cmp(a));\n/// #     for &denomination in &sorted_denominations {\n/// #         while remaining_value >= denomination {\n/// #             remaining_value -= denomination;\n/// #             result.push(denomination);\n/// #         }\n/// #     }\n/// #     result\n/// # }\n/// // Edge case: zero value\n/// let denominations = vec![1, 2, 5, 10];\n/// let result = find_minimum_change(&denominations, 0);\n/// assert_eq!(result, Vec::<i32>::new());\n/// ```\n///\n/// ```\n/// # fn find_minimum_change(denominations: &[i32], value: i32) -> Vec<i32> {\n/// #     if value <= 0 || denominations.is_empty() { return Vec::new(); }\n/// #     let mut remaining_value = value;\n/// #     let mut result = Vec::new();\n/// #     let mut sorted_denominations = denominations.to_vec();\n/// #     sorted_denominations.sort_unstable_by(|a, b| b.cmp(a));\n/// #     for &denomination in &sorted_denominations {\n/// #         while remaining_value >= denomination {\n/// #             remaining_value -= denomination;\n/// #             result.push(denomination);\n/// #         }\n/// #     }\n/// #     result\n/// # }\n/// // Edge case: negative value\n/// let denominations = vec![1, 2, 5, 10];\n/// let result = find_minimum_change(&denominations, -50);\n/// assert_eq!(result, Vec::<i32>::new());\n/// ```\n///\n/// ```\n/// # fn find_minimum_change(denominations: &[i32], value: i32) -> Vec<i32> {\n/// #     if value <= 0 || denominations.is_empty() { return Vec::new(); }\n/// #     let mut remaining_value = value;\n/// #     let mut result = Vec::new();\n/// #     let mut sorted_denominations = denominations.to_vec();\n/// #     sorted_denominations.sort_unstable_by(|a, b| b.cmp(a));\n/// #     for &denomination in &sorted_denominations {\n/// #         while remaining_value >= denomination {\n/// #             remaining_value -= denomination;\n/// #             result.push(denomination);\n/// #         }\n/// #     }\n/// #     result\n/// # }\n/// // Non-standard denominations\n/// let denominations = vec![1, 5, 100, 500, 1000];\n/// let result = find_minimum_change(&denominations, 456);\n/// assert_eq!(\n///     result,\n///     vec![100, 100, 100, 100, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1]\n/// );\n/// ```\npub fn find_minimum_change(denominations: &[i32], value: i32) -> Vec<i32> {\n    // Handle edge cases\n    if value <= 0 || denominations.is_empty() {\n        return Vec::new();\n    }\n\n    let mut remaining_value = value;\n    let mut result = Vec::new();\n\n    // Sort denominations in descending order for greedy selection\n    let mut sorted_denominations = denominations.to_vec();\n    sorted_denominations.sort_unstable_by(|a, b| b.cmp(a));\n\n    // Greedily select the largest denomination at each step\n    for &denomination in &sorted_denominations {\n        while remaining_value >= denomination {\n            remaining_value -= denomination;\n            result.push(denomination);\n        }\n    }\n\n    result\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_indian_currency_standard() {\n        let denominations = vec![1, 2, 5, 10, 20, 50, 100, 500, 2000];\n        let result = find_minimum_change(&denominations, 987);\n        assert_eq!(result, vec![500, 100, 100, 100, 100, 50, 20, 10, 5, 2]);\n        assert_eq!(result.len(), 10);\n    }\n\n    #[test]\n    fn test_large_amount() {\n        let denominations = vec![1, 5, 10, 20, 50, 100, 200, 500, 1000, 2000];\n        let result = find_minimum_change(&denominations, 18745);\n        assert_eq!(\n            result,\n            vec![2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 500, 200, 20, 20, 5]\n        );\n        assert_eq!(result.iter().sum::<i32>(), 18745);\n    }\n\n    #[test]\n    fn test_zero_value() {\n        let denominations = vec![1, 2, 5, 10, 20, 50, 100, 500, 2000];\n        let result = find_minimum_change(&denominations, 0);\n        assert_eq!(result, Vec::<i32>::new());\n    }\n\n    #[test]\n    fn test_negative_value() {\n        let denominations = vec![1, 2, 5, 10, 20, 50, 100, 500, 2000];\n        let result = find_minimum_change(&denominations, -98);\n        assert_eq!(result, Vec::<i32>::new());\n    }\n\n    #[test]\n    fn test_non_standard_denominations() {\n        let denominations = vec![1, 5, 100, 500, 1000];\n        let result = find_minimum_change(&denominations, 456);\n        assert_eq!(\n            result,\n            vec![100, 100, 100, 100, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1]\n        );\n        assert_eq!(result.iter().sum::<i32>(), 456);\n    }\n\n    #[test]\n    fn test_single_denomination() {\n        let denominations = vec![5];\n        let result = find_minimum_change(&denominations, 25);\n        assert_eq!(result, vec![5, 5, 5, 5, 5]);\n    }\n\n    #[test]\n    fn test_exact_denomination() {\n        let denominations = vec![1, 5, 10, 25, 50, 100];\n        let result = find_minimum_change(&denominations, 100);\n        assert_eq!(result, vec![100]);\n    }\n\n    #[test]\n    fn test_empty_denominations() {\n        let denominations: Vec<i32> = vec![];\n        let result = find_minimum_change(&denominations, 100);\n        assert_eq!(result, Vec::<i32>::new());\n    }\n\n    #[test]\n    fn test_unsorted_denominations() {\n        let denominations = vec![100, 1, 50, 5, 20, 10, 2];\n        let result = find_minimum_change(&denominations, 178);\n        assert_eq!(result, vec![100, 50, 20, 5, 2, 1]);\n        assert_eq!(result.iter().sum::<i32>(), 178);\n    }\n\n    #[test]\n    fn test_usd_currency() {\n        let denominations = vec![1, 5, 10, 25, 50, 100]; // cents\n        let result = find_minimum_change(&denominations, 99);\n        assert_eq!(result, vec![50, 25, 10, 10, 1, 1, 1, 1]);\n        assert_eq!(result.len(), 8);\n    }\n}\n"
  },
  {
    "path": "src/greedy/mod.rs",
    "content": "mod minimum_coin_change;\nmod smallest_range;\nmod stable_matching;\n\npub use self::minimum_coin_change::find_minimum_change;\npub use self::smallest_range::smallest_range;\npub use self::stable_matching::stable_matching;\n"
  },
  {
    "path": "src/greedy/smallest_range.rs",
    "content": "//! # Smallest Range Covering Elements from K Lists\n//!\n//! Given `k` sorted integer lists, finds the smallest range `[lo, hi]` such\n//! that at least one element from every list lies within that range.\n//!\n//! ## Algorithm\n//!\n//! A min-heap is seeded with the first element of each list.  On every\n//! iteration the heap yields the current global minimum; the global maximum is\n//! maintained separately.  If `[min, max]` is tighter than the best range seen\n//! so far, it is recorded.  The minimum is then replaced by the next element\n//! from the same list.  The loop stops as soon as any list is exhausted,\n//! because no further range can cover all lists.\n//!\n//! ## References\n//!\n//! - <https://en.wikipedia.org/wiki/Priority_queue>\n\nuse std::cmp::Reverse;\nuse std::collections::BinaryHeap;\n\n/// Finds the smallest range that includes at least one number from each of the\n/// given sorted lists.\n///\n/// Time complexity: `O(n log k)` where `n` is the total number of elements\n/// and `k` is the number of lists.\n///\n/// Space complexity: `O(k)` for the heap.\n///\n/// Returns `None` if any list is empty.\npub fn smallest_range(nums: &[&[i64]]) -> Option<[i64; 2]> {\n    // A range cannot cover an empty list\n    if nums.iter().any(|list| list.is_empty()) {\n        return None;\n    }\n\n    // Heap entries: (Reverse(value), list_index, element_index).\n    // Wrapping the value in Reverse turns BinaryHeap (max-heap) into a min-heap.\n    let mut heap: BinaryHeap<(Reverse<i64>, usize, usize)> = BinaryHeap::new();\n    let mut current_max = i64::MIN;\n\n    // Seed the heap with the first element from each list\n    for (list_idx, list) in nums.iter().enumerate() {\n        heap.push((Reverse(list[0]), list_idx, 0));\n        current_max = current_max.max(list[0]);\n    }\n\n    // Use Option to avoid sentinel arithmetic that could overflow\n    let mut best: Option<[i64; 2]> = None;\n\n    let is_tighter = |candidate: [i64; 2], best: Option<[i64; 2]>| match best {\n        None => true,\n        Some(b) => (candidate[1] - candidate[0]) < (b[1] - b[0]),\n    };\n\n    while let Some((Reverse(current_min), list_idx, elem_idx)) = heap.pop() {\n        // Check if [current_min, current_max] beats the best range seen so far\n        let candidate = [current_min, current_max];\n        if is_tighter(candidate, best) {\n            best = Some(candidate);\n        }\n\n        // If this list is exhausted we can no longer cover all lists\n        let next_idx = elem_idx + 1;\n        if next_idx == nums[list_idx].len() {\n            break;\n        }\n\n        // Advance to the next element in the same list\n        let next_val = nums[list_idx][next_idx];\n        heap.push((Reverse(next_val), list_idx, next_idx));\n        current_max = current_max.max(next_val);\n    }\n\n    best\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn mixed_lists() {\n        assert_eq!(\n            smallest_range(&[&[4, 10, 15, 24, 26], &[0, 9, 12, 20], &[5, 18, 22, 30]]),\n            Some([20, 24])\n        );\n    }\n\n    #[test]\n    fn identical_lists() {\n        assert_eq!(\n            smallest_range(&[&[1, 2, 3], &[1, 2, 3], &[1, 2, 3]]),\n            Some([1, 1])\n        );\n    }\n\n    #[test]\n    fn negative_and_positive() {\n        assert_eq!(\n            smallest_range(&[&[-3, -2, -1], &[0, 0, 0], &[1, 2, 3]]),\n            Some([-1, 1])\n        );\n    }\n\n    #[test]\n    fn non_overlapping() {\n        assert_eq!(\n            smallest_range(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]),\n            Some([3, 7])\n        );\n    }\n\n    #[test]\n    fn all_zeros() {\n        assert_eq!(\n            smallest_range(&[&[0, 0, 0], &[0, 0, 0], &[0, 0, 0]]),\n            Some([0, 0])\n        );\n    }\n\n    #[test]\n    fn empty_lists() {\n        assert_eq!(smallest_range(&[&[], &[], &[]]), None);\n    }\n\n    #[test]\n    fn single_elements() {\n        assert_eq!(smallest_range(&[&[5], &[3], &[9]]), Some([3, 9]));\n    }\n\n    #[test]\n    fn single_list() {\n        assert_eq!(smallest_range(&[&[1, 2, 3]]), Some([1, 1]));\n    }\n\n    #[test]\n    fn one_empty_among_non_empty() {\n        assert_eq!(smallest_range(&[&[1, 2], &[], &[3, 4]]), None);\n    }\n}\n"
  },
  {
    "path": "src/greedy/stable_matching.rs",
    "content": "use std::collections::{HashMap, VecDeque};\n\nfn initialize_men(\n    men_preferences: &HashMap<String, Vec<String>>,\n) -> (VecDeque<String>, HashMap<String, usize>) {\n    let mut free_men = VecDeque::new();\n    let mut next_proposal = HashMap::new();\n\n    for man in men_preferences.keys() {\n        free_men.push_back(man.clone());\n        next_proposal.insert(man.clone(), 0);\n    }\n\n    (free_men, next_proposal)\n}\n\nfn initialize_women(\n    women_preferences: &HashMap<String, Vec<String>>,\n) -> HashMap<String, Option<String>> {\n    let mut current_partner = HashMap::new();\n    for woman in women_preferences.keys() {\n        current_partner.insert(woman.clone(), None);\n    }\n    current_partner\n}\n\nfn precompute_woman_ranks(\n    women_preferences: &HashMap<String, Vec<String>>,\n) -> HashMap<String, HashMap<String, usize>> {\n    let mut woman_ranks = HashMap::new();\n    for (woman, preferences) in women_preferences {\n        let mut rank_map = HashMap::new();\n        for (rank, man) in preferences.iter().enumerate() {\n            rank_map.insert(man.clone(), rank);\n        }\n        woman_ranks.insert(woman.clone(), rank_map);\n    }\n    woman_ranks\n}\n\nfn process_proposal(\n    man: &str,\n    free_men: &mut VecDeque<String>,\n    current_partner: &mut HashMap<String, Option<String>>,\n    man_engaged: &mut HashMap<String, Option<String>>,\n    next_proposal: &mut HashMap<String, usize>,\n    men_preferences: &HashMap<String, Vec<String>>,\n    woman_ranks: &HashMap<String, HashMap<String, usize>>,\n) {\n    let man_pref_list = &men_preferences[man];\n    let next_woman_idx = next_proposal[man];\n    let woman = &man_pref_list[next_woman_idx];\n\n    // Update man's next proposal index\n    next_proposal.insert(man.to_string(), next_woman_idx + 1);\n\n    if let Some(current_man) = current_partner[woman].clone() {\n        // Woman is currently engaged, check if she prefers the new man\n        if woman_prefers_new_man(woman, man, &current_man, woman_ranks) {\n            engage_man(\n                man,\n                woman,\n                free_men,\n                current_partner,\n                man_engaged,\n                Some(current_man),\n            );\n        } else {\n            // Woman rejects the proposal, so the man remains free\n            free_men.push_back(man.to_string());\n        }\n    } else {\n        // Woman is not engaged, so engage her with this man\n        engage_man(man, woman, free_men, current_partner, man_engaged, None);\n    }\n}\n\nfn woman_prefers_new_man(\n    woman: &str,\n    man1: &str,\n    man2: &str,\n    woman_ranks: &HashMap<String, HashMap<String, usize>>,\n) -> bool {\n    let ranks = &woman_ranks[woman];\n    ranks[man1] < ranks[man2]\n}\n\nfn engage_man(\n    man: &str,\n    woman: &str,\n    free_men: &mut VecDeque<String>,\n    current_partner: &mut HashMap<String, Option<String>>,\n    man_engaged: &mut HashMap<String, Option<String>>,\n    current_man: Option<String>,\n) {\n    man_engaged.insert(man.to_string(), Some(woman.to_string()));\n    current_partner.insert(woman.to_string(), Some(man.to_string()));\n\n    if let Some(current_man) = current_man {\n        // The current man is now free\n        free_men.push_back(current_man);\n    }\n}\n\nfn finalize_matches(man_engaged: HashMap<String, Option<String>>) -> HashMap<String, String> {\n    let mut stable_matches = HashMap::new();\n    for (man, woman_option) in man_engaged {\n        if let Some(woman) = woman_option {\n            stable_matches.insert(man, woman);\n        }\n    }\n    stable_matches\n}\n\npub fn stable_matching(\n    men_preferences: &HashMap<String, Vec<String>>,\n    women_preferences: &HashMap<String, Vec<String>>,\n) -> HashMap<String, String> {\n    let (mut free_men, mut next_proposal) = initialize_men(men_preferences);\n    let mut current_partner = initialize_women(women_preferences);\n    let mut man_engaged = HashMap::new();\n\n    let woman_ranks = precompute_woman_ranks(women_preferences);\n\n    while let Some(man) = free_men.pop_front() {\n        process_proposal(\n            &man,\n            &mut free_men,\n            &mut current_partner,\n            &mut man_engaged,\n            &mut next_proposal,\n            men_preferences,\n            &woman_ranks,\n        );\n    }\n\n    finalize_matches(man_engaged)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::collections::HashMap;\n\n    #[test]\n    fn test_stable_matching_scenario_1() {\n        let men_preferences = HashMap::from([\n            (\n                \"A\".to_string(),\n                vec![\"X\".to_string(), \"Y\".to_string(), \"Z\".to_string()],\n            ),\n            (\n                \"B\".to_string(),\n                vec![\"Y\".to_string(), \"X\".to_string(), \"Z\".to_string()],\n            ),\n            (\n                \"C\".to_string(),\n                vec![\"X\".to_string(), \"Y\".to_string(), \"Z\".to_string()],\n            ),\n        ]);\n\n        let women_preferences = HashMap::from([\n            (\n                \"X\".to_string(),\n                vec![\"B\".to_string(), \"A\".to_string(), \"C\".to_string()],\n            ),\n            (\n                \"Y\".to_string(),\n                vec![\"A\".to_string(), \"B\".to_string(), \"C\".to_string()],\n            ),\n            (\n                \"Z\".to_string(),\n                vec![\"A\".to_string(), \"B\".to_string(), \"C\".to_string()],\n            ),\n        ]);\n\n        let matches = stable_matching(&men_preferences, &women_preferences);\n\n        let expected_matches1 = HashMap::from([\n            (\"A\".to_string(), \"Y\".to_string()),\n            (\"B\".to_string(), \"X\".to_string()),\n            (\"C\".to_string(), \"Z\".to_string()),\n        ]);\n\n        let expected_matches2 = HashMap::from([\n            (\"A\".to_string(), \"X\".to_string()),\n            (\"B\".to_string(), \"Y\".to_string()),\n            (\"C\".to_string(), \"Z\".to_string()),\n        ]);\n\n        assert!(matches == expected_matches1 || matches == expected_matches2);\n    }\n\n    #[test]\n    fn test_stable_matching_empty() {\n        let men_preferences = HashMap::new();\n        let women_preferences = HashMap::new();\n\n        let matches = stable_matching(&men_preferences, &women_preferences);\n        assert!(matches.is_empty());\n    }\n\n    #[test]\n    fn test_stable_matching_duplicate_preferences() {\n        let men_preferences = HashMap::from([\n            (\"A\".to_string(), vec![\"X\".to_string(), \"X\".to_string()]), // Man with duplicate preferences\n            (\"B\".to_string(), vec![\"Y\".to_string()]),\n        ]);\n\n        let women_preferences = HashMap::from([\n            (\"X\".to_string(), vec![\"A\".to_string(), \"B\".to_string()]),\n            (\"Y\".to_string(), vec![\"B\".to_string()]),\n        ]);\n\n        let matches = stable_matching(&men_preferences, &women_preferences);\n        let expected_matches = HashMap::from([\n            (\"A\".to_string(), \"X\".to_string()),\n            (\"B\".to_string(), \"Y\".to_string()),\n        ]);\n\n        assert_eq!(matches, expected_matches);\n    }\n\n    #[test]\n    fn test_stable_matching_single_pair() {\n        let men_preferences = HashMap::from([(\"A\".to_string(), vec![\"X\".to_string()])]);\n        let women_preferences = HashMap::from([(\"X\".to_string(), vec![\"A\".to_string()])]);\n\n        let matches = stable_matching(&men_preferences, &women_preferences);\n        let expected_matches = HashMap::from([(\"A\".to_string(), \"X\".to_string())]);\n\n        assert_eq!(matches, expected_matches);\n    }\n    #[test]\n    fn test_woman_prefers_new_man() {\n        let men_preferences = HashMap::from([\n            (\n                \"A\".to_string(),\n                vec![\"X\".to_string(), \"Y\".to_string(), \"Z\".to_string()],\n            ),\n            (\n                \"B\".to_string(),\n                vec![\"X\".to_string(), \"Y\".to_string(), \"Z\".to_string()],\n            ),\n            (\n                \"C\".to_string(),\n                vec![\"X\".to_string(), \"Y\".to_string(), \"Z\".to_string()],\n            ),\n        ]);\n\n        let women_preferences = HashMap::from([\n            (\n                \"X\".to_string(),\n                vec![\"B\".to_string(), \"A\".to_string(), \"C\".to_string()],\n            ),\n            (\n                \"Y\".to_string(),\n                vec![\"A\".to_string(), \"B\".to_string(), \"C\".to_string()],\n            ),\n            (\n                \"Z\".to_string(),\n                vec![\"A\".to_string(), \"B\".to_string(), \"C\".to_string()],\n            ),\n        ]);\n\n        let matches = stable_matching(&men_preferences, &women_preferences);\n\n        let expected_matches = HashMap::from([\n            (\"A\".to_string(), \"Y\".to_string()),\n            (\"B\".to_string(), \"X\".to_string()),\n            (\"C\".to_string(), \"Z\".to_string()),\n        ]);\n\n        assert_eq!(matches, expected_matches);\n    }\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "pub mod backtracking;\npub mod big_integer;\npub mod bit_manipulation;\npub mod ciphers;\npub mod compression;\npub mod conversions;\npub mod data_structures;\npub mod dynamic_programming;\npub mod financial;\npub mod general;\npub mod geometry;\npub mod graph;\npub mod greedy;\npub mod machine_learning;\npub mod math;\npub mod navigation;\npub mod number_theory;\npub mod searching;\npub mod signal_analysis;\npub mod sorting;\npub mod string;\n"
  },
  {
    "path": "src/machine_learning/cholesky.rs",
    "content": "pub fn cholesky(mat: Vec<f64>, n: usize) -> Vec<f64> {\n    if (mat.is_empty()) || (n == 0) {\n        return vec![];\n    }\n    let mut res = vec![0.0; mat.len()];\n    for i in 0..n {\n        for j in 0..=i {\n            let mut s = 0.0;\n            for k in 0..j {\n                s += res[i * n + k] * res[j * n + k];\n            }\n            let value = if i == j {\n                let diag_value = mat[i * n + i] - s;\n                if diag_value.is_nan() {\n                    0.0\n                } else {\n                    diag_value.sqrt()\n                }\n            } else {\n                let off_diag_value = 1.0 / res[j * n + j] * (mat[i * n + j] - s);\n                if off_diag_value.is_nan() {\n                    0.0\n                } else {\n                    off_diag_value\n                }\n            };\n            res[i * n + j] = value;\n        }\n    }\n    res\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_cholesky() {\n        // Test case 1\n        let mat1 = vec![25.0, 15.0, -5.0, 15.0, 18.0, 0.0, -5.0, 0.0, 11.0];\n        let res1 = cholesky(mat1, 3);\n\n        // The expected Cholesky decomposition values\n        #[allow(clippy::useless_vec)]\n        let expected1 = vec![5.0, 0.0, 0.0, 3.0, 3.0, 0.0, -1.0, 1.0, 3.0];\n\n        assert!(res1\n            .iter()\n            .zip(expected1.iter())\n            .all(|(a, b)| (a - b).abs() < 1e-6));\n    }\n\n    fn transpose_matrix(mat: &[f64], n: usize) -> Vec<f64> {\n        (0..n)\n            .flat_map(|i| (0..n).map(move |j| mat[j * n + i]))\n            .collect()\n    }\n\n    fn matrix_multiply(mat1: &[f64], mat2: &[f64], n: usize) -> Vec<f64> {\n        (0..n)\n            .flat_map(|i| {\n                (0..n).map(move |j| {\n                    (0..n).fold(0.0, |acc, k| acc + mat1[i * n + k] * mat2[k * n + j])\n                })\n            })\n            .collect()\n    }\n\n    #[test]\n    fn test_matrix_operations() {\n        // Test case 1: Transposition\n        let mat1 = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];\n        let transposed_mat1 = transpose_matrix(&mat1, 3);\n        let expected_transposed_mat1 = vec![1.0, 4.0, 7.0, 2.0, 5.0, 8.0, 3.0, 6.0, 9.0];\n        assert_eq!(transposed_mat1, expected_transposed_mat1);\n\n        // Test case 2: Matrix multiplication\n        let mat2 = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];\n        let mat3 = vec![9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0];\n        let multiplied_mat = matrix_multiply(&mat2, &mat3, 3);\n        let expected_multiplied_mat = vec![30.0, 24.0, 18.0, 84.0, 69.0, 54.0, 138.0, 114.0, 90.0];\n        assert_eq!(multiplied_mat, expected_multiplied_mat);\n    }\n\n    #[test]\n    fn empty_matrix() {\n        let mat = vec![];\n        let res = cholesky(mat, 0);\n        assert_eq!(res, vec![]);\n    }\n\n    #[test]\n    fn matrix_with_all_zeros() {\n        let mat3 = vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];\n        let res3 = cholesky(mat3, 3);\n        let expected3 = vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];\n        assert_eq!(res3, expected3);\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/decision_tree.rs",
    "content": "/// Decision Tree classifier using the ID3 algorithm with entropy-based splitting.\n/// The tree recursively splits data based on the feature that provides the highest information gain.\n/// Supports both categorical and continuous features through threshold-based splitting.\n\n#[derive(Debug, Clone, PartialEq)]\nenum TreeNode {\n    Leaf {\n        class_label: f64,\n        samples: usize,\n    },\n    InternalNode {\n        feature_index: usize,\n        threshold: f64,\n        left: Box<TreeNode>,\n        right: Box<TreeNode>,\n        samples: usize,\n    },\n}\n\n/// Calculate entropy of a set of labels\nfn calculate_entropy(labels: &[f64]) -> f64 {\n    if labels.is_empty() {\n        return 0.0;\n    }\n\n    let total = labels.len() as f64;\n    let mut unique_labels: Vec<f64> = Vec::new();\n    let mut counts = Vec::new();\n\n    for &label in labels {\n        let mut found = false;\n        for (i, &existing_label) in unique_labels.iter().enumerate() {\n            if (existing_label - label).abs() < 1e-10 {\n                counts[i] += 1;\n                found = true;\n                break;\n            }\n        }\n        if !found {\n            unique_labels.push(label);\n            counts.push(1);\n        }\n    }\n\n    let mut entropy = 0.0;\n    for &count in &counts {\n        let probability = count as f64 / total;\n        if probability > 0.0 {\n            entropy -= probability * probability.log2();\n        }\n    }\n\n    entropy\n}\n\n/// Find the best split for a feature\nfn find_best_split(data: &[(Vec<f64>, f64)], feature_index: usize) -> Option<(f64, f64)> {\n    if data.is_empty() {\n        return None;\n    }\n\n    let num_samples = data.len();\n\n    let mut feature_values: Vec<(f64, f64)> = data\n        .iter()\n        .map(|(features, label)| (features[feature_index], *label))\n        .collect();\n\n    feature_values.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));\n\n    let parent_entropy =\n        calculate_entropy(&data.iter().map(|(_, label)| *label).collect::<Vec<_>>());\n\n    let mut best_threshold = feature_values[0].0;\n    let mut best_gain = 0.0;\n\n    for i in 1..num_samples {\n        if feature_values[i].0 != feature_values[i - 1].0 {\n            let threshold = f64::midpoint(feature_values[i].0, feature_values[i - 1].0);\n\n            let left_labels: Vec<f64> = feature_values[..i]\n                .iter()\n                .map(|(_, label)| *label)\n                .collect();\n            let right_labels: Vec<f64> = feature_values[i..]\n                .iter()\n                .map(|(_, label)| *label)\n                .collect();\n\n            let left_entropy = calculate_entropy(&left_labels);\n            let right_entropy = calculate_entropy(&right_labels);\n\n            let left_weight = i as f64 / num_samples as f64;\n            let right_weight = (num_samples - i) as f64 / num_samples as f64;\n\n            let weighted_entropy = left_weight * left_entropy + right_weight * right_entropy;\n            let information_gain = parent_entropy - weighted_entropy;\n\n            if information_gain > best_gain {\n                best_gain = information_gain;\n                best_threshold = threshold;\n            }\n        }\n    }\n\n    if best_gain > 0.0 {\n        Some((best_threshold, best_gain))\n    } else {\n        None\n    }\n}\n\n/// Find the best feature and threshold to split on\nfn find_best_split_feature(\n    data: &[(Vec<f64>, f64)],\n    feature_indices: &[usize],\n) -> Option<(usize, f64)> {\n    if data.is_empty() || feature_indices.is_empty() {\n        return None;\n    }\n\n    let mut best_feature_index = 0;\n    let mut best_threshold = 0.0;\n    let mut best_gain = 0.0;\n\n    for &feature_index in feature_indices {\n        if let Some((threshold, gain)) = find_best_split(data, feature_index) {\n            if gain > best_gain {\n                best_gain = gain;\n                best_threshold = threshold;\n                best_feature_index = feature_index;\n            }\n        }\n    }\n\n    if best_gain > 0.0 {\n        Some((best_feature_index, best_threshold))\n    } else {\n        None\n    }\n}\n\n/// Get the majority class label\nfn get_majority_class(labels: &[f64]) -> f64 {\n    if labels.is_empty() {\n        return 0.0;\n    }\n\n    let mut unique_labels: Vec<f64> = Vec::new();\n    let mut counts = Vec::new();\n\n    for &label in labels {\n        let mut found = false;\n        for (i, &existing_label) in unique_labels.iter().enumerate() {\n            if (existing_label - label).abs() < 1e-10 {\n                counts[i] += 1;\n                found = true;\n                break;\n            }\n        }\n        if !found {\n            unique_labels.push(label);\n            counts.push(1);\n        }\n    }\n\n    let mut max_index = 0;\n    let mut max_count = 0;\n    for (i, &count) in counts.iter().enumerate() {\n        if count > max_count {\n            max_count = count;\n            max_index = i;\n        }\n    }\n\n    unique_labels[max_index]\n}\n\n/// Build the decision tree recursively\nfn build_tree(\n    data: &[(Vec<f64>, f64)],\n    feature_indices: &[usize],\n    max_depth: usize,\n    min_samples_split: usize,\n    current_depth: usize,\n) -> TreeNode {\n    let labels: Vec<f64> = data.iter().map(|(_, label)| *label).collect();\n\n    // Count unique labels\n    let mut unique_count = 0;\n    for i in 0..labels.len() {\n        let mut is_unique = true;\n        for j in 0..i {\n            if (labels[i] - labels[j]).abs() < 1e-10 {\n                is_unique = false;\n                break;\n            }\n        }\n        if is_unique {\n            unique_count += 1;\n        }\n    }\n\n    if unique_count == 1\n        || data.len() < min_samples_split\n        || current_depth >= max_depth\n        || feature_indices.is_empty()\n    {\n        let class_label = get_majority_class(&labels);\n        return TreeNode::Leaf {\n            class_label,\n            samples: data.len(),\n        };\n    }\n\n    if let Some((feature_index, threshold)) = find_best_split_feature(data, feature_indices) {\n        let mut left_data = Vec::new();\n        let mut right_data = Vec::new();\n\n        for (features, label) in data {\n            if features[feature_index] < threshold {\n                left_data.push((features.clone(), *label));\n            } else {\n                right_data.push((features.clone(), *label));\n            }\n        }\n\n        if left_data.is_empty() || right_data.is_empty() {\n            let class_label = get_majority_class(&labels);\n            return TreeNode::Leaf {\n                class_label,\n                samples: data.len(),\n            };\n        }\n\n        let left_child = build_tree(\n            &left_data,\n            feature_indices,\n            max_depth,\n            min_samples_split,\n            current_depth + 1,\n        );\n        let right_child = build_tree(\n            &right_data,\n            feature_indices,\n            max_depth,\n            min_samples_split,\n            current_depth + 1,\n        );\n\n        TreeNode::InternalNode {\n            feature_index,\n            threshold,\n            left: Box::new(left_child),\n            right: Box::new(right_child),\n            samples: data.len(),\n        }\n    } else {\n        let class_label = get_majority_class(&labels);\n        TreeNode::Leaf {\n            class_label,\n            samples: data.len(),\n        }\n    }\n}\n\n/// Predict the class label for a single test point\nfn predict_tree(tree: &TreeNode, features: &[f64]) -> f64 {\n    match tree {\n        TreeNode::Leaf { class_label, .. } => *class_label,\n        TreeNode::InternalNode {\n            feature_index,\n            threshold,\n            left,\n            right,\n            ..\n        } => {\n            if features[*feature_index] < *threshold {\n                predict_tree(left, features)\n            } else {\n                predict_tree(right, features)\n            }\n        }\n    }\n}\n\n#[derive(Debug, PartialEq)]\npub struct DecisionTree {\n    tree: TreeNode,\n}\n\nimpl DecisionTree {\n    pub fn fit(\n        training_data: Vec<(Vec<f64>, f64)>,\n        max_depth: usize,\n        min_samples_split: usize,\n    ) -> Option<Self> {\n        if training_data.is_empty() {\n            return None;\n        }\n\n        let num_features = training_data[0].0.len();\n        if num_features == 0 {\n            return None;\n        }\n\n        let feature_indices: Vec<usize> = (0..num_features).collect();\n        let tree = build_tree(\n            &training_data,\n            &feature_indices,\n            max_depth,\n            min_samples_split,\n            0,\n        );\n\n        Some(DecisionTree { tree })\n    }\n\n    pub fn predict(&self, test_point: &[f64]) -> Option<f64> {\n        if test_point.is_empty() {\n            return None;\n        }\n\n        Some(predict_tree(&self.tree, test_point))\n    }\n\n    #[allow(dead_code)]\n    pub fn predict_batch(&self, test_points: &[Vec<f64>]) -> Vec<Option<f64>> {\n        test_points\n            .iter()\n            .map(|point| self.predict(point))\n            .collect()\n    }\n}\n\n/// Convenience function to train a decision tree and make predictions\npub fn decision_tree(\n    training_data: Vec<(Vec<f64>, f64)>,\n    test_point: Vec<f64>,\n    max_depth: usize,\n    min_samples_split: usize,\n) -> Option<f64> {\n    let model = DecisionTree::fit(training_data, max_depth, min_samples_split)?;\n    model.predict(&test_point)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_decision_tree_simple_xor() {\n        let training_data = vec![\n            (vec![0.0, 0.0], 0.0),\n            (vec![0.0, 1.0], 1.0),\n            (vec![1.0, 0.0], 1.0),\n            (vec![1.0, 1.0], 0.0),\n        ];\n\n        let model = DecisionTree::fit(training_data, 10, 2);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        // XOR is difficult for decision trees with small dataset\n        // Just verify the model can make predictions (not necessarily perfect for XOR)\n        let result = model.predict(&[0.0, 0.0]);\n        assert!(result.is_some());\n\n        let result = model.predict(&[1.0, 1.0]);\n        assert!(result.is_some());\n    }\n\n    #[test]\n    fn test_decision_tree_linearly_separable() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![3.0, 3.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n            (vec![7.0, 7.0], 1.0),\n        ];\n\n        let model = DecisionTree::fit(training_data, 10, 2);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        assert_eq!(model.predict(&[1.5, 1.5]), Some(0.0));\n        assert_eq!(model.predict(&[5.5, 5.5]), Some(1.0));\n    }\n\n    #[test]\n    fn test_decision_tree_one_feature() {\n        let training_data = vec![\n            (vec![1.0], 0.0),\n            (vec![2.0], 0.0),\n            (vec![3.0], 0.0),\n            (vec![5.0], 1.0),\n            (vec![6.0], 1.0),\n            (vec![7.0], 1.0),\n        ];\n\n        let model = DecisionTree::fit(training_data, 10, 2);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        assert_eq!(model.predict(&[2.5]), Some(0.0));\n        assert_eq!(model.predict(&[5.5]), Some(1.0));\n    }\n\n    #[test]\n    fn test_decision_tree_multiple_classes() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n            (vec![9.0, 9.0], 2.0),\n            (vec![10.0, 10.0], 2.0),\n        ];\n\n        let model = DecisionTree::fit(training_data, 10, 2);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        assert_eq!(model.predict(&[1.5, 1.5]), Some(0.0));\n        assert_eq!(model.predict(&[5.5, 5.5]), Some(1.0));\n        assert_eq!(model.predict(&[9.5, 9.5]), Some(2.0));\n    }\n\n    #[test]\n    fn test_decision_tree_empty_training_data() {\n        let training_data = vec![];\n        let model = DecisionTree::fit(training_data, 10, 2);\n        assert_eq!(model, None);\n    }\n\n    #[test]\n    fn test_decision_tree_empty_features() {\n        let training_data = vec![(vec![], 0.0), (vec![], 1.0)];\n        let model = DecisionTree::fit(training_data, 10, 2);\n        assert_eq!(model, None);\n    }\n\n    #[test]\n    fn test_decision_tree_max_depth() {\n        let training_data = vec![\n            (vec![0.0, 0.0], 0.0),\n            (vec![0.0, 1.0], 1.0),\n            (vec![1.0, 0.0], 1.0),\n            (vec![1.0, 1.0], 0.0),\n        ];\n\n        let model = DecisionTree::fit(training_data, 1, 2);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n        let result = model.predict(&[0.5, 0.5]);\n        assert!(result.is_some());\n    }\n\n    #[test]\n    fn test_decision_tree_min_samples_split() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n        ];\n\n        let model = DecisionTree::fit(training_data, 10, 10);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n        let result = model.predict(&[1.5, 1.5]);\n        assert!(result.is_some());\n    }\n\n    #[test]\n    fn test_decision_tree_predict_batch() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n        ];\n\n        let model = DecisionTree::fit(training_data, 10, 2);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        let test_points = vec![vec![1.5, 1.5], vec![5.5, 5.5]];\n        let predictions = model.predict_batch(&test_points);\n\n        assert_eq!(predictions.len(), 2);\n        assert_eq!(predictions[0], Some(0.0));\n        assert_eq!(predictions[1], Some(1.0));\n    }\n\n    #[test]\n    fn test_decision_tree_convenience_function() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n        ];\n\n        let result = decision_tree(training_data, vec![1.5, 1.5], 10, 2);\n        assert_eq!(result, Some(0.0));\n\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n        ];\n\n        let result = decision_tree(training_data, vec![5.5, 5.5], 10, 2);\n        assert_eq!(result, Some(1.0));\n    }\n\n    #[test]\n    fn test_calculate_entropy() {\n        let labels = vec![0.0, 0.0, 0.0, 0.0];\n        let entropy = calculate_entropy(&labels);\n        assert!((entropy - 0.0).abs() < 1e-10);\n\n        let labels = vec![0.0, 0.0, 1.0, 1.0];\n        let entropy = calculate_entropy(&labels);\n        assert!((entropy - 1.0).abs() < 1e-10);\n\n        let labels = vec![0.0, 1.0, 2.0];\n        let entropy = calculate_entropy(&labels);\n        assert!(entropy > 0.0 && entropy < 2.0);\n    }\n\n    #[test]\n    fn test_get_majority_class() {\n        let labels = vec![0.0, 0.0, 1.0, 1.0, 0.0];\n        let majority = get_majority_class(&labels);\n        assert_eq!(majority, 0.0);\n\n        let labels = vec![1.0, 1.0, 2.0, 2.0, 2.0];\n        let majority = get_majority_class(&labels);\n        assert_eq!(majority, 2.0);\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/k_means.rs",
    "content": "use rand::random;\n\nfn get_distance(p1: &(f64, f64), p2: &(f64, f64)) -> f64 {\n    let dx: f64 = p1.0 - p2.0;\n    let dy: f64 = p1.1 - p2.1;\n\n    ((dx * dx) + (dy * dy)).sqrt()\n}\n\nfn find_nearest(data_point: &(f64, f64), centroids: &[(f64, f64)]) -> u32 {\n    let mut cluster: u32 = 0;\n\n    for (i, c) in centroids.iter().enumerate() {\n        let d1 = get_distance(data_point, c);\n        let d2 = get_distance(data_point, &centroids[cluster as usize]);\n\n        if d1 < d2 {\n            cluster = i as u32;\n        }\n    }\n\n    cluster\n}\n\npub fn k_means(data_points: Vec<(f64, f64)>, n_clusters: usize, max_iter: i32) -> Option<Vec<u32>> {\n    if data_points.len() < n_clusters {\n        return None;\n    }\n\n    let mut centroids: Vec<(f64, f64)> = Vec::new();\n    let mut labels: Vec<u32> = vec![0; data_points.len()];\n\n    for _ in 0..n_clusters {\n        let x: f64 = random::<f64>();\n        let y: f64 = random::<f64>();\n\n        centroids.push((x, y));\n    }\n\n    let mut count_iter: i32 = 0;\n\n    while count_iter < max_iter {\n        let mut new_centroids_position: Vec<(f64, f64)> = vec![(0.0, 0.0); n_clusters];\n        let mut new_centroids_num: Vec<u32> = vec![0; n_clusters];\n\n        for (i, d) in data_points.iter().enumerate() {\n            let nearest_cluster = find_nearest(d, &centroids);\n            labels[i] = nearest_cluster;\n\n            new_centroids_position[nearest_cluster as usize].0 += d.0;\n            new_centroids_position[nearest_cluster as usize].1 += d.1;\n            new_centroids_num[nearest_cluster as usize] += 1;\n        }\n\n        for i in 0..centroids.len() {\n            if new_centroids_num[i] == 0 {\n                continue;\n            }\n\n            let new_x: f64 = new_centroids_position[i].0 / new_centroids_num[i] as f64;\n            let new_y: f64 = new_centroids_position[i].1 / new_centroids_num[i] as f64;\n\n            centroids[i] = (new_x, new_y);\n        }\n\n        count_iter += 1;\n    }\n\n    Some(labels)\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_k_means() {\n        let mut data_points: Vec<(f64, f64)> = vec![];\n        let n_points: usize = 1000;\n\n        for _ in 0..n_points {\n            let x: f64 = random::<f64>() * 100.0;\n            let y: f64 = random::<f64>() * 100.0;\n\n            data_points.push((x, y));\n        }\n\n        println!(\"{:?}\", k_means(data_points, 10, 100).unwrap_or_default());\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/k_nearest_neighbors.rs",
    "content": "/// K-Nearest Neighbors (KNN) algorithm for classification.\n/// KNN is a simple, instance-based learning algorithm that classifies\n/// a data point based on the majority class of its k nearest neighbors.\n\nfn euclidean_distance(p1: &[f64], p2: &[f64]) -> f64 {\n    if p1.len() != p2.len() {\n        return f64::INFINITY;\n    }\n\n    p1.iter()\n        .zip(p2.iter())\n        .map(|(a, b)| (a - b).powi(2))\n        .sum::<f64>()\n        .sqrt()\n}\n\npub fn k_nearest_neighbors(\n    training_data: Vec<(Vec<f64>, f64)>,\n    test_point: Vec<f64>,\n    k: usize,\n) -> Option<f64> {\n    if training_data.is_empty() || k == 0 || k > training_data.len() {\n        return None;\n    }\n\n    let mut distances: Vec<(f64, f64)> = training_data\n        .iter()\n        .map(|(features, label)| (euclidean_distance(&test_point, features), *label))\n        .collect();\n\n    distances.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));\n\n    let k_nearest = &distances[..k];\n\n    let mut label_counts: Vec<(f64, usize)> = Vec::new();\n    for (_, label) in k_nearest {\n        let found = label_counts\n            .iter_mut()\n            .find(|(l, _)| (l - label).abs() < 1e-10);\n        if let Some((_, count)) = found {\n            *count += 1;\n        } else {\n            label_counts.push((*label, 1));\n        }\n    }\n\n    label_counts\n        .iter()\n        .max_by_key(|(_, count)| *count)\n        .map(|(label, _)| *label)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_standard_knn() {\n        let training_data = vec![\n            (vec![0.0, 0.0], 0.0),\n            (vec![1.0, 0.0], 0.0),\n            (vec![0.0, 1.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 5.0], 1.0),\n            (vec![5.0, 6.0], 1.0),\n        ];\n\n        let test_point = vec![0.5, 0.5];\n        let result = k_nearest_neighbors(training_data.clone(), test_point, 3);\n        assert_eq!(result, Some(0.0));\n\n        let test_point = vec![5.5, 5.5];\n        let result = k_nearest_neighbors(training_data, test_point, 3);\n        assert_eq!(result, Some(1.0));\n    }\n\n    #[test]\n    fn test_one_dimensional_knn() {\n        let training_data = vec![\n            (vec![1.0], 0.0),\n            (vec![2.0], 0.0),\n            (vec![3.0], 0.0),\n            (vec![8.0], 1.0),\n            (vec![9.0], 1.0),\n            (vec![10.0], 1.0),\n        ];\n\n        let test_point = vec![2.5];\n        let result = k_nearest_neighbors(training_data, test_point, 3);\n        assert_eq!(result, Some(0.0));\n    }\n\n    #[test]\n    fn test_knn_empty_data() {\n        let training_data = vec![];\n        let test_point = vec![1.0, 2.0];\n        let result = k_nearest_neighbors(training_data, test_point, 3);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_knn_invalid_k() {\n        let training_data = vec![(vec![1.0], 0.0), (vec![2.0], 1.0)];\n        let test_point = vec![1.5];\n\n        // k = 0 should return None\n        let result = k_nearest_neighbors(training_data.clone(), test_point.clone(), 0);\n        assert_eq!(result, None);\n\n        // k > training_data.len() should return None\n        let result = k_nearest_neighbors(training_data, test_point, 10);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_euclidean_distance_different_dimensions() {\n        let training_data = vec![\n            (vec![1.0, 2.0], 0.0),\n            (vec![2.0, 3.0], 0.0),\n            (vec![5.0], 1.0),\n        ];\n        let test_point = vec![1.5, 2.5];\n        let result = k_nearest_neighbors(training_data, test_point, 2);\n        assert_eq!(result, Some(0.0));\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/linear_regression.rs",
    "content": "/// Returns the parameters of the line after performing simple linear regression on the input data.\npub fn linear_regression(data_points: Vec<(f64, f64)>) -> Option<(f64, f64)> {\n    if data_points.is_empty() {\n        return None;\n    }\n\n    let count = data_points.len() as f64;\n    let mean_x = data_points.iter().fold(0.0, |sum, y| sum + y.0) / count;\n    let mean_y = data_points.iter().fold(0.0, |sum, y| sum + y.1) / count;\n\n    let mut covariance = 0.0;\n    let mut std_dev_sqr_x = 0.0;\n    let mut std_dev_sqr_y = 0.0;\n\n    for data_point in data_points {\n        covariance += (data_point.0 - mean_x) * (data_point.1 - mean_y);\n        std_dev_sqr_x += (data_point.0 - mean_x).powi(2);\n        std_dev_sqr_y += (data_point.1 - mean_y).powi(2);\n    }\n\n    let std_dev_x = std_dev_sqr_x.sqrt();\n    let std_dev_y = std_dev_sqr_y.sqrt();\n    let std_dev_prod = std_dev_x * std_dev_y;\n\n    let pcc = covariance / std_dev_prod; //Pearson's correlation constant\n    let b = pcc * (std_dev_y / std_dev_x); //Slope of the line\n    let a = mean_y - b * mean_x; //Y-Intercept of the line\n\n    Some((a, b))\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_linear_regression() {\n        assert_eq!(\n            linear_regression(vec![(0.0, 0.0), (1.0, 1.0), (2.0, 2.0)]),\n            Some((2.220446049250313e-16, 0.9999999999999998))\n        );\n    }\n\n    #[test]\n    fn test_empty_list_linear_regression() {\n        assert_eq!(linear_regression(vec![]), None);\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/logistic_regression.rs",
    "content": "use super::optimization::gradient_descent;\nuse std::f64::consts::E;\n\n/// Returns the weights after performing Logistic regression on the input data points.\npub fn logistic_regression(\n    data_points: Vec<(Vec<f64>, f64)>,\n    iterations: usize,\n    learning_rate: f64,\n) -> Option<Vec<f64>> {\n    if data_points.is_empty() {\n        return None;\n    }\n\n    let num_features = data_points[0].0.len() + 1;\n    let mut params = vec![0.0; num_features];\n\n    let derivative_fn = |params: &[f64]| derivative(params, &data_points);\n\n    gradient_descent(derivative_fn, &mut params, learning_rate, iterations as i32);\n\n    Some(params)\n}\n\nfn derivative(params: &[f64], data_points: &[(Vec<f64>, f64)]) -> Vec<f64> {\n    let num_features = params.len();\n    let mut gradients = vec![0.0; num_features];\n\n    for (features, y_i) in data_points {\n        let z = params[0]\n            + params[1..]\n                .iter()\n                .zip(features)\n                .map(|(p, x)| p * x)\n                .sum::<f64>();\n        let prediction = 1.0 / (1.0 + E.powf(-z));\n\n        gradients[0] += prediction - y_i;\n        for (i, x_i) in features.iter().enumerate() {\n            gradients[i + 1] += (prediction - y_i) * x_i;\n        }\n    }\n\n    gradients\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_logistic_regression_simple() {\n        let data = vec![\n            (vec![0.0], 0.0),\n            (vec![1.0], 0.0),\n            (vec![2.0], 0.0),\n            (vec![3.0], 1.0),\n            (vec![4.0], 1.0),\n            (vec![5.0], 1.0),\n        ];\n\n        let result = logistic_regression(data, 10000, 0.05);\n        assert!(result.is_some());\n\n        let params = result.unwrap();\n        assert!((params[0] + 17.65).abs() < 1.0);\n        assert!((params[1] - 7.13).abs() < 1.0);\n    }\n\n    #[test]\n    fn test_logistic_regression_extreme_data() {\n        let data = vec![\n            (vec![-100.0], 0.0),\n            (vec![-10.0], 0.0),\n            (vec![0.0], 0.0),\n            (vec![10.0], 1.0),\n            (vec![100.0], 1.0),\n        ];\n\n        let result = logistic_regression(data, 10000, 0.05);\n        assert!(result.is_some());\n\n        let params = result.unwrap();\n        assert!((params[0] + 6.20).abs() < 1.0);\n        assert!((params[1] - 5.5).abs() < 1.0);\n    }\n\n    #[test]\n    fn test_logistic_regression_no_data() {\n        let result = logistic_regression(vec![], 5000, 0.1);\n        assert_eq!(result, None);\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/loss_function/average_margin_ranking_loss.rs",
    "content": "/// Marginal Ranking\n///\n/// The 'average_margin_ranking_loss' function calculates the Margin Ranking loss, which is a\n/// loss function used for ranking problems in machine learning.\n///\n/// ## Formula\n///\n/// For a pair of values `x_first` and `x_second`, `margin`, and `y_true`,\n/// the Margin Ranking loss is calculated as:\n///\n///  - loss = `max(0, -y_true * (x_first - x_second) + margin)`.\n///\n/// It returns the average loss by dividing the `total_loss` by total no. of\n/// elements.\n///\n/// Pytorch implementation:\n/// https://pytorch.org/docs/stable/generated/torch.nn.MarginRankingLoss.html\n/// https://gombru.github.io/2019/04/03/ranking_loss/\n/// https://vinija.ai/concepts/loss/#pairwise-ranking-loss\n///\n\npub fn average_margin_ranking_loss(\n    x_first: &[f64],\n    x_second: &[f64],\n    margin: f64,\n    y_true: f64,\n) -> Result<f64, MarginalRankingLossError> {\n    check_input(x_first, x_second, margin, y_true)?;\n\n    let total_loss: f64 = x_first\n        .iter()\n        .zip(x_second.iter())\n        .map(|(f, s)| (margin - y_true * (f - s)).max(0.0))\n        .sum();\n    Ok(total_loss / (x_first.len() as f64))\n}\n\nfn check_input(\n    x_first: &[f64],\n    x_second: &[f64],\n    margin: f64,\n    y_true: f64,\n) -> Result<(), MarginalRankingLossError> {\n    if x_first.len() != x_second.len() {\n        return Err(MarginalRankingLossError::InputsHaveDifferentLength);\n    }\n    if x_first.is_empty() {\n        return Err(MarginalRankingLossError::EmptyInputs);\n    }\n    if margin < 0.0 {\n        return Err(MarginalRankingLossError::NegativeMargin);\n    }\n    if y_true != 1.0 && y_true != -1.0 {\n        return Err(MarginalRankingLossError::InvalidValues);\n    }\n\n    Ok(())\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub enum MarginalRankingLossError {\n    InputsHaveDifferentLength,\n    EmptyInputs,\n    InvalidValues,\n    NegativeMargin,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_with_wrong_inputs {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (vec_a, vec_b, margin, y_true, expected) = $inputs;\n                    assert_eq!(average_margin_ranking_loss(&vec_a, &vec_b, margin, y_true), expected);\n                    assert_eq!(average_margin_ranking_loss(&vec_b, &vec_a, margin, y_true), expected);\n                }\n            )*\n        }\n    }\n\n    test_with_wrong_inputs! {\n        invalid_length0: (vec![1.0, 2.0, 3.0], vec![2.0, 3.0], 1.0, 1.0, Err(MarginalRankingLossError::InputsHaveDifferentLength)),\n        invalid_length1: (vec![1.0, 2.0], vec![2.0, 3.0, 4.0], 1.0, 1.0, Err(MarginalRankingLossError::InputsHaveDifferentLength)),\n        invalid_length2: (vec![], vec![1.0, 2.0, 3.0], 1.0, 1.0, Err(MarginalRankingLossError::InputsHaveDifferentLength)),\n        invalid_length3: (vec![1.0, 2.0, 3.0], vec![], 1.0, 1.0, Err(MarginalRankingLossError::InputsHaveDifferentLength)),\n        invalid_values: (vec![1.0, 2.0, 3.0], vec![2.0, 3.0, 4.0], -1.0, 1.0, Err(MarginalRankingLossError::NegativeMargin)),\n        invalid_y_true: (vec![1.0, 2.0, 3.0], vec![2.0, 3.0, 4.0], 1.0, 2.0, Err(MarginalRankingLossError::InvalidValues)),\n        empty_inputs: (vec![], vec![], 1.0, 1.0, Err(MarginalRankingLossError::EmptyInputs)),\n    }\n\n    macro_rules! test_average_margin_ranking_loss {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (x_first, x_second, margin, y_true, expected) = $inputs;\n                    assert_eq!(average_margin_ranking_loss(&x_first, &x_second, margin, y_true), Ok(expected));\n                }\n            )*\n        }\n    }\n\n    test_average_margin_ranking_loss! {\n        set_0: (vec![1.0, 2.0, 3.0], vec![2.0, 3.0, 4.0], 1.0, -1.0, 0.0),\n        set_1: (vec![1.0, 2.0, 3.0], vec![2.0, 3.0, 4.0], 1.0, 1.0, 2.0),\n        set_2: (vec![1.0, 2.0, 3.0], vec![1.0, 2.0, 3.0], 0.0, 1.0, 0.0),\n        set_3: (vec![4.0, 5.0, 6.0], vec![1.0, 2.0, 3.0], 1.0, -1.0, 4.0),\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/loss_function/hinge_loss.rs",
    "content": "//! # Hinge Loss\n//!\n//! The `hng_loss` function calculates the Hinge loss, which is a\n//! loss function used for classification problems in machine learning.\n//!\n//! ## Formula\n//!\n//! For a pair of actual and predicted values, represented as vectors `y_true` and\n//! `y_pred`, the Hinge loss is calculated as:\n//!\n//! - loss = `max(0, 1 - y_true * y_pred)`.\n//!\n//! It returns the average loss by dividing the `total_loss` by total no. of\n//! elements.\n//!\npub fn hng_loss(y_true: &[f64], y_pred: &[f64]) -> f64 {\n    let mut total_loss: f64 = 0.0;\n    for (p, a) in y_pred.iter().zip(y_true.iter()) {\n        let loss = (1.0 - a * p).max(0.0);\n        total_loss += loss;\n    }\n    total_loss / (y_pred.len() as f64)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_hinge_loss() {\n        let predicted_values: Vec<f64> = vec![-1.0, 1.0, 1.0];\n        let actual_values: Vec<f64> = vec![-1.0, -1.0, 1.0];\n        assert_eq!(\n            hng_loss(&predicted_values, &actual_values),\n            0.6666666666666666\n        );\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/loss_function/huber_loss.rs",
    "content": "/// Computes the Huber loss between arrays of true and predicted values.\n///\n/// # Arguments\n///\n/// * `y_true` - An array of true values.\n/// * `y_pred` - An array of predicted values.\n/// * `delta` - The threshold parameter that controls the linear behavior of the loss function.\n///\n/// # Returns\n///\n/// The average Huber loss for all pairs of true and predicted values.\npub fn huber_loss(y_true: &[f64], y_pred: &[f64], delta: f64) -> Option<f64> {\n    if y_true.len() != y_pred.len() || y_pred.is_empty() {\n        return None;\n    }\n\n    let loss: f64 = y_true\n        .iter()\n        .zip(y_pred.iter())\n        .map(|(&true_val, &pred_val)| {\n            let residual = (true_val - pred_val).abs();\n            match residual {\n                r if r <= delta => 0.5 * r.powi(2),\n                _ => delta * residual - 0.5 * delta.powi(2),\n            }\n        })\n        .sum();\n\n    Some(loss / (y_pred.len() as f64))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! huber_loss_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (y_true, y_pred, delta, expected_loss) = $test_case;\n                    assert_eq!(huber_loss(&y_true, &y_pred, delta), expected_loss);\n                }\n            )*\n        };\n    }\n\n    huber_loss_tests! {\n        test_huber_loss_residual_less_than_delta: (\n            vec![10.0, 8.0, 12.0],\n            vec![9.0, 7.0, 11.0],\n            1.0,\n            Some(0.5)\n        ),\n        test_huber_loss_residual_greater_than_delta: (\n            vec![3.0, 5.0, 7.0],\n            vec![2.0, 4.0, 8.0],\n            0.5,\n            Some(0.375)\n        ),\n        test_huber_loss_invalid_length: (\n            vec![10.0, 8.0, 12.0],\n            vec![7.0, 6.0],\n            1.0,\n            None\n        ),\n        test_huber_loss_empty_prediction: (\n            vec![10.0, 8.0, 12.0],\n            vec![],\n            1.0,\n            None\n        ),\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/loss_function/kl_divergence_loss.rs",
    "content": "//! # KL divergence Loss Function\n//!\n//! For a pair of actual and predicted probability distributions represented as vectors `actual` and `predicted`, the KL divergence loss is calculated as:\n//!\n//! `L = -Σ(actual[i] * ln(predicted[i]/actual[i]))` for all `i` in the range of the vectors\n//!\n//! Where `ln` is the natural logarithm function, and `Σ` denotes the summation over all elements of the vectors.\n//!\n//! ## KL divergence Loss Function Implementation\n//!\n//! This implementation takes two references to vectors of f64 values, `actual` and `predicted`, and returns the KL divergence loss between them.\n//!\npub fn kld_loss(actual: &[f64], predicted: &[f64]) -> f64 {\n    // epsilon to handle if any of the elements are zero\n    let eps = 0.00001f64;\n    let loss: f64 = actual\n        .iter()\n        .zip(predicted.iter())\n        .map(|(&a, &p)| (a + eps) * ((a + eps) / (p + eps)).ln())\n        .sum();\n    loss\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_kld_loss() {\n        let test_vector_actual = vec![1.346112, 1.337432, 1.246655];\n        let test_vector = vec![1.033836, 1.082015, 1.117323];\n        assert_eq!(\n            kld_loss(&test_vector_actual, &test_vector),\n            0.7752789394328498\n        );\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/loss_function/mean_absolute_error_loss.rs",
    "content": "//! # Mean Absolute Error Loss Function\n//!\n//! The `mae_loss` function calculates the Mean Absolute Error loss, which is a\n//! robust loss function used in machine learning.\n//!\n//! ## Formula\n//!\n//! For a pair of actual and predicted values, represented as vectors `actual`\n//! and `predicted`, the Mean Absolute  loss is calculated as:\n//!\n//! - loss = `(actual - predicted) / n_elements`.\n//!\n//! It returns the average loss by dividing the `total_loss` by total no. of\n//! elements.\n//!\npub fn mae_loss(predicted: &[f64], actual: &[f64]) -> f64 {\n    let mut total_loss: f64 = 0.0;\n    for (p, a) in predicted.iter().zip(actual.iter()) {\n        let diff: f64 = p - a;\n        let absolute_diff = diff.abs();\n        total_loss += absolute_diff;\n    }\n    total_loss / (predicted.len() as f64)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_mae_loss() {\n        let predicted_values: Vec<f64> = vec![1.0, 2.0, 3.0, 4.0];\n        let actual_values: Vec<f64> = vec![1.0, 3.0, 3.5, 4.5];\n        assert_eq!(mae_loss(&predicted_values, &actual_values), 0.5);\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/loss_function/mean_squared_error_loss.rs",
    "content": "//! # Mean Square Loss Function\n//!\n//! The `mse_loss` function calculates the Mean Square Error loss, which is a\n//! robust loss function used in machine learning.\n//!\n//! ## Formula\n//!\n//! For a pair of actual and predicted values, represented as vectors `actual`\n//! and `predicted`, the Mean Square  loss is calculated as:\n//!\n//! - loss = `(actual - predicted)^2 / n_elements`.\n//!\n//! It returns the average loss by dividing the `total_loss` by total no. of\n//! elements.\n//!\npub fn mse_loss(predicted: &[f64], actual: &[f64]) -> f64 {\n    let mut total_loss: f64 = 0.0;\n    for (p, a) in predicted.iter().zip(actual.iter()) {\n        let diff: f64 = p - a;\n        total_loss += diff * diff;\n    }\n    total_loss / (predicted.len() as f64)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_mse_loss() {\n        let predicted_values: Vec<f64> = vec![1.0, 2.0, 3.0, 4.0];\n        let actual_values: Vec<f64> = vec![1.0, 3.0, 3.5, 4.5];\n        assert_eq!(mse_loss(&predicted_values, &actual_values), 0.375);\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/loss_function/mod.rs",
    "content": "mod average_margin_ranking_loss;\nmod hinge_loss;\nmod huber_loss;\nmod kl_divergence_loss;\nmod mean_absolute_error_loss;\nmod mean_squared_error_loss;\nmod negative_log_likelihood;\n\npub use self::average_margin_ranking_loss::average_margin_ranking_loss;\npub use self::hinge_loss::hng_loss;\npub use self::huber_loss::huber_loss;\npub use self::kl_divergence_loss::kld_loss;\npub use self::mean_absolute_error_loss::mae_loss;\npub use self::mean_squared_error_loss::mse_loss;\npub use self::negative_log_likelihood::neg_log_likelihood;\n"
  },
  {
    "path": "src/machine_learning/loss_function/negative_log_likelihood.rs",
    "content": "// Negative Log Likelihood Loss Function\n//\n// The `neg_log_likelihood` function calculates the Negative Log Likelyhood loss,\n// which is a loss function used for classification problems in machine learning.\n//\n// ## Formula\n//\n// For a pair of actual and predicted values, represented as vectors `y_true` and\n// `y_pred`, the Negative Log Likelihood loss is calculated as:\n//\n// - loss = `-y_true * log(y_pred) - (1 - y_true) * log(1 - y_pred)`.\n//\n// It returns the average loss by dividing the `total_loss` by total no. of\n// elements.\n//\n// https://towardsdatascience.com/cross-entropy-negative-log-likelihood-and-all-that-jazz-47a95bd2e81\n// http://neuralnetworksanddeeplearning.com/chap3.html\n// Derivation of the formula:\n// https://medium.com/@bhardwajprakarsh/negative-log-likelihood-loss-why-do-we-use-it-for-binary-classification-7625f9e3c944\n\npub fn neg_log_likelihood(\n    y_true: &[f64],\n    y_pred: &[f64],\n) -> Result<f64, NegativeLogLikelihoodLossError> {\n    // Checks if the inputs are empty\n    if y_true.len() != y_pred.len() {\n        return Err(NegativeLogLikelihoodLossError::InputsHaveDifferentLength);\n    }\n    // Checks if the length of the actual and predicted values are equal\n    if y_pred.is_empty() {\n        return Err(NegativeLogLikelihoodLossError::EmptyInputs);\n    }\n    // Checks values are between 0 and 1\n    if !are_all_values_in_range(y_true) || !are_all_values_in_range(y_pred) {\n        return Err(NegativeLogLikelihoodLossError::InvalidValues);\n    }\n\n    let mut total_loss: f64 = 0.0;\n    for (p, a) in y_pred.iter().zip(y_true.iter()) {\n        let loss: f64 = -a * p.ln() - (1.0 - a) * (1.0 - p).ln();\n        total_loss += loss;\n    }\n    Ok(total_loss / (y_pred.len() as f64))\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub enum NegativeLogLikelihoodLossError {\n    InputsHaveDifferentLength,\n    EmptyInputs,\n    InvalidValues,\n}\n\nfn are_all_values_in_range(values: &[f64]) -> bool {\n    values.iter().all(|&x| (0.0..=1.0).contains(&x))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_with_wrong_inputs {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (values_a, values_b, expected_error) = $inputs;\n                    assert_eq!(neg_log_likelihood(&values_a, &values_b), expected_error);\n                    assert_eq!(neg_log_likelihood(&values_b, &values_a), expected_error);\n                }\n            )*\n        }\n    }\n\n    test_with_wrong_inputs! {\n        different_length: (vec![0.9, 0.0, 0.8], vec![0.9, 0.1], Err(NegativeLogLikelihoodLossError::InputsHaveDifferentLength)),\n        different_length_one_empty: (vec![], vec![0.9, 0.1], Err(NegativeLogLikelihoodLossError::InputsHaveDifferentLength)),\n        value_greater_than_1: (vec![1.1, 0.0, 0.8], vec![0.1, 0.2, 0.3], Err(NegativeLogLikelihoodLossError::InvalidValues)),\n        value_greater_smaller_than_0: (vec![0.9, 0.0, -0.1], vec![0.1, 0.2, 0.3], Err(NegativeLogLikelihoodLossError::InvalidValues)),\n        empty_input: (vec![], vec![], Err(NegativeLogLikelihoodLossError::EmptyInputs)),\n    }\n\n    macro_rules! test_neg_log_likelihood {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (actual_values, predicted_values, expected) = $inputs;\n                    assert_eq!(neg_log_likelihood(&actual_values, &predicted_values).unwrap(), expected);\n                }\n            )*\n        }\n    }\n\n    test_neg_log_likelihood! {\n        set_0: (vec![1.0, 0.0, 1.0], vec![0.9, 0.1, 0.8], 0.14462152754328741),\n        set_1: (vec![1.0, 0.0, 1.0], vec![0.1, 0.2, 0.3], 1.2432338162113972),\n        set_2: (vec![0.0, 1.0, 0.0], vec![0.1, 0.2, 0.3], 0.6904911240102196),\n        set_3: (vec![1.0, 0.0, 1.0, 0.0], vec![0.9, 0.1, 0.8, 0.2], 0.164252033486018),\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/mod.rs",
    "content": "mod cholesky;\nmod decision_tree;\nmod k_means;\nmod k_nearest_neighbors;\nmod linear_regression;\nmod logistic_regression;\nmod loss_function;\nmod naive_bayes;\nmod optimization;\nmod perceptron;\nmod principal_component_analysis;\nmod random_forest;\nmod support_vector_classifier;\n\npub use self::cholesky::cholesky;\npub use self::decision_tree::decision_tree;\npub use self::k_means::k_means;\npub use self::k_nearest_neighbors::k_nearest_neighbors;\npub use self::linear_regression::linear_regression;\npub use self::logistic_regression::logistic_regression;\npub use self::loss_function::{\n    average_margin_ranking_loss, hng_loss, huber_loss, kld_loss, mae_loss, mse_loss,\n    neg_log_likelihood,\n};\npub use self::naive_bayes::naive_bayes;\npub use self::optimization::{gradient_descent, Adam};\npub use self::perceptron::{classify, perceptron};\npub use self::principal_component_analysis::principal_component_analysis;\npub use self::random_forest::random_forest;\npub use self::support_vector_classifier::{Kernel, SVCError, SVC};\n"
  },
  {
    "path": "src/machine_learning/naive_bayes.rs",
    "content": "/// Naive Bayes classifier for classification tasks.\n/// This implementation uses Gaussian Naive Bayes, which assumes that\n/// features follow a normal (Gaussian) distribution.\n/// The algorithm calculates class priors and feature statistics (mean and variance)\n/// for each class, then uses Bayes' theorem to predict class probabilities.\n\npub struct ClassStatistics {\n    pub class_label: f64,\n    pub prior: f64,\n    pub feature_means: Vec<f64>,\n    pub feature_variances: Vec<f64>,\n}\n\nfn calculate_class_statistics(\n    training_data: &[(Vec<f64>, f64)],\n    class_label: f64,\n    num_features: usize,\n) -> Option<ClassStatistics> {\n    let class_samples: Vec<&(Vec<f64>, f64)> = training_data\n        .iter()\n        .filter(|(_, label)| (*label - class_label).abs() < 1e-10)\n        .collect();\n\n    if class_samples.is_empty() {\n        return None;\n    }\n\n    let prior = class_samples.len() as f64 / training_data.len() as f64;\n\n    let mut feature_means = vec![0.0; num_features];\n    let mut feature_variances = vec![0.0; num_features];\n\n    // Calculate means\n    for (features, _) in &class_samples {\n        for (i, &feature) in features.iter().enumerate() {\n            if i < num_features {\n                feature_means[i] += feature;\n            }\n        }\n    }\n\n    let n = class_samples.len() as f64;\n    for mean in &mut feature_means {\n        *mean /= n;\n    }\n\n    // Calculate variances\n    for (features, _) in &class_samples {\n        for (i, &feature) in features.iter().enumerate() {\n            if i < num_features {\n                let diff = feature - feature_means[i];\n                feature_variances[i] += diff * diff;\n            }\n        }\n    }\n\n    let epsilon = 1e-9;\n    for variance in &mut feature_variances {\n        *variance = (*variance / n).max(epsilon);\n    }\n\n    Some(ClassStatistics {\n        class_label,\n        prior,\n        feature_means,\n        feature_variances,\n    })\n}\n\nfn gaussian_log_pdf(x: f64, mean: f64, variance: f64) -> f64 {\n    let diff = x - mean;\n    let exponent_term = -(diff * diff) / (2.0 * variance);\n    let log_coefficient = -0.5 * (2.0 * std::f64::consts::PI * variance).ln();\n    log_coefficient + exponent_term\n}\n\npub fn train_naive_bayes(training_data: Vec<(Vec<f64>, f64)>) -> Option<Vec<ClassStatistics>> {\n    if training_data.is_empty() {\n        return None;\n    }\n\n    let num_features = training_data[0].0.len();\n    if num_features == 0 {\n        return None;\n    }\n\n    // Verify all samples have the same number of features\n    if !training_data\n        .iter()\n        .all(|(features, _)| features.len() == num_features)\n    {\n        return None;\n    }\n\n    // Get unique class labels\n    let mut unique_classes = Vec::new();\n    for (_, label) in &training_data {\n        if !unique_classes\n            .iter()\n            .any(|&c: &f64| (c - *label).abs() < 1e-10)\n        {\n            unique_classes.push(*label);\n        }\n    }\n\n    let mut class_stats = Vec::new();\n\n    for class_label in unique_classes {\n        if let Some(mut stats) =\n            calculate_class_statistics(&training_data, class_label, num_features)\n        {\n            stats.class_label = class_label;\n            class_stats.push(stats);\n        }\n    }\n\n    if class_stats.is_empty() {\n        return None;\n    }\n\n    Some(class_stats)\n}\n\npub fn predict_naive_bayes(model: &[ClassStatistics], test_point: &[f64]) -> Option<f64> {\n    if model.is_empty() || test_point.is_empty() {\n        return None;\n    }\n\n    // Get number of features from the first class statistics\n    let num_features = model[0].feature_means.len();\n    if test_point.len() != num_features {\n        return None;\n    }\n\n    let mut best_class = None;\n    let mut best_log_prob = f64::NEG_INFINITY;\n\n    for stats in model {\n        // Calculate log probability to avoid underflow\n        let mut log_prob = stats.prior.ln();\n\n        for (i, &feature) in test_point.iter().enumerate() {\n            if i < stats.feature_means.len() && i < stats.feature_variances.len() {\n                // Use log PDF directly to avoid numerical underflow\n                log_prob +=\n                    gaussian_log_pdf(feature, stats.feature_means[i], stats.feature_variances[i]);\n            }\n        }\n\n        if log_prob > best_log_prob {\n            best_log_prob = log_prob;\n            best_class = Some(stats.class_label);\n        }\n    }\n\n    best_class\n}\n\npub fn naive_bayes(training_data: Vec<(Vec<f64>, f64)>, test_point: Vec<f64>) -> Option<f64> {\n    let model = train_naive_bayes(training_data)?;\n    predict_naive_bayes(&model, &test_point)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_naive_bayes_simple_classification() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![1.1, 1.0], 0.0),\n            (vec![1.0, 1.1], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![5.1, 5.0], 1.0),\n            (vec![5.0, 5.1], 1.0),\n        ];\n\n        // Test point closer to class 0\n        let test_point = vec![1.05, 1.05];\n        let result = naive_bayes(training_data.clone(), test_point);\n        assert_eq!(result, Some(0.0));\n\n        // Test point closer to class 1\n        let test_point = vec![5.05, 5.05];\n        let result = naive_bayes(training_data, test_point);\n        assert_eq!(result, Some(1.0));\n    }\n\n    #[test]\n    fn test_naive_bayes_one_dimensional() {\n        let training_data = vec![\n            (vec![1.0], 0.0),\n            (vec![1.1], 0.0),\n            (vec![1.2], 0.0),\n            (vec![5.0], 1.0),\n            (vec![5.1], 1.0),\n            (vec![5.2], 1.0),\n        ];\n\n        let test_point = vec![1.15];\n        let result = naive_bayes(training_data.clone(), test_point);\n        assert_eq!(result, Some(0.0));\n\n        let test_point = vec![5.15];\n        let result = naive_bayes(training_data, test_point);\n        assert_eq!(result, Some(1.0));\n    }\n\n    #[test]\n    fn test_naive_bayes_empty_training_data() {\n        let training_data = vec![];\n        let test_point = vec![1.0, 2.0];\n        let result = naive_bayes(training_data, test_point);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_naive_bayes_empty_test_point() {\n        let training_data = vec![(vec![1.0, 2.0], 0.0)];\n        let test_point = vec![];\n        let result = naive_bayes(training_data, test_point);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_naive_bayes_dimension_mismatch() {\n        let training_data = vec![(vec![1.0, 2.0], 0.0), (vec![3.0, 4.0], 1.0)];\n        let test_point = vec![1.0]; // Wrong dimension\n        let result = naive_bayes(training_data, test_point);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_naive_bayes_inconsistent_feature_dimensions() {\n        let training_data = vec![\n            (vec![1.0, 2.0], 0.0),\n            (vec![3.0], 1.0), // Different dimension\n        ];\n        let test_point = vec![1.0, 2.0];\n        let result = naive_bayes(training_data, test_point);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_naive_bayes_multiple_classes() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![1.1, 1.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![5.1, 5.0], 1.0),\n            (vec![9.0, 9.0], 2.0),\n            (vec![9.1, 9.0], 2.0),\n        ];\n\n        let test_point = vec![1.05, 1.05];\n        let result = naive_bayes(training_data.clone(), test_point);\n        assert_eq!(result, Some(0.0));\n\n        let test_point = vec![5.05, 5.05];\n        let result = naive_bayes(training_data.clone(), test_point);\n        assert_eq!(result, Some(1.0));\n\n        let test_point = vec![9.05, 9.05];\n        let result = naive_bayes(training_data, test_point);\n        assert_eq!(result, Some(2.0));\n    }\n\n    #[test]\n    fn test_train_and_predict_separately() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![1.1, 1.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![5.1, 5.0], 1.0),\n        ];\n\n        let model = train_naive_bayes(training_data);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n        assert_eq!(model.len(), 2);\n\n        let test_point = vec![1.05, 1.05];\n        let result = predict_naive_bayes(&model, &test_point);\n        assert_eq!(result, Some(0.0));\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/optimization/adam.rs",
    "content": "//! # Adam (Adaptive Moment Estimation) optimizer\n//!\n//! The `Adam (Adaptive Moment Estimation)` optimizer is an adaptive learning rate algorithm used\n//! in gradient descent and machine learning, such as for training neural networks to solve deep\n//! learning problems. Boasting memory-efficient fast convergence rates, it sets and iteratively\n//! updates learning rates individually for each model parameter based on the gradient history.\n//!\n//! ## Algorithm:\n//!\n//! Given:\n//!   - α is the learning rate\n//!   - (β_1, β_2) are the exponential decay rates for moment estimates\n//!   - ϵ is any small value to prevent division by zero\n//!   - g_t are the gradients at time step t\n//!   - m_t are the biased first moment estimates of the gradient at time step t\n//!   - v_t are the biased second raw moment estimates of the gradient at time step t\n//!   - θ_t are the model parameters at time step t\n//!   - t is the time step\n//!\n//! Required:\n//!   θ_0\n//!\n//! Initialize:\n//!   m_0 <- 0\n//!   v_0 <- 0\n//!   t <- 0\n//!\n//! while θ_t not converged do\n//!   m_t = β_1 * m_{t−1} + (1 − β_1) * g_t\n//!   v_t = β_2 * v_{t−1} + (1 − β_2) * g_t^2\n//!   m_hat_t = m_t / 1 - β_1^t\n//!   v_hat_t = v_t / 1 - β_2^t\n//!   θ_t = θ_{t-1} − α * m_hat_t / (sqrt(v_hat_t) + ϵ)\n//!\n//! ## Resources:\n//!   - Adam: A Method for Stochastic Optimization (by Diederik P. Kingma and Jimmy Ba):\n//!       - [https://arxiv.org/abs/1412.6980]\n//!   - PyTorch Adam optimizer:\n//!       - [https://pytorch.org/docs/stable/generated/torch.optim.Adam.html#torch.optim.Adam]\n//!\npub struct Adam {\n    learning_rate: f64, // alpha: initial step size for iterative optimization\n    betas: (f64, f64),  // betas: exponential decay rates for moment estimates\n    epsilon: f64,       // epsilon: prevent division by zero\n    m: Vec<f64>,        // m: biased first moment estimate of the gradient vector\n    v: Vec<f64>,        // v: biased second raw moment estimate of the gradient vector\n    t: usize,           // t: time step\n}\n\nimpl Adam {\n    pub fn new(\n        learning_rate: Option<f64>,\n        betas: Option<(f64, f64)>,\n        epsilon: Option<f64>,\n        params_len: usize,\n    ) -> Self {\n        Adam {\n            learning_rate: learning_rate.unwrap_or(1e-3), // typical good default lr\n            betas: betas.unwrap_or((0.9, 0.999)),         // typical good default decay rates\n            epsilon: epsilon.unwrap_or(1e-8),             // typical good default epsilon\n            m: vec![0.0; params_len], // first moment vector elements all initialized to zero\n            v: vec![0.0; params_len], // second moment vector elements all initialized to zero\n            t: 0,                     // time step initialized to zero\n        }\n    }\n\n    pub fn step(&mut self, gradients: &[f64]) -> Vec<f64> {\n        let mut model_params = vec![0.0; gradients.len()];\n        self.t += 1;\n\n        for i in 0..gradients.len() {\n            // update biased first moment estimate and second raw moment estimate\n            self.m[i] = self.betas.0 * self.m[i] + (1.0 - self.betas.0) * gradients[i];\n            self.v[i] = self.betas.1 * self.v[i] + (1.0 - self.betas.1) * gradients[i].powf(2f64);\n\n            // compute bias-corrected first moment estimate and second raw moment estimate\n            let m_hat = self.m[i] / (1.0 - self.betas.0.powi(self.t as i32));\n            let v_hat = self.v[i] / (1.0 - self.betas.1.powi(self.t as i32));\n\n            // update model parameters\n            model_params[i] -= self.learning_rate * m_hat / (v_hat.sqrt() + self.epsilon);\n        }\n        model_params // return updated model parameters\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_adam_init_default_values() {\n        let optimizer = Adam::new(None, None, None, 1);\n\n        assert_eq!(optimizer.learning_rate, 0.001);\n        assert_eq!(optimizer.betas, (0.9, 0.999));\n        assert_eq!(optimizer.epsilon, 1e-8);\n        assert_eq!(optimizer.m, vec![0.0; 1]);\n        assert_eq!(optimizer.v, vec![0.0; 1]);\n        assert_eq!(optimizer.t, 0);\n    }\n\n    #[test]\n    fn test_adam_init_custom_lr_value() {\n        let optimizer = Adam::new(Some(0.9), None, None, 2);\n\n        assert_eq!(optimizer.learning_rate, 0.9);\n        assert_eq!(optimizer.betas, (0.9, 0.999));\n        assert_eq!(optimizer.epsilon, 1e-8);\n        assert_eq!(optimizer.m, vec![0.0; 2]);\n        assert_eq!(optimizer.v, vec![0.0; 2]);\n        assert_eq!(optimizer.t, 0);\n    }\n\n    #[test]\n    fn test_adam_init_custom_betas_value() {\n        let optimizer = Adam::new(None, Some((0.8, 0.899)), None, 3);\n\n        assert_eq!(optimizer.learning_rate, 0.001);\n        assert_eq!(optimizer.betas, (0.8, 0.899));\n        assert_eq!(optimizer.epsilon, 1e-8);\n        assert_eq!(optimizer.m, vec![0.0; 3]);\n        assert_eq!(optimizer.v, vec![0.0; 3]);\n        assert_eq!(optimizer.t, 0);\n    }\n\n    #[test]\n    fn test_adam_init_custom_epsilon_value() {\n        let optimizer = Adam::new(None, None, Some(1e-10), 4);\n\n        assert_eq!(optimizer.learning_rate, 0.001);\n        assert_eq!(optimizer.betas, (0.9, 0.999));\n        assert_eq!(optimizer.epsilon, 1e-10);\n        assert_eq!(optimizer.m, vec![0.0; 4]);\n        assert_eq!(optimizer.v, vec![0.0; 4]);\n        assert_eq!(optimizer.t, 0);\n    }\n\n    #[test]\n    fn test_adam_init_all_custom_values() {\n        let optimizer = Adam::new(Some(1.0), Some((0.001, 0.099)), Some(1e-1), 5);\n\n        assert_eq!(optimizer.learning_rate, 1.0);\n        assert_eq!(optimizer.betas, (0.001, 0.099));\n        assert_eq!(optimizer.epsilon, 1e-1);\n        assert_eq!(optimizer.m, vec![0.0; 5]);\n        assert_eq!(optimizer.v, vec![0.0; 5]);\n        assert_eq!(optimizer.t, 0);\n    }\n\n    #[test]\n    fn test_adam_step_default_params() {\n        let gradients = vec![-1.0, 2.0, -3.0, 4.0, -5.0, 6.0, -7.0, 8.0];\n\n        let mut optimizer = Adam::new(None, None, None, 8);\n        let updated_params = optimizer.step(&gradients);\n\n        assert_eq!(\n            updated_params,\n            vec![\n                0.0009999999900000003,\n                -0.000999999995,\n                0.0009999999966666666,\n                -0.0009999999975,\n                0.000999999998,\n                -0.0009999999983333334,\n                0.0009999999985714286,\n                -0.00099999999875\n            ]\n        );\n    }\n\n    #[test]\n    fn test_adam_step_custom_params() {\n        let gradients = vec![9.0, -8.0, 7.0, -6.0, 5.0, -4.0, 3.0, -2.0, 1.0];\n\n        let mut optimizer = Adam::new(Some(0.005), Some((0.5, 0.599)), Some(1e-5), 9);\n        let updated_params = optimizer.step(&gradients);\n\n        assert_eq!(\n            updated_params,\n            vec![\n                -0.004999994444450618,\n                0.004999993750007813,\n                -0.004999992857153062,\n                0.004999991666680556,\n                -0.004999990000020001,\n                0.004999987500031251,\n                -0.004999983333388888,\n                0.004999975000124999,\n                -0.0049999500004999945\n            ]\n        );\n    }\n\n    #[test]\n    fn test_adam_step_empty_gradients_array() {\n        let gradients = vec![];\n\n        let mut optimizer = Adam::new(None, None, None, 0);\n        let updated_params = optimizer.step(&gradients);\n\n        assert_eq!(updated_params, vec![]);\n    }\n\n    #[ignore]\n    #[test]\n    fn test_adam_step_iteratively_until_convergence_with_default_params() {\n        const CONVERGENCE_THRESHOLD: f64 = 1e-5;\n        let gradients = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];\n\n        let mut optimizer = Adam::new(None, None, None, 6);\n\n        let mut model_params = vec![0.0; 6];\n        let mut updated_params = optimizer.step(&gradients);\n\n        while (updated_params\n            .iter()\n            .zip(model_params.iter())\n            .map(|(x, y)| x - y)\n            .collect::<Vec<f64>>())\n        .iter()\n        .map(|&x| x.powi(2))\n        .sum::<f64>()\n        .sqrt()\n            > CONVERGENCE_THRESHOLD\n        {\n            model_params = updated_params;\n            updated_params = optimizer.step(&gradients);\n        }\n\n        assert!(updated_params < vec![CONVERGENCE_THRESHOLD; 6]);\n        assert_ne!(updated_params, model_params);\n        assert_eq!(\n            updated_params,\n            vec![\n                -0.0009999999899999931,\n                -0.0009999999949999929,\n                -0.0009999999966666597,\n                -0.0009999999974999929,\n                -0.0009999999979999927,\n                -0.0009999999983333263\n            ]\n        );\n    }\n\n    #[ignore]\n    #[test]\n    fn test_adam_step_iteratively_until_convergence_with_custom_params() {\n        const CONVERGENCE_THRESHOLD: f64 = 1e-7;\n        let gradients = vec![7.0, -8.0, 9.0, -10.0, 11.0, -12.0, 13.0];\n\n        let mut optimizer = Adam::new(Some(0.005), Some((0.8, 0.899)), Some(1e-5), 7);\n\n        let mut model_params = vec![0.0; 7];\n        let mut updated_params = optimizer.step(&gradients);\n\n        while (updated_params\n            .iter()\n            .zip(model_params.iter())\n            .map(|(x, y)| x - y)\n            .collect::<Vec<f64>>())\n        .iter()\n        .map(|&x| x.powi(2))\n        .sum::<f64>()\n        .sqrt()\n            > CONVERGENCE_THRESHOLD\n        {\n            model_params = updated_params;\n            updated_params = optimizer.step(&gradients);\n        }\n\n        assert!(updated_params < vec![CONVERGENCE_THRESHOLD; 7]);\n        assert_ne!(updated_params, model_params);\n        assert_eq!(\n            updated_params,\n            vec![\n                -0.004999992857153061,\n                0.004999993750007814,\n                -0.0049999944444506185,\n                0.004999995000005001,\n                -0.004999995454549587,\n                0.004999995833336807,\n                -0.004999996153849113\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/optimization/gradient_descent.rs",
    "content": "/// Gradient Descent Optimization\n///\n/// Gradient descent is an iterative optimization algorithm used to find the minimum of a function.\n/// It works by updating the parameters (in this case, elements of the vector `x`) in the direction of\n/// the steepest decrease in the function's value. This is achieved by subtracting the gradient of\n/// the function at the current point from the current point. The learning rate controls the step size.\n///\n/// The equation for a single parameter (univariate) is:\n/// x_{k+1} = x_k - learning_rate * derivative_of_function(x_k)\n///\n/// For multivariate functions, it extends to each parameter:\n/// x_{k+1} = x_k - learning_rate * gradient_of_function(x_k)\n///\n/// # Arguments\n///\n/// * `derivative_fn` - The function that calculates the gradient of the objective function at a given point.\n/// * `x` - The initial parameter vector to be optimized.\n/// * `learning_rate` - Step size for each iteration.\n/// * `num_iterations` - The number of iterations to run the optimization.\n///\n/// # Returns\n///\n/// A reference to the optimized parameter vector `x`.\n\npub fn gradient_descent(\n    derivative_fn: impl Fn(&[f64]) -> Vec<f64>,\n    x: &mut Vec<f64>,\n    learning_rate: f64,\n    num_iterations: i32,\n) -> &mut Vec<f64> {\n    for _ in 0..num_iterations {\n        let gradient = derivative_fn(x);\n        for (x_k, grad) in x.iter_mut().zip(gradient.iter()) {\n            *x_k -= learning_rate * grad;\n        }\n    }\n\n    x\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_gradient_descent_optimized() {\n        fn derivative_of_square(params: &[f64]) -> Vec<f64> {\n            params.iter().map(|x| 2. * x).collect()\n        }\n\n        let mut x: Vec<f64> = vec![5.0, 6.0];\n        let learning_rate: f64 = 0.03;\n        let num_iterations: i32 = 1000;\n\n        let minimized_vector =\n            gradient_descent(derivative_of_square, &mut x, learning_rate, num_iterations);\n\n        let test_vector = [0.0, 0.0];\n\n        let tolerance = 1e-6;\n        for (minimized_value, test_value) in minimized_vector.iter().zip(test_vector.iter()) {\n            assert!((minimized_value - test_value).abs() < tolerance);\n        }\n    }\n\n    #[test]\n    fn test_gradient_descent_unoptimized() {\n        fn derivative_of_square(params: &[f64]) -> Vec<f64> {\n            params.iter().map(|x| 2. * x).collect()\n        }\n\n        let mut x: Vec<f64> = vec![5.0, 6.0];\n        let learning_rate: f64 = 0.03;\n        let num_iterations: i32 = 10;\n\n        let minimized_vector =\n            gradient_descent(derivative_of_square, &mut x, learning_rate, num_iterations);\n\n        let test_vector = [0.0, 0.0];\n\n        let tolerance = 1e-6;\n        for (minimized_value, test_value) in minimized_vector.iter().zip(test_vector.iter()) {\n            assert!((minimized_value - test_value).abs() >= tolerance);\n        }\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/optimization/mod.rs",
    "content": "mod adam;\nmod gradient_descent;\nmod momentum;\n\npub use self::adam::Adam;\npub use self::gradient_descent::gradient_descent;\n"
  },
  {
    "path": "src/machine_learning/optimization/momentum.rs",
    "content": "/// Momentum Optimization\n///\n/// Momentum is an extension of gradient descent that accelerates convergence by accumulating\n/// a velocity vector in directions of persistent reduction in the objective function.\n/// This helps the optimizer navigate ravines and avoid getting stuck in local minima.\n///\n/// The algorithm maintains a velocity vector that accumulates exponentially decaying moving\n/// averages of past gradients. This allows the optimizer to build up speed in consistent\n/// directions while dampening oscillations.\n///\n/// The update equations are:\n/// velocity_{k+1} = beta * velocity_k + gradient_of_function(x_k)\n/// x_{k+1} = x_k - learning_rate * velocity_{k+1}\n///\n/// where beta (typically 0.9) controls how much past gradients influence the current update.\n///\n/// # Arguments\n///\n/// * `derivative_fn` - The function that calculates the gradient of the objective function at a given point.\n/// * `x` - The initial parameter vector to be optimized.\n/// * `learning_rate` - Step size for each iteration.\n/// * `beta` - Momentum coefficient (typically 0.9). Higher values give more weight to past gradients.\n/// * `num_iterations` - The number of iterations to run the optimization.\n///\n/// # Returns\n///\n/// A reference to the optimized parameter vector `x`.\n#[allow(dead_code)]\npub fn momentum(\n    derivative: impl Fn(&[f64]) -> Vec<f64>,\n    x: &mut Vec<f64>,\n    learning_rate: f64,\n    beta: f64,\n    num_iterations: i32,\n) -> &mut Vec<f64> {\n    // Initialize velocity vector to zero\n    let mut velocity: Vec<f64> = vec![0.0; x.len()];\n\n    for _ in 0..num_iterations {\n        let gradient = derivative(x);\n\n        // Update velocity and parameters\n        for ((x_k, vel), grad) in x.iter_mut().zip(velocity.iter_mut()).zip(gradient.iter()) {\n            *vel = beta * *vel + grad;\n            *x_k -= learning_rate * *vel;\n        }\n    }\n    x\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_momentum_optimized() {\n        fn derivative_of_square(params: &[f64]) -> Vec<f64> {\n            params.iter().map(|x| 2.0 * x).collect()\n        }\n\n        let mut x: Vec<f64> = vec![5.0, 6.0];\n        let learning_rate: f64 = 0.01;\n        let beta: f64 = 0.9;\n        let num_iterations: i32 = 1000;\n\n        let minimized_vector = momentum(\n            derivative_of_square,\n            &mut x,\n            learning_rate,\n            beta,\n            num_iterations,\n        );\n\n        let test_vector = [0.0, 0.0];\n        let tolerance = 1e-6;\n\n        for (minimized_value, test_value) in minimized_vector.iter().zip(test_vector.iter()) {\n            assert!((minimized_value - test_value).abs() < tolerance);\n        }\n    }\n\n    #[test]\n    fn test_momentum_unoptimized() {\n        fn derivative_of_square(params: &[f64]) -> Vec<f64> {\n            params.iter().map(|x| 2.0 * x).collect()\n        }\n\n        let mut x: Vec<f64> = vec![5.0, 6.0];\n        let learning_rate: f64 = 0.01;\n        let beta: f64 = 0.9;\n        let num_iterations: i32 = 10;\n\n        let minimized_vector = momentum(\n            derivative_of_square,\n            &mut x,\n            learning_rate,\n            beta,\n            num_iterations,\n        );\n\n        let test_vector = [0.0, 0.0];\n        let tolerance = 1e-6;\n\n        for (minimized_value, test_value) in minimized_vector.iter().zip(test_vector.iter()) {\n            assert!((minimized_value - test_value).abs() >= tolerance);\n        }\n    }\n\n    #[test]\n    fn test_momentum_faster_than_gd() {\n        fn derivative_of_square(params: &[f64]) -> Vec<f64> {\n            params.iter().map(|x| 2.0 * x).collect()\n        }\n\n        // Test that momentum converges faster than gradient descent\n        let mut x_momentum: Vec<f64> = vec![5.0, 6.0];\n        let mut x_gd: Vec<f64> = vec![5.0, 6.0];\n        let learning_rate: f64 = 0.01;\n        let beta: f64 = 0.9;\n        let num_iterations: i32 = 50;\n\n        momentum(\n            derivative_of_square,\n            &mut x_momentum,\n            learning_rate,\n            beta,\n            num_iterations,\n        );\n\n        // Gradient descent from your original implementation\n        for _ in 0..num_iterations {\n            let gradient = derivative_of_square(&x_gd);\n            for (x_k, grad) in x_gd.iter_mut().zip(gradient.iter()) {\n                *x_k -= learning_rate * grad;\n            }\n        }\n\n        // Momentum should be closer to zero\n        let momentum_distance: f64 = x_momentum.iter().map(|x| x * x).sum();\n        let gd_distance: f64 = x_gd.iter().map(|x| x * x).sum();\n\n        assert!(momentum_distance < gd_distance);\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/perceptron.rs",
    "content": "/// Returns the weights and bias after performing Perceptron algorithm on the input data points.\n/// The Perceptron is a binary classification algorithm that learns a linear separator.\n/// Labels should be either -1.0 or 1.0 for the two classes.\npub fn perceptron(\n    data_points: Vec<(Vec<f64>, f64)>,\n    max_iterations: usize,\n    learning_rate: f64,\n) -> Option<(Vec<f64>, f64)> {\n    if data_points.is_empty() {\n        return None;\n    }\n\n    let num_features = data_points[0].0.len();\n    if num_features == 0 {\n        return None;\n    }\n\n    let mut weights = vec![0.0; num_features];\n    let mut bias = 0.0;\n\n    for _ in 0..max_iterations {\n        let mut misclassified = 0;\n\n        for (features, label) in &data_points {\n            let prediction = predict(&weights, bias, features);\n\n            if prediction != *label {\n                misclassified += 1;\n\n                for (weight, feature) in weights.iter_mut().zip(features.iter()) {\n                    *weight += learning_rate * label * feature;\n                }\n                bias += learning_rate * label;\n            }\n        }\n\n        if misclassified == 0 {\n            break;\n        }\n    }\n\n    Some((weights, bias))\n}\n\n/// Make a prediction using the given weights and bias.\nfn predict(weights: &[f64], bias: f64, features: &[f64]) -> f64 {\n    let sum = weights\n        .iter()\n        .zip(features.iter())\n        .map(|(w, x)| w * x)\n        .sum::<f64>()\n        + bias;\n\n    if sum >= 0.0 {\n        1.0\n    } else {\n        -1.0\n    }\n}\n\n/// Classify a new data point using the learned weights and bias.\npub fn classify(weights: &[f64], bias: f64, features: &[f64]) -> Option<f64> {\n    if weights.is_empty() || features.is_empty() {\n        return None;\n    }\n\n    if weights.len() != features.len() {\n        return None;\n    }\n\n    Some(predict(weights, bias, features))\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_perceptron_linearly_separable() {\n        let data = vec![\n            (vec![1.0, 1.0], 1.0),\n            (vec![2.0, 2.0], 1.0),\n            (vec![3.0, 3.0], 1.0),\n            (vec![-1.0, -1.0], -1.0),\n            (vec![-2.0, -2.0], -1.0),\n            (vec![-3.0, -3.0], -1.0),\n        ];\n\n        let result = perceptron(data, 100, 0.1);\n        assert!(result.is_some());\n\n        let (weights, bias) = result.unwrap();\n\n        let prediction1 = classify(&weights, bias, &[2.5, 2.5]);\n        assert_eq!(prediction1, Some(1.0));\n\n        let prediction2 = classify(&weights, bias, &[-2.5, -2.5]);\n        assert_eq!(prediction2, Some(-1.0));\n    }\n\n    #[test]\n    fn test_perceptron_xor_like() {\n        let data = vec![\n            (vec![0.0, 0.0], -1.0),\n            (vec![1.0, 1.0], 1.0),\n            (vec![0.0, 1.0], -1.0),\n            (vec![1.0, 0.0], -1.0),\n        ];\n\n        let result = perceptron(data, 100, 0.1);\n        assert!(result.is_some());\n\n        let (weights, _bias) = result.unwrap();\n        assert_eq!(weights.len(), 2);\n    }\n\n    #[test]\n    fn test_perceptron_single_feature() {\n        let data = vec![\n            (vec![1.0], 1.0),\n            (vec![2.0], 1.0),\n            (vec![3.0], 1.0),\n            (vec![-1.0], -1.0),\n            (vec![-2.0], -1.0),\n            (vec![-3.0], -1.0),\n        ];\n\n        let result = perceptron(data, 100, 0.1);\n        assert!(result.is_some());\n\n        let (weights, bias) = result.unwrap();\n        assert_eq!(weights.len(), 1);\n\n        let prediction1 = classify(&weights, bias, &[5.0]);\n        assert_eq!(prediction1, Some(1.0));\n\n        let prediction2 = classify(&weights, bias, &[-5.0]);\n        assert_eq!(prediction2, Some(-1.0));\n    }\n\n    #[test]\n    fn test_perceptron_empty_data() {\n        let result = perceptron(vec![], 100, 0.1);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_perceptron_empty_features() {\n        let data = vec![(vec![], 1.0), (vec![], -1.0)];\n        let result = perceptron(data, 100, 0.1);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_perceptron_zero_iterations() {\n        let data = vec![(vec![1.0, 1.0], 1.0), (vec![-1.0, -1.0], -1.0)];\n\n        let result = perceptron(data, 0, 0.1);\n        assert!(result.is_some());\n\n        let (weights, bias) = result.unwrap();\n        assert_eq!(weights, vec![0.0, 0.0]);\n        assert_eq!(bias, 0.0);\n    }\n\n    #[test]\n    fn test_classify_empty_weights() {\n        let result = classify(&[], 0.0, &[1.0, 2.0]);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_classify_empty_features() {\n        let result = classify(&[1.0, 2.0], 0.0, &[]);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_classify_mismatched_dimensions() {\n        let result = classify(&[1.0, 2.0], 0.0, &[1.0]);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_perceptron_different_learning_rates() {\n        let data = vec![\n            (vec![1.0, 1.0], 1.0),\n            (vec![2.0, 2.0], 1.0),\n            (vec![-1.0, -1.0], -1.0),\n            (vec![-2.0, -2.0], -1.0),\n        ];\n\n        let result1 = perceptron(data.clone(), 100, 0.01);\n        let result2 = perceptron(data, 100, 1.0);\n\n        assert!(result1.is_some());\n        assert!(result2.is_some());\n\n        let (weights1, bias1) = result1.unwrap();\n        let (weights2, bias2) = result2.unwrap();\n\n        let prediction1 = classify(&weights1, bias1, &[3.0, 3.0]);\n        let prediction2 = classify(&weights2, bias2, &[3.0, 3.0]);\n\n        assert_eq!(prediction1, Some(1.0));\n        assert_eq!(prediction2, Some(1.0));\n    }\n\n    #[test]\n    fn test_perceptron_with_bias() {\n        let data = vec![\n            (vec![1.0], 1.0),\n            (vec![2.0], 1.0),\n            (vec![10.0], 1.0),\n            (vec![0.0], -1.0),\n            (vec![-1.0], -1.0),\n            (vec![-10.0], -1.0),\n        ];\n\n        let result = perceptron(data, 100, 0.1);\n        assert!(result.is_some());\n\n        let (weights, bias) = result.unwrap();\n\n        let prediction_positive = classify(&weights, bias, &[5.0]);\n        let prediction_negative = classify(&weights, bias, &[-5.0]);\n\n        assert_eq!(prediction_positive, Some(1.0));\n        assert_eq!(prediction_negative, Some(-1.0));\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/principal_component_analysis.rs",
    "content": "/// Principal Component Analysis (PCA) for dimensionality reduction.\n/// PCA transforms data to a new coordinate system where the greatest\n/// variance lies on the first coordinate (first principal component),\n/// the second greatest variance on the second coordinate, and so on.\n\n/// Compute the mean of each feature across all samples\nfn compute_means(data: &[Vec<f64>]) -> Vec<f64> {\n    if data.is_empty() {\n        return vec![];\n    }\n\n    let num_features = data[0].len();\n    let mut means = vec![0.0; num_features];\n\n    for sample in data {\n        for (i, &feature) in sample.iter().enumerate() {\n            means[i] += feature;\n        }\n    }\n\n    let n = data.len() as f64;\n    for mean in &mut means {\n        *mean /= n;\n    }\n\n    means\n}\n\n/// Center the data by subtracting the mean from each feature\nfn center_data(data: &[Vec<f64>], means: &[f64]) -> Vec<Vec<f64>> {\n    data.iter()\n        .map(|sample| {\n            sample\n                .iter()\n                .zip(means.iter())\n                .map(|(&x, &mean)| x - mean)\n                .collect()\n        })\n        .collect()\n}\n\n/// Compute covariance matrix from centered data\nfn compute_covariance_matrix(centered_data: &[Vec<f64>]) -> Vec<f64> {\n    if centered_data.is_empty() {\n        return vec![];\n    }\n\n    let n = centered_data.len();\n    let num_features = centered_data[0].len();\n\n    let mut cov_matrix = vec![0.0; num_features * num_features];\n\n    for i in 0..num_features {\n        for j in i..num_features {\n            let mut cov = 0.0;\n            for sample in centered_data {\n                cov += sample[i] * sample[j];\n            }\n            cov /= n as f64;\n\n            cov_matrix[i * num_features + j] = cov;\n            cov_matrix[j * num_features + i] = cov;\n        }\n    }\n\n    cov_matrix\n}\n\n/// Power iteration method to find the dominant eigenvalue and eigenvector\nfn power_iteration(matrix: &[f64], n: usize, max_iter: usize, tolerance: f64) -> (f64, Vec<f64>) {\n    let mut b_k = vec![1.0; n];\n    let mut b_k_prev = vec![0.0; n];\n\n    for _ in 0..max_iter {\n        b_k_prev.clone_from(&b_k);\n\n        let mut b_k_new = vec![0.0; n];\n        for i in 0..n {\n            for j in 0..n {\n                b_k_new[i] += matrix[i * n + j] * b_k[j];\n            }\n        }\n\n        let norm = b_k_new.iter().map(|x| x * x).sum::<f64>().sqrt();\n        if norm > 1e-10 {\n            for val in &mut b_k_new {\n                *val /= norm;\n            }\n        }\n\n        b_k = b_k_new;\n\n        let diff: f64 = b_k\n            .iter()\n            .zip(b_k_prev.iter())\n            .map(|(a, b)| (a - b).abs())\n            .fold(0.0, |acc, x| acc.max(x));\n\n        if diff < tolerance {\n            break;\n        }\n    }\n\n    let eigenvalue = b_k\n        .iter()\n        .enumerate()\n        .map(|(i, &val)| {\n            let mut row_sum = 0.0;\n            for j in 0..n {\n                row_sum += matrix[i * n + j] * b_k[j];\n            }\n            row_sum * val\n        })\n        .sum::<f64>()\n        / b_k.iter().map(|x| x * x).sum::<f64>();\n\n    (eigenvalue, b_k)\n}\n\n/// Deflate a matrix by removing the component along a given eigenvector\nfn deflate_matrix(matrix: &[f64], eigenvector: &[f64], eigenvalue: f64, n: usize) -> Vec<f64> {\n    let mut deflated = matrix.to_vec();\n\n    for i in 0..n {\n        for j in 0..n {\n            deflated[i * n + j] -= eigenvalue * eigenvector[i] * eigenvector[j];\n        }\n    }\n\n    deflated\n}\n\n/// Perform PCA on the input data\n/// Returns transformed data with reduced dimensions\npub fn principal_component_analysis(\n    data: Vec<Vec<f64>>,\n    num_components: usize,\n) -> Option<Vec<Vec<f64>>> {\n    if data.is_empty() {\n        return None;\n    }\n\n    let num_features = data[0].len();\n\n    if num_features == 0 {\n        return None;\n    }\n\n    if num_components > num_features {\n        return None;\n    }\n\n    if num_components == 0 {\n        return None;\n    }\n\n    let means = compute_means(&data);\n    let centered_data = center_data(&data, &means);\n    let cov_matrix = compute_covariance_matrix(&centered_data);\n\n    let mut eigenvectors = Vec::new();\n    let mut deflated_matrix = cov_matrix;\n\n    for _ in 0..num_components {\n        let (_eigenvalue, eigenvector) =\n            power_iteration(&deflated_matrix, num_features, 1000, 1e-10);\n        eigenvectors.push(eigenvector);\n        deflated_matrix = deflate_matrix(\n            &deflated_matrix,\n            eigenvectors.last().unwrap(),\n            _eigenvalue,\n            num_features,\n        );\n    }\n\n    let transformed_data: Vec<Vec<f64>> = centered_data\n        .iter()\n        .map(|sample| {\n            (0..num_components)\n                .map(|k| {\n                    eigenvectors[k]\n                        .iter()\n                        .zip(sample.iter())\n                        .map(|(&ev, &s)| ev * s)\n                        .sum::<f64>()\n                })\n                .collect()\n        })\n        .collect();\n\n    Some(transformed_data)\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_pca_simple() {\n        let data = vec![\n            vec![1.0, 2.0],\n            vec![2.0, 3.0],\n            vec![3.0, 4.0],\n            vec![4.0, 5.0],\n            vec![5.0, 6.0],\n        ];\n\n        let result = principal_component_analysis(data, 1);\n        assert!(result.is_some());\n\n        let transformed = result.unwrap();\n        assert_eq!(transformed.len(), 5);\n        assert_eq!(transformed[0].len(), 1);\n\n        let all_values: Vec<f64> = transformed.iter().map(|v| v[0]).collect();\n        let mean = all_values.iter().sum::<f64>() / all_values.len() as f64;\n\n        assert!((mean).abs() < 1e-5);\n    }\n\n    #[test]\n    fn test_pca_empty_data() {\n        let data = vec![];\n        let result = principal_component_analysis(data, 2);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_pca_empty_features() {\n        let data = vec![vec![], vec![]];\n        let result = principal_component_analysis(data, 1);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_pca_invalid_num_components() {\n        let data = vec![vec![1.0, 2.0], vec![2.0, 3.0]];\n\n        let result = principal_component_analysis(data.clone(), 3);\n        assert_eq!(result, None);\n\n        let result = principal_component_analysis(data, 0);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_pca_preserves_dimensions() {\n        let data = vec![\n            vec![1.0, 2.0, 3.0],\n            vec![4.0, 5.0, 6.0],\n            vec![7.0, 8.0, 9.0],\n        ];\n\n        let result = principal_component_analysis(data, 2);\n        assert!(result.is_some());\n\n        let transformed = result.unwrap();\n        assert_eq!(transformed.len(), 3);\n        assert_eq!(transformed[0].len(), 2);\n    }\n\n    #[test]\n    fn test_pca_reconstruction_variance() {\n        let data = vec![\n            vec![2.5, 2.4],\n            vec![0.5, 0.7],\n            vec![2.2, 2.9],\n            vec![1.9, 2.2],\n            vec![3.1, 3.0],\n            vec![2.3, 2.7],\n            vec![2.0, 1.6],\n            vec![1.0, 1.1],\n            vec![1.5, 1.6],\n            vec![1.1, 0.9],\n        ];\n\n        let result = principal_component_analysis(data, 1);\n        assert!(result.is_some());\n\n        let transformed = result.unwrap();\n        assert_eq!(transformed.len(), 10);\n        assert_eq!(transformed[0].len(), 1);\n    }\n\n    #[test]\n    fn test_center_data() {\n        let data = vec![\n            vec![1.0, 2.0, 3.0],\n            vec![4.0, 5.0, 6.0],\n            vec![7.0, 8.0, 9.0],\n        ];\n\n        let means = vec![4.0, 5.0, 6.0];\n        let centered = center_data(&data, &means);\n\n        assert_eq!(centered[0], vec![-3.0, -3.0, -3.0]);\n        assert_eq!(centered[1], vec![0.0, 0.0, 0.0]);\n        assert_eq!(centered[2], vec![3.0, 3.0, 3.0]);\n    }\n\n    #[test]\n    fn test_compute_means() {\n        let data = vec![\n            vec![1.0, 2.0, 3.0],\n            vec![4.0, 5.0, 6.0],\n            vec![7.0, 8.0, 9.0],\n        ];\n\n        let means = compute_means(&data);\n        assert_eq!(means, vec![4.0, 5.0, 6.0]);\n    }\n\n    #[test]\n    fn test_power_iteration() {\n        let matrix = vec![4.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 1.0, 2.0];\n\n        let (eigenvalue, eigenvector) = power_iteration(&matrix, 3, 1000, 1e-10);\n\n        assert!(eigenvalue > 0.0);\n        assert_eq!(eigenvector.len(), 3);\n\n        let norm = eigenvector.iter().map(|x| x * x).sum::<f64>().sqrt();\n        assert!((norm - 1.0).abs() < 1e-6);\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/random_forest.rs",
    "content": "use rand::seq::SliceRandom;\nuse rand::RngExt;\n\n/// Train a single decision tree on a bootstrap sample with random feature subset\n#[allow(dead_code)]\nfn train_tree(\n    training_data: &[(Vec<f64>, f64)],\n    num_features: usize,\n    max_depth: usize,\n    min_samples_split: usize,\n    max_features: usize,\n) -> Option<crate::machine_learning::decision_tree::DecisionTree> {\n    if training_data.is_empty() {\n        return None;\n    }\n\n    // Bootstrap sampling: sample with replacement\n    let num_samples = training_data.len();\n    let mut rng = rand::rng();\n    let mut bootstrap_sample = Vec::with_capacity(num_samples);\n\n    for _ in 0..num_samples {\n        let random_index = rng.random_range(0..num_samples);\n        bootstrap_sample.push(training_data[random_index].clone());\n    }\n\n    // Select random subset of features for this tree\n    let mut feature_indices: Vec<usize> = (0..num_features).collect();\n    feature_indices.shuffle(&mut rng);\n    feature_indices.truncate(max_features);\n\n    // Train decision tree on bootstrap sample with limited features\n    let limited_sample: Vec<(Vec<f64>, f64)> = bootstrap_sample\n        .iter()\n        .map(|(features, label)| {\n            let limited_features: Vec<f64> =\n                feature_indices.iter().map(|&idx| features[idx]).collect();\n            (limited_features, *label)\n        })\n        .collect();\n\n    let tree = crate::machine_learning::decision_tree::DecisionTree::fit(\n        limited_sample,\n        max_depth,\n        min_samples_split,\n    )?;\n\n    Some(tree)\n}\n\n#[derive(Debug, PartialEq)]\npub struct RandomForest {\n    trees: Vec<crate::machine_learning::decision_tree::DecisionTree>,\n    feature_indices: Vec<Vec<usize>>,\n    num_classes: usize,\n}\n\nimpl RandomForest {\n    pub fn fit(\n        training_data: Vec<(Vec<f64>, f64)>,\n        num_trees: usize,\n        max_depth: usize,\n        min_samples_split: usize,\n        max_features: Option<usize>,\n    ) -> Option<Self> {\n        if training_data.is_empty() {\n            return None;\n        }\n\n        let num_features = training_data[0].0.len();\n        if num_features == 0 {\n            return None;\n        }\n\n        // Default max_features to sqrt of total features\n        let max_features = max_features.unwrap_or_else(|| (num_features as f64).sqrt() as usize);\n        let max_features = max_features.max(1).min(num_features);\n\n        let mut trees = Vec::new();\n        let mut all_feature_indices = Vec::new();\n\n        // Train multiple decision trees\n        for _ in 0..num_trees {\n            let mut rng = rand::rng();\n            let mut feature_indices: Vec<usize> = (0..num_features).collect();\n            feature_indices.shuffle(&mut rng);\n            feature_indices.truncate(max_features);\n\n            let mut bootstrap_sample = Vec::with_capacity(training_data.len());\n            for _ in 0..training_data.len() {\n                let random_index = rng.random_range(0..training_data.len());\n                bootstrap_sample.push(training_data[random_index].clone());\n            }\n\n            let limited_sample: Vec<(Vec<f64>, f64)> = bootstrap_sample\n                .iter()\n                .map(|(features, label)| {\n                    let limited_features: Vec<f64> =\n                        feature_indices.iter().map(|&idx| features[idx]).collect();\n                    (limited_features, *label)\n                })\n                .collect();\n\n            if let Some(tree) = crate::machine_learning::decision_tree::DecisionTree::fit(\n                limited_sample,\n                max_depth,\n                min_samples_split,\n            ) {\n                trees.push(tree);\n                all_feature_indices.push(feature_indices);\n            }\n        }\n\n        if trees.is_empty() {\n            return None;\n        }\n\n        // Determine number of classes\n        let mut unique_labels: Vec<f64> = Vec::new();\n        for (_, label) in &training_data {\n            if !unique_labels.contains(label) {\n                unique_labels.push(*label);\n            }\n        }\n        let num_classes = unique_labels.len();\n\n        Some(RandomForest {\n            trees,\n            feature_indices: all_feature_indices,\n            num_classes,\n        })\n    }\n\n    pub fn predict(&self, test_point: &[f64]) -> Option<f64> {\n        if test_point.is_empty() || self.trees.is_empty() {\n            return None;\n        }\n\n        let mut predictions: Vec<f64> = Vec::new();\n\n        for (tree, feature_indices) in self.trees.iter().zip(self.feature_indices.iter()) {\n            let limited_point: Vec<f64> =\n                feature_indices.iter().map(|&idx| test_point[idx]).collect();\n\n            if let Some(prediction) = tree.predict(&limited_point) {\n                predictions.push(prediction);\n            }\n        }\n\n        if predictions.is_empty() {\n            return None;\n        }\n\n        // Majority voting\n        let mut unique_labels: Vec<f64> = Vec::new();\n        let mut counts: Vec<usize> = Vec::new();\n\n        for &pred in &predictions {\n            let mut found = false;\n            for (i, &label) in unique_labels.iter().enumerate() {\n                if (label - pred).abs() < 1e-10 {\n                    counts[i] += 1;\n                    found = true;\n                    break;\n                }\n            }\n            if !found {\n                unique_labels.push(pred);\n                counts.push(1);\n            }\n        }\n\n        let mut max_count = 0;\n        let mut best_label = unique_labels[0];\n        for (i, &count) in counts.iter().enumerate() {\n            if count > max_count {\n                max_count = count;\n                best_label = unique_labels[i];\n            }\n        }\n\n        Some(best_label)\n    }\n\n    #[allow(dead_code)]\n    pub fn predict_batch(&self, test_points: &[Vec<f64>]) -> Vec<Option<f64>> {\n        test_points\n            .iter()\n            .map(|point| self.predict(point))\n            .collect()\n    }\n}\n\n/// Convenience function to train a random forest and make predictions\npub fn random_forest(\n    training_data: Vec<(Vec<f64>, f64)>,\n    test_point: Vec<f64>,\n    num_trees: usize,\n    max_depth: usize,\n    min_samples_split: usize,\n    max_features: Option<usize>,\n) -> Option<f64> {\n    let model = RandomForest::fit(\n        training_data,\n        num_trees,\n        max_depth,\n        min_samples_split,\n        max_features,\n    )?;\n    model.predict(&test_point)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_random_forest_linearly_separable() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![3.0, 3.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n            (vec![7.0, 7.0], 1.0),\n        ];\n\n        let model = RandomForest::fit(training_data, 10, 5, 2, None);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        assert_eq!(model.predict(&[1.5, 1.5]), Some(0.0));\n        assert_eq!(model.predict(&[5.5, 5.5]), Some(1.0));\n    }\n\n    #[test]\n    fn test_random_forest_xor() {\n        let training_data = vec![\n            (vec![0.0, 0.0], 0.0),\n            (vec![0.0, 1.0], 1.0),\n            (vec![1.0, 0.0], 1.0),\n            (vec![1.0, 1.0], 0.0),\n            // Add more samples to help with XOR\n            (vec![0.2, 0.2], 0.0),\n            (vec![0.8, 0.8], 0.0),\n            (vec![0.2, 0.8], 1.0),\n            (vec![0.8, 0.2], 1.0),\n        ];\n\n        let model = RandomForest::fit(training_data, 20, 5, 2, Some(2));\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        // Verify model can make predictions (not necessarily perfect)\n        let result = model.predict(&[0.0, 0.0]);\n        assert!(result.is_some());\n\n        let result = model.predict(&[1.0, 1.0]);\n        assert!(result.is_some());\n    }\n\n    #[test]\n    fn test_random_forest_multiple_classes() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n            (vec![9.0, 9.0], 2.0),\n            (vec![10.0, 10.0], 2.0),\n        ];\n\n        let model = RandomForest::fit(training_data, 10, 5, 2, None);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        assert_eq!(model.predict(&[1.5, 1.5]), Some(0.0));\n        assert_eq!(model.predict(&[5.5, 5.5]), Some(1.0));\n        assert_eq!(model.predict(&[9.5, 9.5]), Some(2.0));\n    }\n\n    #[test]\n    fn test_random_forest_one_feature() {\n        let training_data = vec![\n            (vec![1.0], 0.0),\n            (vec![2.0], 0.0),\n            (vec![3.0], 0.0),\n            (vec![5.0], 1.0),\n            (vec![6.0], 1.0),\n            (vec![7.0], 1.0),\n        ];\n\n        let model = RandomForest::fit(training_data, 10, 5, 2, None);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        assert_eq!(model.predict(&[2.5]), Some(0.0));\n        assert_eq!(model.predict(&[5.5]), Some(1.0));\n    }\n\n    #[test]\n    fn test_random_forest_empty_training_data() {\n        let training_data = vec![];\n        let model = RandomForest::fit(training_data, 10, 5, 2, None);\n        assert_eq!(model, None);\n    }\n\n    #[test]\n    fn test_random_forest_empty_features() {\n        let training_data = vec![(vec![], 0.0), (vec![], 1.0)];\n        let model = RandomForest::fit(training_data, 10, 5, 2, None);\n        assert_eq!(model, None);\n    }\n\n    #[test]\n    fn test_random_forest_predict_batch() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n        ];\n\n        let model = RandomForest::fit(training_data, 10, 5, 2, None);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        let test_points = vec![vec![1.5, 1.5], vec![5.5, 5.5]];\n        let predictions = model.predict_batch(&test_points);\n\n        assert_eq!(predictions.len(), 2);\n        assert_eq!(predictions[0], Some(0.0));\n        assert_eq!(predictions[1], Some(1.0));\n    }\n\n    #[test]\n    fn test_random_forest_custom_max_features() {\n        let training_data = vec![\n            (vec![1.0, 2.0, 3.0], 0.0),\n            (vec![2.0, 3.0, 4.0], 0.0),\n            (vec![5.0, 6.0, 7.0], 1.0),\n            (vec![6.0, 7.0, 8.0], 1.0),\n        ];\n\n        let model = RandomForest::fit(training_data, 10, 5, 2, Some(2));\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        assert_eq!(model.predict(&[1.5, 2.5, 3.5]), Some(0.0));\n        assert_eq!(model.predict(&[5.5, 6.5, 7.5]), Some(1.0));\n    }\n\n    #[test]\n    fn test_random_forest_convenience_function() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n        ];\n\n        let result = random_forest(training_data, vec![1.5, 1.5], 10, 5, 2, None);\n        assert_eq!(result, Some(0.0));\n\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n        ];\n\n        let result = random_forest(training_data, vec![5.5, 5.5], 10, 5, 2, None);\n        assert_eq!(result, Some(1.0));\n    }\n\n    #[test]\n    fn test_random_forest_single_tree() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n        ];\n\n        let model = RandomForest::fit(training_data, 1, 5, 2, None);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        // With single tree and bootstrap sampling, predictions may vary\n        // Just verify model can make predictions\n        let result1 = model.predict(&[1.5, 1.5]);\n        let result2 = model.predict(&[5.5, 5.5]);\n\n        assert!(result1.is_some());\n        assert!(result2.is_some());\n    }\n\n    #[test]\n    fn test_random_forest_empty_test_point() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n        ];\n\n        let model = RandomForest::fit(training_data, 10, 5, 2, None);\n        assert!(model.is_some());\n\n        let model = model.unwrap();\n\n        let result = model.predict(&[]);\n        assert_eq!(result, None);\n    }\n\n    #[test]\n    fn test_random_forest_different_num_trees() {\n        let training_data = vec![\n            (vec![1.0, 1.0], 0.0),\n            (vec![2.0, 2.0], 0.0),\n            (vec![5.0, 5.0], 1.0),\n            (vec![6.0, 6.0], 1.0),\n        ];\n\n        let model_5 = RandomForest::fit(training_data.clone(), 5, 5, 2, None);\n        let model_20 = RandomForest::fit(training_data, 20, 5, 2, None);\n\n        assert!(model_5.is_some());\n        assert!(model_20.is_some());\n\n        let model_5 = model_5.unwrap();\n        let model_20 = model_20.unwrap();\n\n        assert_eq!(model_5.predict(&[1.5, 1.5]), Some(0.0));\n        assert_eq!(model_20.predict(&[1.5, 1.5]), Some(0.0));\n    }\n}\n"
  },
  {
    "path": "src/machine_learning/support_vector_classifier.rs",
    "content": "//! Support Vector Classifier (SVC)\n//!\n//! This module implements a Support Vector Machine classifier with support for\n//! linear and RBF (Radial Basis Function) kernels. It uses the dual formulation\n//! of the SVM optimization problem.\n//!\n//! # Example\n//! ```\n//! use ndarray::array;\n//! use the_algorithms_rust::machine_learning::{SVC, Kernel};\n//!\n//! let observations = vec![\n//!     array![0.0, 1.0],\n//!     array![0.0, 2.0],\n//!     array![1.0, 1.0],\n//!     array![1.0, 2.0],\n//! ];\n//! let classes = array![1.0, 1.0, -1.0, -1.0];\n//!\n//! let mut svc = SVC::new(Kernel::Linear, f64::INFINITY).unwrap();\n//! svc.fit(&observations, &classes).unwrap();\n//! assert_eq!(svc.predict(&array![0.0, 1.0]), 1.0);\n//! assert_eq!(svc.predict(&array![1.0, 1.0]), -1.0);\n//! ```\n\nuse ndarray::{Array1, Array2};\nuse std::f64;\n\n/// Kernel types supported by the SVC\n#[derive(Debug, Clone)]\npub enum Kernel {\n    /// Linear kernel: K(x, y) = x · y\n    Linear,\n    /// RBF kernel: K(x, y) = exp(-gamma * ||x - y||²)\n    Rbf { gamma: f64 },\n}\n\n/// Support Vector Classifier\n///\n/// A binary classifier that finds the optimal hyperplane to separate two classes.\n/// Uses the dual formulation with support for different kernel functions.\n#[derive(Debug)]\npub struct SVC {\n    kernel: Kernel,\n    regularization: f64,\n    observations: Vec<Array1<f64>>,\n    classes: Array1<f64>,\n    optimum: Array1<f64>,\n    offset: f64,\n}\n\n/// Errors that can occur when creating or using an SVC\n#[derive(Debug, PartialEq)]\npub enum SVCError {\n    InvalidGamma,\n    InvalidRegularization,\n    EmptyData,\n    MismatchedDimensions,\n}\n\nimpl std::fmt::Display for SVCError {\n    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n        match self {\n            SVCError::InvalidGamma => write!(f, \"gamma must be > 0\"),\n            SVCError::InvalidRegularization => write!(f, \"regularization must be > 0\"),\n            SVCError::EmptyData => write!(f, \"observations and classes cannot be empty\"),\n            SVCError::MismatchedDimensions => {\n                write!(f, \"number of observations must match number of classes\")\n            }\n        }\n    }\n}\n\nimpl std::error::Error for SVCError {}\n\nimpl SVC {\n    /// Creates a new Support Vector Classifier\n    ///\n    /// # Arguments\n    /// * `kernel` - The kernel function to use\n    /// * `regularization` - Soft margin constraint (C parameter), use `f64::INFINITY` for hard margin\n    ///\n    /// # Errors\n    /// Returns an error if gamma (for RBF kernel) or regularization are invalid\n    ///\n    /// # Example\n    /// ```\n    /// use the_algorithms_rust::machine_learning::{SVC, Kernel};\n    ///\n    /// let svc = SVC::new(Kernel::Linear, f64::INFINITY).unwrap();\n    /// let svc_rbf = SVC::new(Kernel::Rbf { gamma: 0.5 }, 1.0).unwrap();\n    /// ```\n    pub fn new(kernel: Kernel, regularization: f64) -> Result<Self, SVCError> {\n        if regularization <= 0.0 {\n            return Err(SVCError::InvalidRegularization);\n        }\n\n        if let Kernel::Rbf { gamma } = kernel {\n            if gamma <= 0.0 {\n                return Err(SVCError::InvalidGamma);\n            }\n        }\n\n        Ok(SVC {\n            kernel,\n            regularization,\n            observations: Vec::new(),\n            classes: Array1::zeros(0),\n            optimum: Array1::zeros(0),\n            offset: 0.0,\n        })\n    }\n\n    /// Computes the kernel function between two vectors\n    fn kernel_function(&self, v1: &Array1<f64>, v2: &Array1<f64>) -> f64 {\n        match &self.kernel {\n            Kernel::Linear => v1.dot(v2),\n            Kernel::Rbf { gamma } => {\n                let diff = v1 - v2;\n                let norm_sq = diff.dot(&diff);\n                (-gamma * norm_sq).exp()\n            }\n        }\n    }\n\n    /// Fits the SVC with training data\n    ///\n    /// # Arguments\n    /// * `observations` - Training feature vectors\n    /// * `classes` - Class labels (should be 1.0 or -1.0)\n    ///\n    /// # Errors\n    /// Returns an error if data is empty or dimensions don't match\n    ///\n    /// # Example\n    /// ```\n    /// use ndarray::array;\n    /// use the_algorithms_rust::machine_learning::{SVC, Kernel};\n    ///\n    /// let observations = vec![array![0.0, 1.0], array![1.0, 0.0]];\n    /// let classes = array![1.0, -1.0];\n    /// let mut svc = SVC::new(Kernel::Linear, f64::INFINITY).unwrap();\n    /// svc.fit(&observations, &classes).unwrap();\n    /// ```\n    pub fn fit(\n        &mut self,\n        observations: &[Array1<f64>],\n        classes: &Array1<f64>,\n    ) -> Result<(), SVCError> {\n        if observations.is_empty() || classes.is_empty() {\n            return Err(SVCError::EmptyData);\n        }\n\n        if observations.len() != classes.len() {\n            return Err(SVCError::MismatchedDimensions);\n        }\n\n        self.observations = observations.to_vec();\n        self.classes.clone_from(classes);\n\n        let n = classes.len();\n\n        // Solve the dual optimization problem\n        // We use a simple gradient descent approach for educational purposes\n        // In production, you'd want to use a proper QP solver\n        let optimum = self.solve_dual(n);\n        self.optimum = optimum;\n\n        // Calculate offset (bias term)\n        self.offset = self.calculate_offset(n);\n\n        Ok(())\n    }\n\n    /// Solves the dual optimization problem using a simple gradient descent\n    ///\n    /// This is a simplified solver for educational purposes.\n    /// In production, use a proper QP solver like OSQP or similar.\n    fn solve_dual(&self, n: usize) -> Array1<f64> {\n        let mut lambda = Array1::from_elem(n, 0.5);\n        let learning_rate = 0.1;\n        let iterations = 5000;\n        let tolerance = 1e-8;\n\n        // Precompute kernel matrix for efficiency\n        let mut kernel_matrix = Array2::zeros((n, n));\n        for i in 0..n {\n            for j in 0..n {\n                kernel_matrix[[i, j]] =\n                    self.kernel_function(&self.observations[i], &self.observations[j]);\n            }\n        }\n\n        for iter in 0..iterations {\n            let mut gradient = Array1::zeros(n);\n\n            // Compute gradient of the dual objective\n            for i in 0..n {\n                let mut sum = 0.0;\n                for j in 0..n {\n                    sum += lambda[j] * self.classes[j] * kernel_matrix[[i, j]];\n                }\n                gradient[i] = self.classes[i] * sum - 1.0;\n            }\n\n            // Update lambda with gradient descent\n            let old_lambda = lambda.clone();\n\n            // Adaptive learning rate\n            let lr = learning_rate / (1.0 + iter as f64 / 1000.0);\n            lambda = &lambda - lr * &gradient;\n\n            // Project onto constraints: 0 <= lambda <= C\n            for i in 0..n {\n                lambda[i] = lambda[i].max(0.0).min(self.regularization);\n            }\n\n            // Enforce sum(lambda * y) = 0 constraint using projection\n            let mut sum_ly = 0.0;\n            for i in 0..n {\n                sum_ly += lambda[i] * self.classes[i];\n            }\n\n            // Better constraint enforcement\n            let mut correction = sum_ly / n as f64;\n            for _ in 0..10 {\n                for i in 0..n {\n                    let delta = correction * self.classes[i];\n                    let new_val = lambda[i] - delta;\n                    lambda[i] = new_val.max(0.0).min(self.regularization);\n                }\n\n                // Recalculate sum\n                sum_ly = 0.0;\n                for i in 0..n {\n                    sum_ly += lambda[i] * self.classes[i];\n                }\n                correction = sum_ly / n as f64;\n\n                if sum_ly.abs() < 1e-10 {\n                    break;\n                }\n            }\n\n            // Check convergence\n            let diff = &lambda - &old_lambda;\n            if diff.dot(&diff).sqrt() < tolerance {\n                break;\n            }\n        }\n\n        lambda\n    }\n\n    /// Calculates the offset (bias) term\n    fn calculate_offset(&self, n: usize) -> f64 {\n        let mut sum = 0.0;\n        let mut count = 0;\n\n        // Calculate bias using support vectors (lambda > threshold and < C)\n        let threshold = 1e-5;\n        for i in 0..n {\n            if self.optimum[i] > threshold && self.optimum[i] < self.regularization - threshold {\n                let mut kernel_sum = 0.0;\n                for j in 0..n {\n                    kernel_sum += self.optimum[j]\n                        * self.classes[j]\n                        * self.kernel_function(&self.observations[j], &self.observations[i]);\n                }\n                sum += self.classes[i] - kernel_sum;\n                count += 1;\n            }\n        }\n\n        // If no clear support vectors, use all points\n        if count == 0 {\n            for i in 0..n {\n                let mut kernel_sum = 0.0;\n                for j in 0..n {\n                    kernel_sum += self.optimum[j]\n                        * self.classes[j]\n                        * self.kernel_function(&self.observations[j], &self.observations[i]);\n                }\n                sum += self.classes[i] - kernel_sum;\n            }\n            sum / n as f64\n        } else {\n            sum / count as f64\n        }\n    }\n\n    /// Predicts the class of a new observation\n    ///\n    /// # Arguments\n    /// * `observation` - Feature vector to classify\n    ///\n    /// # Returns\n    /// The predicted class (1.0 or -1.0)\n    ///\n    /// # Example\n    /// ```\n    /// use ndarray::array;\n    /// use the_algorithms_rust::machine_learning::{SVC, Kernel};\n    ///\n    /// let observations = vec![array![0.0, 1.0], array![1.0, 0.0]];\n    /// let classes = array![1.0, -1.0];\n    /// let mut svc = SVC::new(Kernel::Linear, f64::INFINITY).unwrap();\n    /// svc.fit(&observations, &classes).unwrap();\n    ///\n    /// let prediction = svc.predict(&array![0.5, 0.5]);\n    /// assert!(prediction == 1.0 || prediction == -1.0);\n    /// ```\n    pub fn predict(&self, observation: &Array1<f64>) -> f64 {\n        let mut sum = 0.0;\n        for i in 0..self.classes.len() {\n            sum += self.optimum[i]\n                * self.classes[i]\n                * self.kernel_function(&self.observations[i], observation);\n        }\n\n        if sum + self.offset >= 0.0 {\n            1.0\n        } else {\n            -1.0\n        }\n    }\n\n    /// Returns the number of support vectors\n    ///\n    /// Support vectors are observations with non-zero lambda values\n    pub fn n_support_vectors(&self) -> usize {\n        self.optimum.iter().filter(|&&l| l > 1e-5).count()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use ndarray::array;\n\n    #[test]\n    fn test_linear_kernel_simple() {\n        let observations = vec![\n            array![0.0, 1.0],\n            array![0.0, 2.0],\n            array![1.0, 1.0],\n            array![1.0, 2.0],\n        ];\n        let classes = array![1.0, 1.0, -1.0, -1.0];\n\n        let mut svc = SVC::new(Kernel::Linear, f64::INFINITY).unwrap();\n        svc.fit(&observations, &classes).unwrap();\n\n        assert_eq!(svc.predict(&array![0.0, 1.0]), 1.0);\n        assert_eq!(svc.predict(&array![1.0, 1.0]), -1.0);\n        assert_eq!(svc.predict(&array![2.0, 2.0]), -1.0);\n    }\n\n    #[test]\n    fn test_rbf_kernel() {\n        let observations = vec![\n            array![0.0, 0.0],\n            array![1.0, 1.0],\n            array![0.0, 1.0],\n            array![1.0, 0.0],\n        ];\n        let classes = array![1.0, 1.0, -1.0, -1.0];\n\n        let mut svc = SVC::new(Kernel::Rbf { gamma: 1.0 }, 1.0).unwrap();\n        svc.fit(&observations, &classes).unwrap();\n\n        // The RBF kernel should handle this XOR-like pattern better than linear\n        assert_eq!(svc.predict(&array![0.0, 0.0]), 1.0);\n        assert_eq!(svc.predict(&array![1.0, 1.0]), 1.0);\n    }\n\n    #[test]\n    fn test_invalid_gamma() {\n        let result = SVC::new(Kernel::Rbf { gamma: -1.0 }, 1.0);\n        assert!(matches!(result, Err(SVCError::InvalidGamma)));\n\n        let result = SVC::new(Kernel::Rbf { gamma: 0.0 }, 1.0);\n        assert!(matches!(result, Err(SVCError::InvalidGamma)));\n    }\n\n    #[test]\n    fn test_invalid_regularization() {\n        let result = SVC::new(Kernel::Linear, 0.0);\n        assert!(matches!(result, Err(SVCError::InvalidRegularization)));\n\n        let result = SVC::new(Kernel::Linear, -1.0);\n        assert!(matches!(result, Err(SVCError::InvalidRegularization)));\n    }\n\n    #[test]\n    fn test_empty_data() {\n        let mut svc = SVC::new(Kernel::Linear, 1.0).unwrap();\n        let result = svc.fit(&[], &Array1::zeros(0));\n        assert!(matches!(result, Err(SVCError::EmptyData)));\n    }\n\n    #[test]\n    fn test_mismatched_dimensions() {\n        let mut svc = SVC::new(Kernel::Linear, 1.0).unwrap();\n        let observations = vec![array![1.0, 2.0]];\n        let classes = array![1.0, -1.0]; // Too many classes\n        let result = svc.fit(&observations, &classes);\n        assert!(matches!(result, Err(SVCError::MismatchedDimensions)));\n    }\n\n    #[test]\n    fn test_support_vectors_count() {\n        let observations = vec![\n            array![0.0, 1.0],\n            array![0.0, 2.0],\n            array![1.0, 1.0],\n            array![1.0, 2.0],\n        ];\n        let classes = array![1.0, 1.0, -1.0, -1.0];\n\n        let mut svc = SVC::new(Kernel::Linear, f64::INFINITY).unwrap();\n        svc.fit(&observations, &classes).unwrap();\n\n        // Should have at least some support vectors\n        assert!(svc.n_support_vectors() > 0);\n        assert!(svc.n_support_vectors() <= observations.len());\n    }\n}\n"
  },
  {
    "path": "src/math/abs.rs",
    "content": "/// This function returns the absolute value of a number.\\\n/// The absolute value of a number is the non-negative value of the number, regardless of its sign.\\\n///\n/// Wikipedia: <https://en.wikipedia.org/wiki/Absolute_value>\npub fn abs<T>(num: T) -> T\nwhere\n    T: std::ops::Neg<Output = T> + PartialOrd + Copy + num_traits::Zero,\n{\n    if num < T::zero() {\n        return -num;\n    }\n    num\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_negative_number_i32() {\n        assert_eq!(69, abs(-69));\n    }\n\n    #[test]\n    fn test_negative_number_f64() {\n        assert_eq!(69.69, abs(-69.69));\n    }\n\n    #[test]\n    fn zero() {\n        assert_eq!(0.0, abs(0.0));\n    }\n\n    #[test]\n    fn positive_number() {\n        assert_eq!(69.69, abs(69.69));\n    }\n}\n"
  },
  {
    "path": "src/math/aliquot_sum.rs",
    "content": "/// Aliquot sum of a number is defined as the sum of the proper divisors of a number.\\\n/// i.e. all the divisors of a number apart from the number itself.\n///\n/// ## Example:\n/// The aliquot sum of 6 is (1 + 2 + 3) = 6, and that of 15 is (1 + 3 + 5) = 9\n///\n/// Wikipedia article on Aliquot Sum: <https://en.wikipedia.org/wiki/Aliquot_sum>\n\npub fn aliquot_sum(number: u64) -> u64 {\n    if number == 0 {\n        panic!(\"Input has to be positive.\")\n    }\n\n    (1..=number / 2).filter(|&d| number.is_multiple_of(d)).sum()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_aliquot_sum {\n        ($($name:ident: $tc:expr,)*) => {\n        $(\n            #[test]\n            fn $name() {\n                let (number, expected) = $tc;\n                assert_eq!(aliquot_sum(number), expected);\n            }\n        )*\n        }\n    }\n\n    test_aliquot_sum! {\n        test_with_1: (1, 0),\n        test_with_2: (2, 1),\n        test_with_3: (3, 1),\n        test_with_4: (4, 1+2),\n        test_with_5: (5, 1),\n        test_with_6: (6, 6),\n        test_with_7: (7, 1),\n        test_with_8: (8, 1+2+4),\n        test_with_9: (9, 1+3),\n        test_with_10: (10, 1+2+5),\n        test_with_15: (15, 9),\n        test_with_343: (343, 57),\n        test_with_344: (344, 316),\n        test_with_500: (500, 592),\n        test_with_501: (501, 171),\n    }\n\n    #[test]\n    #[should_panic]\n    fn panics_if_input_is_zero() {\n        aliquot_sum(0);\n    }\n}\n"
  },
  {
    "path": "src/math/amicable_numbers.rs",
    "content": "// Operations based around amicable numbers\n// Suports u32 but should be interchangable with other types\n// Wikipedia reference: https://en.wikipedia.org/wiki/Amicable_numbers\n\n// Returns vec of amicable pairs below N\n// N must be positive\npub fn amicable_pairs_under_n(n: u32) -> Option<Vec<(u32, u32)>> {\n    let mut factor_sums = vec![0; n as usize];\n\n    // Make a list of the sum of the factors of each number below N\n    for i in 1..n {\n        for j in (i * 2..n).step_by(i as usize) {\n            factor_sums[j as usize] += i;\n        }\n    }\n\n    // Default value of (0, 0) if no pairs are found\n    let mut out = vec![(0, 0)];\n    // Check if numbers are amicable then append\n    for (i, x) in factor_sums.iter().enumerate() {\n        if (*x < n) && (factor_sums[*x as usize] == i as u32) && (*x > i as u32) {\n            out.push((i as u32, *x));\n        }\n    }\n\n    // Check if anything was added to the vec, if so remove the (0, 0) and return\n    if out.len() == 1 {\n        None\n    } else {\n        out.remove(0);\n        Some(out)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    pub fn test_amicable_numbers_below_n() {\n        // First 10 amicable numbers, sorted (low, high)\n        let expected_result = vec![\n            (220, 284),\n            (1184, 1210),\n            (2620, 2924),\n            (5020, 5564),\n            (6232, 6368),\n            (10744, 10856),\n            (12285, 14595),\n            (17296, 18416),\n            (63020, 76084),\n            (66928, 66992),\n        ];\n\n        // Generate pairs under 100,000\n        let mut result = amicable_pairs_under_n(100_000).unwrap();\n\n        // There should be 13 pairs under 100,000\n        assert_eq!(result.len(), 13);\n\n        // Check the first 10 against known values\n        result = result[..10].to_vec();\n        assert_eq!(result, expected_result);\n\n        // N that does not have any amicable pairs below it, the result should be None\n        assert_eq!(amicable_pairs_under_n(100), None);\n    }\n}\n"
  },
  {
    "path": "src/math/area_of_polygon.rs",
    "content": "/**\n * @file\n * @brief Calculate the area of a polygon defined by a vector of points.\n *\n * @details\n * This program provides a function to calculate the area of a polygon defined by a vector of points.\n * The area is calculated using the formula: A = |Σ((xi - xi-1) * (yi + yi-1))| / 2\n * where (xi, yi) are the coordinates of the points in the vector.\n *\n * @param fig A vector of points defining the polygon.\n * @return The area of the polygon.\n *\n * @author [Gyandeep](https://github.com/Gyan172004)\n * @see [Wikipedia - Polygon](https://en.wikipedia.org/wiki/Polygon)\n */\n\npub struct Point {\n    x: f64,\n    y: f64,\n}\n\n/**\n * Calculate the area of a polygon defined by a vector of points.\n * @param fig A vector of points defining the polygon.\n * @return The area of the polygon.\n */\n\npub fn area_of_polygon(fig: &[Point]) -> f64 {\n    let mut res = 0.0;\n\n    for i in 0..fig.len() {\n        let p = if i > 0 {\n            &fig[i - 1]\n        } else {\n            &fig[fig.len() - 1]\n        };\n        let q = &fig[i];\n\n        res += (p.x - q.x) * (p.y + q.y);\n    }\n\n    f64::abs(res) / 2.0\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    /**\n     * Test case for calculating the area of a triangle.\n     */\n    #[test]\n    fn test_area_triangle() {\n        let points = vec![\n            Point { x: 0.0, y: 0.0 },\n            Point { x: 1.0, y: 0.0 },\n            Point { x: 0.0, y: 1.0 },\n        ];\n\n        assert_eq!(area_of_polygon(&points), 0.5);\n    }\n\n    /**\n     * Test case for calculating the area of a square.\n     */\n    #[test]\n    fn test_area_square() {\n        let points = vec![\n            Point { x: 0.0, y: 0.0 },\n            Point { x: 1.0, y: 0.0 },\n            Point { x: 1.0, y: 1.0 },\n            Point { x: 0.0, y: 1.0 },\n        ];\n\n        assert_eq!(area_of_polygon(&points), 1.0);\n    }\n\n    /**\n     * Test case for calculating the area of a hexagon.\n     */\n    #[test]\n    fn test_area_hexagon() {\n        let points = vec![\n            Point { x: 0.0, y: 0.0 },\n            Point { x: 1.0, y: 0.0 },\n            Point { x: 1.5, y: 0.866 },\n            Point { x: 1.0, y: 1.732 },\n            Point { x: 0.0, y: 1.732 },\n            Point { x: -0.5, y: 0.866 },\n        ];\n\n        assert_eq!(area_of_polygon(&points), 2.598);\n    }\n}\n"
  },
  {
    "path": "src/math/area_under_curve.rs",
    "content": "pub fn area_under_curve(start: f64, end: f64, func: fn(f64) -> f64, step_count: usize) -> f64 {\n    assert!(step_count > 0);\n\n    let (start, end) = if start > end {\n        (end, start)\n    } else {\n        (start, end)\n    }; //swap if bounds reversed\n\n    let step_length: f64 = (end - start) / step_count as f64;\n    let mut area = 0f64;\n    let mut fx1 = func(start);\n    let mut fx2: f64;\n\n    for eval_point in (1..=step_count).map(|x| (x as f64 * step_length) + start) {\n        fx2 = func(eval_point);\n        area += (fx2 + fx1).abs() * step_length * 0.5;\n        fx1 = fx2;\n    }\n\n    area\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_linear_func() {\n        assert_eq!(area_under_curve(1f64, 2f64, |x| x, 10), 1.5000000000000002);\n    }\n\n    #[test]\n    fn test_quadratic_func() {\n        assert_eq!(\n            area_under_curve(1f64, 2f64, |x| x * x, 1000),\n            2.333333500000005\n        );\n    }\n\n    #[test]\n    fn test_zero_length() {\n        assert_eq!(area_under_curve(0f64, 0f64, |x| x * x, 1000), 0.0);\n    }\n\n    #[test]\n    fn test_reverse() {\n        assert_eq!(\n            area_under_curve(1f64, 2f64, |x| x, 10),\n            area_under_curve(2f64, 1f64, |x| x, 10)\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/armstrong_number.rs",
    "content": "pub fn is_armstrong_number(number: u32) -> bool {\n    let mut digits: Vec<u32> = Vec::new();\n    let mut num: u32 = number;\n\n    loop {\n        digits.push(num % 10);\n        num /= 10;\n        if num == 0 {\n            break;\n        }\n    }\n\n    let sum_nth_power_of_digits: u32 = digits\n        .iter()\n        .map(|digit| digit.pow(digits.len() as u32))\n        .sum();\n    sum_nth_power_of_digits == number\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn one_digit_armstrong_number() {\n        assert!(is_armstrong_number(1))\n    }\n    #[test]\n    fn two_digit_numbers_are_not_armstrong_numbers() {\n        assert!(!is_armstrong_number(15))\n    }\n    #[test]\n    fn three_digit_armstrong_number() {\n        assert!(is_armstrong_number(153))\n    }\n    #[test]\n    fn three_digit_non_armstrong_number() {\n        assert!(!is_armstrong_number(105))\n    }\n    #[test]\n    fn big_armstrong_number() {\n        assert!(is_armstrong_number(912985153))\n    }\n}\n"
  },
  {
    "path": "src/math/average.rs",
    "content": "#[doc = \"# Average\nMean, Median, and Mode, in mathematics, the three principal ways of designating the average value of a list of numbers.\nThe arithmetic mean is found by adding the numbers and dividing the sum by the number of numbers in the list.\nThis is what is most often meant by an average. The median is the middle value in a list ordered from smallest to largest.\nThe mode is the most frequently occurring value on the list.\n\nReference: https://www.britannica.com/science/mean-median-and-mode\n\nThis program approximates the mean, median and mode of a finite sequence.\nNote: Floats sequences are not allowed for `mode` function.\n\"]\nuse std::collections::HashMap;\nuse std::collections::HashSet;\n\nuse num_traits::Num;\n\nfn sum<T: Num + Copy>(sequence: Vec<T>) -> T {\n    sequence.iter().fold(T::zero(), |acc, x| acc + *x)\n}\n\n/// # Argument\n///\n/// * `sequence` - A vector of numbers.\n/// Returns mean of `sequence`.\npub fn mean<T: Num + Copy + num_traits::FromPrimitive>(sequence: Vec<T>) -> Option<T> {\n    let len = sequence.len();\n    if len == 0 {\n        return None;\n    }\n    Some(sum(sequence) / (T::from_usize(len).unwrap()))\n}\n\nfn mean_of_two<T: Num + Copy>(a: T, b: T) -> T {\n    (a + b) / (T::one() + T::one())\n}\n\n/// # Argument\n///\n/// * `sequence` - A vector of numbers.\n/// Returns median of `sequence`.\n\npub fn median<T: Num + Copy + PartialOrd>(mut sequence: Vec<T>) -> Option<T> {\n    if sequence.is_empty() {\n        return None;\n    }\n    sequence.sort_by(|a, b| a.partial_cmp(b).unwrap());\n    if sequence.len() % 2 == 1 {\n        let k = (sequence.len() + 1) / 2;\n        Some(sequence[k - 1])\n    } else {\n        let j = (sequence.len()) / 2;\n        Some(mean_of_two(sequence[j - 1], sequence[j]))\n    }\n}\n\nfn histogram<T: Eq + std::hash::Hash>(sequence: Vec<T>) -> HashMap<T, usize> {\n    sequence.into_iter().fold(HashMap::new(), |mut res, val| {\n        *res.entry(val).or_insert(0) += 1;\n        res\n    })\n}\n\n/// # Argument\n///\n/// * `sequence` - The input vector.\n/// Returns mode of `sequence`.\npub fn mode<T: Eq + std::hash::Hash>(sequence: Vec<T>) -> Option<HashSet<T>> {\n    if sequence.is_empty() {\n        return None;\n    }\n    let hist = histogram(sequence);\n    let max_count = *hist.values().max().unwrap();\n    Some(\n        hist.into_iter()\n            .filter(|(_, count)| *count == max_count)\n            .map(|(value, _)| value)\n            .collect(),\n    )\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    #[test]\n    fn median_test() {\n        assert_eq!(median(vec![4, 53, 2, 1, 9, 0, 2, 3, 6]).unwrap(), 3);\n        assert_eq!(median(vec![-9, -8, 0, 1, 2, 2, 3, 4, 6, 9, 53]).unwrap(), 2);\n        assert_eq!(median(vec![2, 3]).unwrap(), 2);\n        assert_eq!(median(vec![3.0, 2.0]).unwrap(), 2.5);\n        assert_eq!(median(vec![1.0, 700.0, 5.0]).unwrap(), 5.0);\n        assert!(median(Vec::<i32>::new()).is_none());\n        assert!(median(Vec::<f64>::new()).is_none());\n    }\n    #[test]\n    fn mode_test() {\n        assert_eq!(\n            mode(vec![4, 53, 2, 1, 9, 0, 2, 3, 6]).unwrap(),\n            HashSet::from([2])\n        );\n        assert_eq!(\n            mode(vec![-9, -8, 0, 1, 2, 2, 3, -1, -1, 9, -1, -9]).unwrap(),\n            HashSet::from([-1])\n        );\n        assert_eq!(mode(vec![\"a\", \"b\", \"a\"]).unwrap(), HashSet::from([\"a\"]));\n        assert_eq!(mode(vec![1, 2, 2, 1]).unwrap(), HashSet::from([1, 2]));\n        assert_eq!(mode(vec![1, 2, 2, 1, 3]).unwrap(), HashSet::from([1, 2]));\n        assert_eq!(mode(vec![1]).unwrap(), HashSet::from([1]));\n        assert!(mode(Vec::<i32>::new()).is_none());\n    }\n    #[test]\n    fn mean_test() {\n        assert_eq!(mean(vec![2023.1112]).unwrap(), 2023.1112);\n        assert_eq!(mean(vec![0.0, 1.0, 2.0, 3.0, 4.0]).unwrap(), 2.0);\n        assert_eq!(\n            mean(vec![-7.0, 4.0, 53.0, 2.0, 1.0, -9.0, 0.0, 2.0, 3.0, -6.0]).unwrap(),\n            4.3\n        );\n        assert_eq!(mean(vec![1, 2]).unwrap(), 1);\n        assert!(mean(Vec::<f64>::new()).is_none());\n        assert!(mean(Vec::<i32>::new()).is_none());\n    }\n}\n"
  },
  {
    "path": "src/math/baby_step_giant_step.rs",
    "content": "use crate::math::greatest_common_divisor;\n/// Baby-step Giant-step algorithm\n///\n/// Solving discrete logarithm problem:\n///     a^x = b (mod n) , with respect to gcd(a, n) == 1\n/// with O(sqrt(n)) time complexity.\n///\n/// Wikipedia reference: https://en.wikipedia.org/wiki/Baby-step_giant-step\n/// When a is the primitive root modulo n, the answer is unique.\n/// Otherwise it will return the smallest positive solution\nuse std::collections::HashMap;\n\npub fn baby_step_giant_step(a: usize, b: usize, n: usize) -> Option<usize> {\n    if greatest_common_divisor::greatest_common_divisor_stein(a as u64, n as u64) != 1 {\n        return None;\n    }\n\n    let mut h_map = HashMap::new();\n    let m = (n as f64).sqrt().ceil() as usize;\n    // baby step\n    let mut step = 1;\n    for i in 0..m {\n        h_map.insert((step * b) % n, i);\n        step = (step * a) % n;\n    }\n    // Now step = a^m (mod n), giant step\n    let giant_step = step;\n    for i in (m..=n).step_by(m) {\n        if let Some(v) = h_map.get(&step) {\n            return Some(i - v);\n        }\n        step = (step * giant_step) % n;\n    }\n    None\n}\n\n#[cfg(test)]\nmod tests {\n    use super::baby_step_giant_step;\n\n    #[test]\n    fn small_numbers() {\n        assert_eq!(baby_step_giant_step(5, 3, 11), Some(2));\n        assert_eq!(baby_step_giant_step(3, 83, 100), Some(9));\n        assert_eq!(baby_step_giant_step(9, 1, 61), Some(5));\n        assert_eq!(baby_step_giant_step(5, 1, 67), Some(22));\n        assert_eq!(baby_step_giant_step(7, 1, 45), Some(12));\n    }\n\n    #[test]\n    fn primitive_root_tests() {\n        assert_eq!(\n            baby_step_giant_step(3, 311401496, 998244353),\n            Some(178105253)\n        );\n        assert_eq!(\n            baby_step_giant_step(5, 324637211, 1000000007),\n            Some(976653449)\n        );\n    }\n\n    #[test]\n    fn random_numbers() {\n        assert_eq!(baby_step_giant_step(174857, 48604, 150991), Some(177));\n        assert_eq!(baby_step_giant_step(912103, 53821, 75401), Some(2644));\n        assert_eq!(baby_step_giant_step(448447, 365819, 671851), Some(23242));\n        assert_eq!(\n            baby_step_giant_step(220757103, 92430653, 434948279),\n            Some(862704)\n        );\n        assert_eq!(\n            baby_step_giant_step(176908456, 23538399, 142357679),\n            Some(14215560)\n        );\n    }\n\n    #[test]\n    fn no_solution() {\n        assert!(baby_step_giant_step(7, 6, 45).is_none());\n        assert!(baby_step_giant_step(23, 15, 85).is_none());\n        assert!(baby_step_giant_step(2, 1, 84).is_none());\n    }\n}\n"
  },
  {
    "path": "src/math/bell_numbers.rs",
    "content": "use num_bigint::BigUint;\nuse num_traits::{One, Zero};\nuse std::sync::RwLock;\n\n/// Returns the number of ways you can select r items given n options\nfn n_choose_r(n: u32, r: u32) -> BigUint {\n    if r == n || r == 0 {\n        return One::one();\n    }\n\n    if r > n {\n        return Zero::zero();\n    }\n\n    // Any combination will only need to be computed once, thus giving no need to\n    // memoize this function\n\n    let product: BigUint = (0..r).fold(BigUint::one(), |acc, x| {\n        (acc * BigUint::from(n - x)) / BigUint::from(x + 1)\n    });\n\n    product\n}\n\n/// A memoization table for storing previous results\nstruct MemTable {\n    buffer: Vec<BigUint>,\n}\n\nimpl MemTable {\n    const fn new() -> Self {\n        MemTable { buffer: Vec::new() }\n    }\n\n    fn get(&self, n: usize) -> Option<BigUint> {\n        if n == 0 || n == 1 {\n            Some(BigUint::one())\n        } else if let Some(entry) = self.buffer.get(n) {\n            if *entry == BigUint::zero() {\n                None\n            } else {\n                Some(entry.clone())\n            }\n        } else {\n            None\n        }\n    }\n\n    fn set(&mut self, n: usize, b: BigUint) {\n        self.buffer[n] = b;\n    }\n\n    #[inline]\n    fn capacity(&self) -> usize {\n        self.buffer.capacity()\n    }\n\n    #[inline]\n    fn resize(&mut self, new_size: usize) {\n        if new_size > self.buffer.len() {\n            self.buffer.resize(new_size, Zero::zero());\n        }\n    }\n}\n\n// Implemented with RwLock so it is accessible across threads\nstatic LOOKUP_TABLE_LOCK: RwLock<MemTable> = RwLock::new(MemTable::new());\n\npub fn bell_number(n: u32) -> BigUint {\n    let needs_resize;\n\n    // Check if number is already in lookup table\n    {\n        let lookup_table = LOOKUP_TABLE_LOCK.read().unwrap();\n\n        if let Some(entry) = lookup_table.get(n as usize) {\n            return entry;\n        }\n\n        needs_resize = (n + 1) as usize > lookup_table.capacity();\n    }\n\n    // Resize table before recursion so that if more values need to be added during recursion the table isn't\n    // reallocated every single time\n    if needs_resize {\n        let mut lookup_table = LOOKUP_TABLE_LOCK.write().unwrap();\n\n        lookup_table.resize((n + 1) as usize);\n    }\n\n    let new_bell_number: BigUint = (0..n).map(|x| bell_number(x) * n_choose_r(n - 1, x)).sum();\n\n    // Add new number to lookup table\n    {\n        let mut lookup_table = LOOKUP_TABLE_LOCK.write().unwrap();\n\n        lookup_table.set(n as usize, new_bell_number.clone());\n    }\n\n    new_bell_number\n}\n\n#[cfg(test)]\npub mod tests {\n    use super::*;\n    use std::str::FromStr;\n\n    #[test]\n    fn test_choose_zero() {\n        for i in 1..100 {\n            assert_eq!(n_choose_r(i, 0), One::one());\n        }\n    }\n\n    #[test]\n    fn test_combination() {\n        let five_choose_1 = BigUint::from(5u32);\n        assert_eq!(n_choose_r(5, 1), five_choose_1);\n        assert_eq!(n_choose_r(5, 4), five_choose_1);\n\n        let ten_choose_3 = BigUint::from(120u32);\n        assert_eq!(n_choose_r(10, 3), ten_choose_3);\n        assert_eq!(n_choose_r(10, 7), ten_choose_3);\n\n        let fourty_two_choose_thirty = BigUint::from_str(\"11058116888\").unwrap();\n        assert_eq!(n_choose_r(42, 30), fourty_two_choose_thirty);\n        assert_eq!(n_choose_r(42, 12), fourty_two_choose_thirty);\n    }\n\n    #[test]\n    fn test_bell_numbers() {\n        let bell_one = BigUint::from(1u32);\n        assert_eq!(bell_number(1), bell_one);\n\n        let bell_three = BigUint::from(5u32);\n        assert_eq!(bell_number(3), bell_three);\n\n        let bell_eight = BigUint::from(4140u32);\n        assert_eq!(bell_number(8), bell_eight);\n\n        let bell_six = BigUint::from(203u32);\n        assert_eq!(bell_number(6), bell_six);\n\n        let bell_twenty_six = BigUint::from_str(\"49631246523618756274\").unwrap();\n        assert_eq!(bell_number(26), bell_twenty_six);\n    }\n}\n"
  },
  {
    "path": "src/math/binary_exponentiation.rs",
    "content": "// Binary exponentiation is an algorithm to compute a power in O(logN) where N is the power.\n//\n// For example, to naively compute n^100, we multiply n 99 times for a O(N) algorithm.\n//\n// With binary exponentiation we can reduce the number of muliplications by only finding the binary\n// exponents. n^100 = n^64 * n^32 * n^4. We can compute n^64 by ((((n^2)^2)^2)...), which is\n// logN multiplications.\n//\n// We know which binary exponents to add by looking at the set bits in the power. For 100, we know\n// the bits for 64, 32, and 4 are set.\n\n// Computes n^p\npub fn binary_exponentiation(mut n: u64, mut p: u32) -> u64 {\n    let mut result_pow: u64 = 1;\n    while p > 0 {\n        if p & 1 == 1 {\n            result_pow *= n;\n        }\n        p >>= 1;\n        n *= n;\n    }\n    result_pow\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn basic() {\n        // Need to be careful about large exponents. It is easy to hit overflows.\n        assert_eq!(binary_exponentiation(2, 3), 8);\n        assert_eq!(binary_exponentiation(4, 12), 16777216);\n        assert_eq!(binary_exponentiation(6, 12), 2176782336);\n        assert_eq!(binary_exponentiation(10, 4), 10000);\n        assert_eq!(binary_exponentiation(20, 3), 8000);\n        assert_eq!(binary_exponentiation(3, 21), 10460353203);\n    }\n\n    #[test]\n    fn up_to_ten() {\n        // Compute all powers from up to ten, using the standard library as the source of truth.\n        for i in 0..10 {\n            for j in 0..10 {\n                println!(\"{i}, {j}\");\n                assert_eq!(binary_exponentiation(i, j), u64::pow(i, j))\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/math/binomial_coefficient.rs",
    "content": "extern crate num_bigint;\nextern crate num_traits;\n\nuse num_bigint::BigInt;\nuse num_traits::FromPrimitive;\n\n/// Calculate binomial coefficient (n choose k).\n///\n/// This function computes the binomial coefficient C(n, k) using BigInt\n/// for arbitrary precision arithmetic.\n///\n/// Formula:\n/// C(n, k) = n! / (k! * (n - k)!)\n///\n/// Reference:\n/// [Binomial Coefficient - Wikipedia](https://en.wikipedia.org/wiki/Binomial_coefficient)\n///\n/// # Arguments\n///\n/// * `n` - The total number of items.\n/// * `k` - The number of items to choose from `n`.\n///\n/// # Returns\n///\n/// Returns the binomial coefficient C(n, k) as a BigInt.\npub fn binom(n: u64, k: u64) -> BigInt {\n    let mut res = BigInt::from_u64(1).unwrap();\n    for i in 0..k {\n        res = (res * BigInt::from_u64(n - i).unwrap()) / BigInt::from_u64(i + 1).unwrap();\n    }\n    res\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_binom_5_2() {\n        assert_eq!(binom(5, 2), BigInt::from(10));\n    }\n\n    #[test]\n    fn test_binom_10_5() {\n        assert_eq!(binom(10, 5), BigInt::from(252));\n    }\n\n    #[test]\n    fn test_binom_0_0() {\n        assert_eq!(binom(0, 0), BigInt::from(1));\n    }\n\n    #[test]\n    fn test_binom_large_n_small_k() {\n        assert_eq!(binom(1000, 2), BigInt::from(499500));\n    }\n\n    #[test]\n    fn test_binom_random_1() {\n        // Random test case 1\n        assert_eq!(binom(7, 4), BigInt::from(35));\n    }\n\n    #[test]\n    fn test_binom_random_2() {\n        // Random test case 2\n        assert_eq!(binom(12, 3), BigInt::from(220));\n    }\n\n    #[test]\n    fn test_binom_random_3() {\n        // Random test case 3\n        assert_eq!(binom(20, 10), BigInt::from(184_756));\n    }\n}\n"
  },
  {
    "path": "src/math/catalan_numbers.rs",
    "content": "// Introduction to Catalan Numbers:\n// Catalan numbers are a sequence of natural numbers with many applications in combinatorial mathematics.\n// They are named after the Belgian mathematician Eugène Charles Catalan, who contributed to their study.\n// Catalan numbers appear in various combinatorial problems, including counting correct bracket sequences,\n// full binary trees, triangulations of polygons, and more.\n\n// For more information, refer to the Wikipedia page on Catalan numbers:\n// https://en.wikipedia.org/wiki/Catalan_number\n\n// Author: [Gyandeep] (https://github.com/Gyan172004)\n\nconst MOD: i64 = 1000000007; // Define your MOD value here\nconst MAX: usize = 1005; // Define your MAX value here\n\npub fn init_catalan() -> Vec<i64> {\n    let mut catalan = vec![0; MAX];\n    catalan[0] = 1;\n    catalan[1] = 1;\n\n    for i in 2..MAX {\n        catalan[i] = 0;\n        for j in 0..i {\n            catalan[i] += (catalan[j] * catalan[i - j - 1]) % MOD;\n            if catalan[i] >= MOD {\n                catalan[i] -= MOD;\n            }\n        }\n    }\n\n    catalan\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_catalan() {\n        let catalan = init_catalan();\n\n        // Test case 1: Catalan number for n = 0\n        assert_eq!(catalan[0], 1);\n\n        // Test case 2: Catalan number for n = 1\n        assert_eq!(catalan[1], 1);\n\n        // Test case 3: Catalan number for n = 5\n        assert_eq!(catalan[5], 42);\n\n        // Test case 4: Catalan number for n = 10\n        assert_eq!(catalan[10], 16796);\n\n        // Test case 5: Catalan number for n = 15\n        assert_eq!(catalan[15], 9694845);\n\n        // Print a success message if all tests pass\n        println!(\"All tests passed!\");\n    }\n}\n"
  },
  {
    "path": "src/math/ceil.rs",
    "content": "// In mathematics and computer science, the ceiling function maps x to the least integer greater than or equal to x\n// Source: https://en.wikipedia.org/wiki/Floor_and_ceiling_functions\n\npub fn ceil(x: f64) -> f64 {\n    let x_rounded_towards_zero = x as i32 as f64;\n    if x < 0. || x_rounded_towards_zero == x {\n        x_rounded_towards_zero\n    } else {\n        x_rounded_towards_zero + 1_f64\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn positive_decimal() {\n        let num = 1.10;\n        assert_eq!(ceil(num), num.ceil());\n    }\n\n    #[test]\n    fn positive_decimal_with_small_number() {\n        let num = 3.01;\n        assert_eq!(ceil(num), num.ceil());\n    }\n\n    #[test]\n    fn positive_integer() {\n        let num = 1.00;\n        assert_eq!(ceil(num), num.ceil());\n    }\n\n    #[test]\n    fn negative_decimal() {\n        let num = -1.10;\n        assert_eq!(ceil(num), num.ceil());\n    }\n\n    #[test]\n    fn negative_decimal_with_small_number() {\n        let num = -1.01;\n        assert_eq!(ceil(num), num.ceil());\n    }\n\n    #[test]\n    fn negative_integer() {\n        let num = -1.00;\n        assert_eq!(ceil(num), num.ceil());\n    }\n\n    #[test]\n    fn zero() {\n        let num = 0.00;\n        assert_eq!(ceil(num), num.ceil());\n    }\n}\n"
  },
  {
    "path": "src/math/chinese_remainder_theorem.rs",
    "content": "use super::extended_euclidean_algorithm;\n\nfn mod_inv(x: i32, n: i32) -> Option<i32> {\n    let (g, x, _) = extended_euclidean_algorithm(x, n);\n    if g == 1 {\n        Some((x % n + n) % n)\n    } else {\n        None\n    }\n}\n\npub fn chinese_remainder_theorem(residues: &[i32], modulli: &[i32]) -> Option<i32> {\n    let prod = modulli.iter().product::<i32>();\n\n    let mut sum = 0;\n\n    for (&residue, &modulus) in residues.iter().zip(modulli) {\n        let p = prod / modulus;\n        sum += residue * mod_inv(p, modulus)? * p\n    }\n    Some(sum % prod)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn basic() {\n        assert_eq!(chinese_remainder_theorem(&[3, 5, 7], &[2, 3, 1]), Some(5));\n        assert_eq!(chinese_remainder_theorem(&[1, 4, 6], &[3, 5, 7]), Some(34));\n        assert_eq!(chinese_remainder_theorem(&[1, 4, 6], &[1, 2, 0]), None);\n        assert_eq!(chinese_remainder_theorem(&[2, 5, 7], &[6, 9, 15]), None);\n    }\n}\n"
  },
  {
    "path": "src/math/collatz_sequence.rs",
    "content": "// collatz conjecture : https://en.wikipedia.org/wiki/Collatz_conjecture\npub fn sequence(mut n: usize) -> Option<Vec<usize>> {\n    if n == 0 {\n        return None;\n    }\n    let mut list: Vec<usize> = vec![];\n    while n != 1 {\n        list.push(n);\n        if n.is_multiple_of(2) {\n            n /= 2;\n        } else {\n            n = 3 * n + 1;\n        }\n    }\n    list.push(n);\n    Some(list)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::sequence;\n\n    #[test]\n    fn validity_check() {\n        assert_eq!(sequence(10).unwrap(), [10, 5, 16, 8, 4, 2, 1]);\n        assert_eq!(\n            sequence(15).unwrap(),\n            [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]\n        );\n        assert_eq!(sequence(0).unwrap_or_else(|| vec![0]), [0]);\n    }\n}\n"
  },
  {
    "path": "src/math/combinations.rs",
    "content": "// Function to calculate combinations of k elements from a set of n elements\npub fn combinations(n: i64, k: i64) -> i64 {\n    // Check if either n or k is negative, and panic if so\n    if n < 0 || k < 0 {\n        panic!(\"Please insert positive values\");\n    }\n\n    let mut res: i64 = 1;\n    for i in 0..k {\n        // Calculate the product of (n - i) and update the result\n        res *= n - i;\n        // Divide by (i + 1) to calculate the combination\n        res /= i + 1;\n    }\n\n    res\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    // Test case for combinations(10, 5)\n    #[test]\n    fn test_combinations_10_choose_5() {\n        assert_eq!(combinations(10, 5), 252);\n    }\n\n    // Test case for combinations(6, 3)\n    #[test]\n    fn test_combinations_6_choose_3() {\n        assert_eq!(combinations(6, 3), 20);\n    }\n\n    // Test case for combinations(20, 5)\n    #[test]\n    fn test_combinations_20_choose_5() {\n        assert_eq!(combinations(20, 5), 15504);\n    }\n\n    // Test case for invalid input (negative values)\n    #[test]\n    #[should_panic(expected = \"Please insert positive values\")]\n    fn test_combinations_invalid_input() {\n        combinations(-5, 10);\n    }\n}\n"
  },
  {
    "path": "src/math/cross_entropy_loss.rs",
    "content": "//! # Cross-Entropy Loss Function\n//!\n//! The `cross_entropy_loss` function calculates the cross-entropy loss between the actual and predicted probability distributions.\n//!\n//! Cross-entropy loss is commonly used in machine learning and deep learning to measure the dissimilarity between two probability distributions. It is often used in classification problems.\n//!\n//! ## Formula\n//!\n//! For a pair of actual and predicted probability distributions represented as vectors `actual` and `predicted`, the cross-entropy loss is calculated as:\n//!\n//! `L = -Σ(actual[i] * ln(predicted[i]))` for all `i` in the range of the vectors\n//!\n//! Where `ln` is the natural logarithm function, and `Σ` denotes the summation over all elements of the vectors.\n//!\n//! ## Cross-Entropy Loss Function Implementation\n//!\n//! This implementation takes two references to vectors of f64 values, `actual` and `predicted`, and returns the cross-entropy loss between them.\n//!\npub fn cross_entropy_loss(actual: &[f64], predicted: &[f64]) -> f64 {\n    let mut loss: Vec<f64> = Vec::new();\n    for (a, p) in actual.iter().zip(predicted.iter()) {\n        loss.push(-a * p.ln());\n    }\n    loss.iter().sum()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_cross_entropy_loss() {\n        let test_vector_actual = vec![0., 1., 0., 0., 0., 0.];\n        let test_vector = vec![0.1, 0.7, 0.1, 0.05, 0.05, 0.1];\n        assert_eq!(\n            cross_entropy_loss(&test_vector_actual, &test_vector),\n            0.35667494393873245\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/decimal_to_fraction.rs",
    "content": "pub fn decimal_to_fraction(decimal: f64) -> (i64, i64) {\n    // Calculate the fractional part of the decimal number\n    let fractional_part = decimal - decimal.floor();\n\n    // If the fractional part is zero, the number is already an integer\n    if fractional_part == 0.0 {\n        (decimal as i64, 1)\n    } else {\n        // Calculate the number of decimal places in the fractional part\n        let number_of_frac_digits = decimal.to_string().split('.').nth(1).unwrap_or(\"\").len();\n\n        // Calculate the numerator and denominator using integer multiplication\n        let numerator = (decimal * 10f64.powi(number_of_frac_digits as i32)) as i64;\n        let denominator = 10i64.pow(number_of_frac_digits as u32);\n\n        // Find the greatest common divisor (GCD) using Euclid's algorithm\n        let mut divisor = denominator;\n        let mut dividend = numerator;\n        while divisor != 0 {\n            let r = dividend % divisor;\n            dividend = divisor;\n            divisor = r;\n        }\n\n        // Reduce the fraction by dividing both numerator and denominator by the GCD\n        let gcd = dividend.abs();\n        let numerator = numerator / gcd;\n        let denominator = denominator / gcd;\n\n        (numerator, denominator)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_decimal_to_fraction_1() {\n        assert_eq!(decimal_to_fraction(2.0), (2, 1));\n    }\n\n    #[test]\n    fn test_decimal_to_fraction_2() {\n        assert_eq!(decimal_to_fraction(89.45), (1789, 20));\n    }\n\n    #[test]\n    fn test_decimal_to_fraction_3() {\n        assert_eq!(decimal_to_fraction(67.), (67, 1));\n    }\n\n    #[test]\n    fn test_decimal_to_fraction_4() {\n        assert_eq!(decimal_to_fraction(45.2), (226, 5));\n    }\n\n    #[test]\n    fn test_decimal_to_fraction_5() {\n        assert_eq!(decimal_to_fraction(1.5), (3, 2));\n    }\n\n    #[test]\n    fn test_decimal_to_fraction_6() {\n        assert_eq!(decimal_to_fraction(6.25), (25, 4));\n    }\n}\n"
  },
  {
    "path": "src/math/doomsday.rs",
    "content": "const T: [i32; 12] = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4];\n\npub fn doomsday(y: i32, m: i32, d: i32) -> i32 {\n    let y = if m < 3 { y - 1 } else { y };\n    (y + y / 4 - y / 100 + y / 400 + T[(m - 1) as usize] + d) % 7\n}\n\npub fn get_week_day(y: i32, m: i32, d: i32) -> String {\n    let day = doomsday(y, m, d);\n    let day_str = match day {\n        0 => \"Sunday\",\n        1 => \"Monday\",\n        2 => \"Tuesday\",\n        3 => \"Wednesday\",\n        4 => \"Thursday\",\n        5 => \"Friday\",\n        6 => \"Saturday\",\n        _ => \"Unknown\",\n    };\n\n    day_str.to_string()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn doomsday_test() {\n        assert_eq!(get_week_day(1990, 3, 21), \"Wednesday\");\n        assert_eq!(get_week_day(2000, 8, 24), \"Thursday\");\n        assert_eq!(get_week_day(2000, 10, 13), \"Friday\");\n        assert_eq!(get_week_day(2001, 4, 18), \"Wednesday\");\n        assert_eq!(get_week_day(2002, 3, 19), \"Tuesday\");\n    }\n}\n"
  },
  {
    "path": "src/math/elliptic_curve.rs",
    "content": "use std::collections::HashSet;\nuse std::fmt;\nuse std::hash::{Hash, Hasher};\nuse std::ops::{Add, Neg, Sub};\n\nuse crate::math::field::{Field, PrimeField};\nuse crate::math::quadratic_residue::legendre_symbol;\n\n/// Elliptic curve defined by `y^2 = x^3 + Ax + B` over a prime field `F` of\n/// characteristic != 2, 3\n///\n/// The coefficients of the elliptic curve are the constant parameters `A` and `B`.\n///\n/// Points form an abelian group with the neutral element [`EllipticCurve::infinity`]. The points\n/// are represented via affine coordinates ([`EllipticCurve::new`]) except for the points\n/// at infinity ([`EllipticCurve::infinity`]).\n///\n/// # Example\n///\n/// ```\n/// use the_algorithms_rust::math::{EllipticCurve, PrimeField};\n/// type E = EllipticCurve<PrimeField<7>, 1, 0>;\n/// let P = E::new(0, 0).expect(\"not on curve E\");\n/// assert_eq!(P + P, E::infinity());\n/// ```\n#[derive(Clone, Copy)]\npub struct EllipticCurve<F, const A: i64, const B: i64> {\n    infinity: bool,\n    x: F,\n    y: F,\n}\n\nimpl<F: Field, const A: i64, const B: i64> EllipticCurve<F, A, B> {\n    /// Point at infinity also the neutral element of the group\n    pub fn infinity() -> Self {\n        Self::check_invariants();\n        Self {\n            infinity: true,\n            x: F::ZERO,\n            y: F::ZERO,\n        }\n    }\n\n    /// Affine point\n    ///\n    ///\n    /// Return `None` if the coordinates are not on the curve\n    pub fn new(x: impl Into<F>, y: impl Into<F>) -> Option<Self> {\n        Self::check_invariants();\n        let x = x.into();\n        let y = y.into();\n        if Self::contains(x, y) {\n            Some(Self {\n                infinity: false,\n                x,\n                y,\n            })\n        } else {\n            None\n        }\n    }\n\n    /// Return `true` if this is the point at infinity\n    pub fn is_infinity(&self) -> bool {\n        self.infinity\n    }\n\n    /// The affine x-coordinate of the point\n    pub fn x(&self) -> &F {\n        &self.x\n    }\n\n    /// The affine y-coordinate of the point\n    pub fn y(&self) -> &F {\n        &self.y\n    }\n\n    /// The discrimant of the elliptic curve\n    pub const fn discriminant() -> i64 {\n        // Note: we can't return an element of F here, because it is not\n        // possible to declare a trait function as const (cf.\n        // <https://doc.rust-lang.org/error_codes/E0379.html>)\n        (-16 * (4 * A * A * A + 27 * B * B)) % (F::CHARACTERISTIC as i64)\n    }\n\n    fn contains(x: F, y: F) -> bool {\n        y * y == x * x * x + x.integer_mul(A) + F::ONE.integer_mul(B)\n    }\n\n    const fn check_invariants() {\n        assert!(F::CHARACTERISTIC != 2);\n        assert!(F::CHARACTERISTIC != 3);\n        assert!(Self::discriminant() != 0);\n    }\n}\n\n/// Elliptic curve methods over a prime field\nimpl<const P: u64, const A: i64, const B: i64> EllipticCurve<PrimeField<P>, A, B> {\n    /// Naive calculation of points via enumeration\n    // TODO: Implement via generators\n    pub fn points() -> impl Iterator<Item = Self> {\n        std::iter::once(Self::infinity()).chain(\n            PrimeField::elements()\n                .flat_map(|x| PrimeField::elements().filter_map(move |y| Self::new(x, y))),\n        )\n    }\n\n    /// Number of points on the elliptic curve over `F`, that is, `#E(F)`\n    pub fn cardinality() -> usize {\n        // TODO: implement counting for big P\n        Self::cardinality_counted_legendre()\n    }\n\n    /// Number of points on the elliptic curve over `F`, that is, `#E(F)`\n    ///\n    /// We simply count the number of points for each x coordinate and sum them up.\n    /// For that, we first precompute the table of all squares in `F`.\n    ///\n    /// Time complexity: O(P) <br>\n    /// Space complexity: O(P)\n    ///\n    /// Only fast for small fields.\n    pub fn cardinality_counted_table() -> usize {\n        let squares: HashSet<_> = PrimeField::<P>::elements().map(|x| x * x).collect();\n        1 + PrimeField::elements()\n            .map(|x| {\n                let y_square = x * x * x + x.integer_mul(A) + PrimeField::from_integer(B);\n                if y_square == PrimeField::ZERO {\n                    1\n                } else if squares.contains(&y_square) {\n                    2\n                } else {\n                    0\n                }\n            })\n            .sum::<usize>()\n    }\n\n    /// Number of points on the elliptic curve over `F`, that is, `#E(F)`\n    ///\n    /// We count the number of points for each x coordinate by using the [Legendre symbol] _(X |\n    /// P)_:\n    ///\n    /// _1 + (x^3 + Ax + B | P),_\n    ///\n    /// The total number of points is then:\n    ///\n    /// _#E(F) = 1 + P + Σ_x (x^3 + Ax + B | P)_ for _x_ in _F_.\n    ///\n    /// Time complexity: O(P) <br>\n    /// Space complexity: O(1)\n    ///\n    /// Only fast for small fields.\n    ///\n    /// [Legendre symbol]: https://en.wikipedia.org/wiki/Legendre_symbol\n    pub fn cardinality_counted_legendre() -> usize {\n        let cardinality: i64 = 1\n            + P as i64\n            + PrimeField::<P>::elements()\n                .map(|x| {\n                    let y_square = x * x * x + x.integer_mul(A) + PrimeField::from_integer(B);\n                    let y_square_int = y_square.to_integer();\n                    legendre_symbol(y_square_int, P)\n                })\n                .sum::<i64>();\n        cardinality\n            .try_into()\n            .expect(\"invalid legendre cardinality\")\n    }\n}\n\n/// Group law\nimpl<F: Field, const A: i64, const B: i64> Add for EllipticCurve<F, A, B> {\n    type Output = Self;\n\n    fn add(self, p: Self) -> Self::Output {\n        if self.infinity {\n            p\n        } else if p.infinity {\n            self\n        } else if self.x == p.x && self.y == -p.y {\n            // mirrored\n            Self::infinity()\n        } else {\n            let slope = if self.x == p.x {\n                ((self.x * self.x).integer_mul(3) + F::from_integer(A)) / self.y.integer_mul(2)\n            } else {\n                (self.y - p.y) / (self.x - p.x)\n            };\n            let x = slope * slope - self.x - p.x;\n            let y = -self.y + slope * (self.x - x);\n            Self::new(x, y).expect(\"elliptic curve group law failed\")\n        }\n    }\n}\n\n/// Inverse\nimpl<F: Field, const A: i64, const B: i64> Neg for EllipticCurve<F, A, B> {\n    type Output = Self;\n\n    fn neg(self) -> Self::Output {\n        if self.infinity {\n            self\n        } else {\n            Self::new(self.x, -self.y).expect(\"elliptic curves are x-axis symmetric\")\n        }\n    }\n}\n\n/// Difference\nimpl<F: Field, const A: i64, const B: i64> Sub for EllipticCurve<F, A, B> {\n    type Output = Self;\n\n    fn sub(self, p: Self) -> Self::Output {\n        self + (-p)\n    }\n}\n\n/// Debug representation via projective coordinates\nimpl<F: fmt::Debug, const A: i64, const B: i64> fmt::Debug for EllipticCurve<F, A, B> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        if self.infinity {\n            f.write_str(\"(0:0:1)\")\n        } else {\n            write!(f, \"({:?}:{:?}:1)\", self.x, self.y)\n        }\n    }\n}\n\n/// Equality of the elliptic curve points (short-circuit at infinity)\nimpl<F: Field, const A: i64, const B: i64> PartialEq for EllipticCurve<F, A, B> {\n    fn eq(&self, other: &Self) -> bool {\n        (self.infinity && other.infinity)\n            || (self.infinity == other.infinity && self.x == other.x && self.y == other.y)\n    }\n}\n\nimpl<F: Field, const A: i64, const B: i64> Eq for EllipticCurve<F, A, B> {}\n\nimpl<F: Field + Hash, const A: i64, const B: i64> Hash for EllipticCurve<F, A, B> {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        if self.infinity {\n            state.write_u8(1);\n            F::ZERO.hash(state);\n            F::ZERO.hash(state);\n        } else {\n            state.write_u8(0);\n            self.x.hash(state);\n            self.y.hash(state);\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::collections::HashSet;\n    use std::time::Instant;\n\n    use super::*;\n\n    #[test]\n    #[should_panic]\n    fn test_char_2_panic() {\n        EllipticCurve::<PrimeField<2>, -1, 1>::infinity();\n    }\n\n    #[test]\n    #[should_panic]\n    fn test_char_3_panic() {\n        EllipticCurve::<PrimeField<2>, -1, 1>::infinity();\n    }\n\n    #[test]\n    #[should_panic]\n    fn test_singular_panic() {\n        EllipticCurve::<PrimeField<5>, 0, 0>::infinity();\n    }\n\n    #[test]\n    fn e_5_1_0_group_table() {\n        type F = PrimeField<5>;\n        type E = EllipticCurve<F, 1, 0>;\n\n        assert_eq!(E::points().count(), 4);\n        let [a, b, c, d] = [\n            E::new(0, 0).unwrap(),\n            E::infinity(),\n            E::new(2, 0).unwrap(),\n            E::new(3, 0).unwrap(),\n        ];\n\n        assert_eq!(a + a, b);\n        assert_eq!(a + b, a);\n        assert_eq!(a + c, d);\n        assert_eq!(a + d, c);\n        assert_eq!(b + a, a);\n        assert_eq!(b + b, b);\n        assert_eq!(b + c, c);\n        assert_eq!(b + d, d);\n        assert_eq!(c + a, d);\n        assert_eq!(c + b, c);\n        assert_eq!(c + c, b);\n        assert_eq!(c + d, a);\n        assert_eq!(d + a, c);\n        assert_eq!(d + b, d);\n        assert_eq!(d + c, a);\n        assert_eq!(d + d, b);\n    }\n\n    #[test]\n    fn group_law() {\n        fn test<const P: u64>() {\n            type E<const P: u64> = EllipticCurve<PrimeField<P>, 1, 0>;\n\n            let o = E::<P>::infinity();\n            assert_eq!(-o, o);\n\n            let points: Vec<_> = E::points().collect();\n            for &p in &points {\n                assert_eq!(p + (-p), o); // inverse\n                assert_eq!((-p) + p, o); // inverse\n                assert_eq!(p - p, o); //inverse\n                assert_eq!(p + o, p); // neutral\n                assert_eq!(o + p, p); //neutral\n\n                for &q in &points {\n                    assert_eq!(p + q, q + p); // commutativity\n\n                    // associativity\n                    for &s in &points {\n                        assert_eq!((p + q) + s, p + (q + s));\n                    }\n                }\n            }\n        }\n        test::<5>();\n        test::<7>();\n        test::<11>();\n        test::<13>();\n        test::<17>();\n        test::<19>();\n        test::<23>();\n    }\n\n    #[test]\n    fn cardinality() {\n        fn test<const P: u64>(expected: usize) {\n            type E<const P: u64> = EllipticCurve<PrimeField<P>, 1, 0>;\n            assert_eq!(E::<P>::cardinality(), expected);\n            assert_eq!(E::<P>::cardinality_counted_table(), expected);\n            assert_eq!(E::<P>::cardinality_counted_legendre(), expected);\n        }\n        test::<5>(4);\n        test::<7>(8);\n        test::<11>(12);\n        test::<13>(20);\n        test::<17>(16);\n        test::<19>(20);\n        test::<23>(24);\n    }\n\n    #[test]\n    #[ignore = \"slow test for measuring time\"]\n    fn cardinality_perf() {\n        const P: u64 = 1000003;\n        type E = EllipticCurve<PrimeField<P>, 1, 0>;\n        const EXPECTED: usize = 1000004;\n\n        let now = Instant::now();\n        assert_eq!(E::cardinality_counted_table(), EXPECTED);\n        println!(\"cardinality_counted_table    : {:?}\", now.elapsed());\n        let now = Instant::now();\n        assert_eq!(E::cardinality_counted_legendre(), EXPECTED);\n        println!(\"cardinality_counted_legendre : {:?}\", now.elapsed());\n    }\n\n    #[test]\n    #[ignore = \"slow test showing that cadinality is not yet feasible to compute for a large prime\"]\n    fn cardinality_large_prime() {\n        const P: u64 = 2_u64.pow(63) - 25; // largest prime fitting into i64\n        type E = EllipticCurve<PrimeField<P>, 1, 0>;\n        const EXPECTED: usize = 9223372041295506260;\n\n        let now = Instant::now();\n        assert_eq!(E::cardinality(), EXPECTED);\n        println!(\"cardinality: {:?}\", now.elapsed());\n    }\n\n    #[test]\n    fn test_points() {\n        type F = PrimeField<5>;\n        type E = EllipticCurve<F, 1, 0>;\n\n        let points: HashSet<_> = E::points().collect();\n        let expected: HashSet<_> = [\n            E::infinity(),\n            E::new(0, 0).unwrap(),\n            E::new(2, 0).unwrap(),\n            E::new(3, 0).unwrap(),\n        ]\n        .into_iter()\n        .collect();\n        assert_eq!(points, expected);\n    }\n}\n"
  },
  {
    "path": "src/math/euclidean_distance.rs",
    "content": "// Author : cyrixninja\n// Calculate the Euclidean distance between two vectors\n// Wikipedia : https://en.wikipedia.org/wiki/Euclidean_distance\n\npub fn euclidean_distance(vector_1: &Vector, vector_2: &Vector) -> f64 {\n    // Calculate the Euclidean distance using the provided vectors.\n    let squared_sum: f64 = vector_1\n        .iter()\n        .zip(vector_2.iter())\n        .map(|(&a, &b)| (a - b).powi(2))\n        .sum();\n\n    squared_sum.sqrt()\n}\n\ntype Vector = Vec<f64>;\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    // Define a test function for the euclidean_distance function.\n    #[test]\n    fn test_euclidean_distance() {\n        // First test case: 2D vectors\n        let vec1_2d = vec![1.0, 2.0];\n        let vec2_2d = vec![4.0, 6.0];\n\n        // Calculate the Euclidean distance\n        let result_2d = euclidean_distance(&vec1_2d, &vec2_2d);\n        assert_eq!(result_2d, 5.0);\n\n        // Second test case: 4D vectors\n        let vec1_4d = vec![1.0, 2.0, 3.0, 4.0];\n        let vec2_4d = vec![5.0, 6.0, 7.0, 8.0];\n\n        // Calculate the Euclidean distance\n        let result_4d = euclidean_distance(&vec1_4d, &vec2_4d);\n        assert_eq!(result_4d, 8.0);\n    }\n}\n"
  },
  {
    "path": "src/math/exponential_linear_unit.rs",
    "content": "//! # Exponential Linear Unit (ELU) Function\n//!\n//! The `exponential_linear_unit` function computes the Exponential Linear Unit (ELU) values of a given vector\n//! of f64 numbers with a specified alpha parameter.\n//!\n//! The ELU activation function is commonly used in neural networks as an alternative to the Leaky ReLU function.\n//! It introduces a small negative slope (controlled by the alpha parameter) for the negative input values and has\n//! an exponential growth for positive values, which can help mitigate the vanishing gradient problem.\n//!\n//! ## Formula\n//!\n//! For a given input vector `x` and an alpha parameter `alpha`, the ELU function computes the output\n//! `y` as follows:\n//!\n//! `y_i = { x_i if x_i >= 0, alpha * (e^x_i - 1) if x_i < 0 }`\n//!\n//! Where `e` is the mathematical constant (approximately 2.71828).\n//!\n//! ## Exponential Linear Unit (ELU) Function Implementation\n//!\n//! This implementation takes a reference to a vector of f64 values and an alpha parameter, and returns a new\n//! vector with the ELU transformation applied to each element. The input vector is not altered.\n//!\n\nuse std::f64::consts::E;\n\npub fn exponential_linear_unit(vector: &Vec<f64>, alpha: f64) -> Vec<f64> {\n    let mut _vector = vector.to_owned();\n\n    for value in &mut _vector {\n        if value < &mut 0. {\n            *value *= alpha * (E.powf(*value) - 1.);\n        }\n    }\n\n    _vector\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_exponential_linear_unit() {\n        let test_vector = vec![-10., 2., -3., 4., -5., 10., 0.05];\n        let alpha = 0.01;\n        assert_eq!(\n            exponential_linear_unit(&test_vector, alpha),\n            vec![\n                0.09999546000702375,\n                2.0,\n                0.028506387948964082,\n                4.0,\n                0.049663102650045726,\n                10.0,\n                0.05\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/extended_euclidean_algorithm.rs",
    "content": "fn update_step(a: &mut i32, old_a: &mut i32, quotient: i32) {\n    let temp = *a;\n    *a = *old_a - quotient * temp;\n    *old_a = temp;\n}\n\npub fn extended_euclidean_algorithm(a: i32, b: i32) -> (i32, i32, i32) {\n    let (mut old_r, mut rem) = (a, b);\n    let (mut old_s, mut coeff_s) = (1, 0);\n    let (mut old_t, mut coeff_t) = (0, 1);\n\n    while rem != 0 {\n        let quotient = old_r / rem;\n\n        update_step(&mut rem, &mut old_r, quotient);\n        update_step(&mut coeff_s, &mut old_s, quotient);\n        update_step(&mut coeff_t, &mut old_t, quotient);\n    }\n\n    (old_r, old_s, old_t)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn basic() {\n        assert_eq!(extended_euclidean_algorithm(101, 13), (1, 4, -31));\n        assert_eq!(extended_euclidean_algorithm(123, 19), (1, -2, 13));\n        assert_eq!(extended_euclidean_algorithm(25, 36), (1, 13, -9));\n        assert_eq!(extended_euclidean_algorithm(69, 54), (3, -7, 9));\n        assert_eq!(extended_euclidean_algorithm(55, 79), (1, 23, -16));\n        assert_eq!(extended_euclidean_algorithm(33, 44), (11, -1, 1));\n        assert_eq!(extended_euclidean_algorithm(50, 70), (10, 3, -2));\n    }\n}\n"
  },
  {
    "path": "src/math/factorial.rs",
    "content": "use num_bigint::BigUint;\nuse num_traits::One;\n#[allow(unused_imports)]\nuse std::str::FromStr;\n\npub fn factorial(number: u64) -> u64 {\n    // Base cases: 0! and 1! are both equal to 1\n    if number == 0 || number == 1 {\n        1\n    } else {\n        // Calculate factorial using the product of the range from 2 to the given number (inclusive)\n        (2..=number).product()\n    }\n}\n\npub fn factorial_recursive(n: u64) -> u64 {\n    // Base cases: 0! and 1! are both equal to 1\n    if n == 0 || n == 1 {\n        1\n    } else {\n        // Calculate factorial recursively by multiplying the current number with factorial of (n - 1)\n        n * factorial_recursive(n - 1)\n    }\n}\n\npub fn factorial_bigmath(num: u32) -> BigUint {\n    let mut result: BigUint = One::one();\n    for i in 1..=num {\n        result *= i;\n    }\n    result\n}\n\n// Module for tests\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    // Test cases for the iterative factorial function\n    #[test]\n    fn test_factorial() {\n        assert_eq!(factorial(0), 1);\n        assert_eq!(factorial(1), 1);\n        assert_eq!(factorial(6), 720);\n        assert_eq!(factorial(10), 3628800);\n        assert_eq!(factorial(20), 2432902008176640000);\n    }\n\n    // Test cases for the recursive factorial function\n    #[test]\n    fn test_factorial_recursive() {\n        assert_eq!(factorial_recursive(0), 1);\n        assert_eq!(factorial_recursive(1), 1);\n        assert_eq!(factorial_recursive(6), 720);\n        assert_eq!(factorial_recursive(10), 3628800);\n        assert_eq!(factorial_recursive(20), 2432902008176640000);\n    }\n\n    #[test]\n    fn basic_factorial() {\n        assert_eq!(factorial_bigmath(10), BigUint::from_str(\"3628800\").unwrap());\n        assert_eq!(\n            factorial_bigmath(50),\n            BigUint::from_str(\"30414093201713378043612608166064768844377641568960512000000000000\")\n                .unwrap()\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/factors.rs",
    "content": "/// Factors are natural numbers which can divide a given natural number to give a remainder of zero\n/// Hence 1, 2, 3 and 6 are all factors of 6, as they divide the number 6 completely,\n/// leaving no remainder.\n/// This function is to list out all the factors of a given number 'n'\n\npub fn factors(number: u64) -> Vec<u64> {\n    let mut factors: Vec<u64> = Vec::new();\n\n    for i in 1..=((number as f64).sqrt() as u64) {\n        if number.is_multiple_of(i) {\n            factors.push(i);\n            if i != number / i {\n                factors.push(number / i);\n            }\n        }\n    }\n\n    factors.sort();\n    factors\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn prime_number() {\n        assert_eq!(vec![1, 59], factors(59));\n    }\n\n    #[test]\n    fn highly_composite_number() {\n        assert_eq!(\n            vec![\n                1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 18, 20, 24, 30, 36, 40, 45, 60, 72, 90, 120,\n                180, 360\n            ],\n            factors(360)\n        );\n    }\n\n    #[test]\n    fn composite_number() {\n        assert_eq!(vec![1, 3, 23, 69], factors(69));\n    }\n}\n"
  },
  {
    "path": "src/math/fast_fourier_transform.rs",
    "content": "use std::ops::{Add, Mul, MulAssign, Sub};\n\n// f64 complex\n#[derive(Clone, Copy, Debug)]\npub struct Complex64 {\n    pub re: f64,\n    pub im: f64,\n}\n\nimpl Complex64 {\n    #[inline]\n    pub fn new(re: f64, im: f64) -> Self {\n        Self { re, im }\n    }\n\n    #[inline]\n    pub fn square_norm(&self) -> f64 {\n        self.re * self.re + self.im * self.im\n    }\n\n    #[inline]\n    pub fn norm(&self) -> f64 {\n        self.square_norm().sqrt()\n    }\n\n    #[inline]\n    pub fn inverse(&self) -> Complex64 {\n        let nrm = self.square_norm();\n        Complex64 {\n            re: self.re / nrm,\n            im: -self.im / nrm,\n        }\n    }\n}\n\nimpl Default for Complex64 {\n    #[inline]\n    fn default() -> Self {\n        Self { re: 0.0, im: 0.0 }\n    }\n}\n\nimpl Add<Complex64> for Complex64 {\n    type Output = Complex64;\n\n    #[inline]\n    fn add(self, other: Complex64) -> Complex64 {\n        Complex64 {\n            re: self.re + other.re,\n            im: self.im + other.im,\n        }\n    }\n}\n\nimpl Sub<Complex64> for Complex64 {\n    type Output = Complex64;\n\n    #[inline]\n    fn sub(self, other: Complex64) -> Complex64 {\n        Complex64 {\n            re: self.re - other.re,\n            im: self.im - other.im,\n        }\n    }\n}\n\nimpl Mul<Complex64> for Complex64 {\n    type Output = Complex64;\n\n    #[inline]\n    fn mul(self, other: Complex64) -> Complex64 {\n        Complex64 {\n            re: self.re * other.re - self.im * other.im,\n            im: self.re * other.im + self.im * other.re,\n        }\n    }\n}\n\nimpl MulAssign<Complex64> for Complex64 {\n    #[inline]\n    fn mul_assign(&mut self, other: Complex64) {\n        let tmp = self.re * other.im + self.im * other.re;\n        self.re = self.re * other.re - self.im * other.im;\n        self.im = tmp;\n    }\n}\n\npub fn fast_fourier_transform_input_permutation(length: usize) -> Vec<usize> {\n    let mut result = Vec::new();\n    result.reserve_exact(length);\n    for i in 0..length {\n        result.push(i);\n    }\n    let mut reverse = 0_usize;\n    let mut position = 1_usize;\n    while position < length {\n        let mut bit = length >> 1;\n        while bit & reverse != 0 {\n            reverse ^= bit;\n            bit >>= 1;\n        }\n        reverse ^= bit;\n        // This is equivalent to adding 1 to a reversed number\n        if position < reverse {\n            // Only swap each element once\n            result.swap(position, reverse);\n        }\n        position += 1;\n    }\n    result\n}\n\npub fn fast_fourier_transform(input: &[f64], input_permutation: &[usize]) -> Vec<Complex64> {\n    let n = input.len();\n    let mut result = Vec::new();\n    result.reserve_exact(n);\n    for position in input_permutation {\n        result.push(Complex64::new(input[*position], 0.0));\n    }\n    let mut segment_length = 1_usize;\n    while segment_length < n {\n        segment_length <<= 1;\n        let angle: f64 = std::f64::consts::TAU / segment_length as f64;\n        let w_len = Complex64::new(angle.cos(), angle.sin());\n        for segment_start in (0..n).step_by(segment_length) {\n            let mut w = Complex64::new(1.0, 0.0);\n            for position in segment_start..(segment_start + segment_length / 2) {\n                let a = result[position];\n                let b = result[position + segment_length / 2] * w;\n                result[position] = a + b;\n                result[position + segment_length / 2] = a - b;\n                w *= w_len;\n            }\n        }\n    }\n    result\n}\n\npub fn inverse_fast_fourier_transform(\n    input: &[Complex64],\n    input_permutation: &[usize],\n) -> Vec<f64> {\n    let n = input.len();\n    let mut result = Vec::new();\n    result.reserve_exact(n);\n    for position in input_permutation {\n        result.push(input[*position]);\n    }\n    let mut segment_length = 1_usize;\n    while segment_length < n {\n        segment_length <<= 1;\n        let angle: f64 = -std::f64::consts::TAU / segment_length as f64;\n        let w_len = Complex64::new(angle.cos(), angle.sin());\n        for segment_start in (0..n).step_by(segment_length) {\n            let mut w = Complex64::new(1.0, 0.0);\n            for position in segment_start..(segment_start + segment_length / 2) {\n                let a = result[position];\n                let b = result[position + segment_length / 2] * w;\n                result[position] = a + b;\n                result[position + segment_length / 2] = a - b;\n                w *= w_len;\n            }\n        }\n    }\n    let scale = 1.0 / n as f64;\n    result.iter().map(|x| x.re * scale).collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    fn almost_equal(a: f64, b: f64, epsilon: f64) -> bool {\n        (a - b).abs() < epsilon\n    }\n\n    const EPSILON: f64 = 1e-6;\n\n    #[test]\n    fn small_polynomial_returns_self() {\n        let polynomial = vec![1.0f64, 1.0, 0.0, 2.5];\n        let permutation = fast_fourier_transform_input_permutation(polynomial.len());\n        let fft = fast_fourier_transform(&polynomial, &permutation);\n        let ifft = inverse_fast_fourier_transform(&fft, &permutation);\n        for (x, y) in ifft.iter().zip(polynomial.iter()) {\n            assert!(almost_equal(*x, *y, EPSILON));\n        }\n    }\n\n    #[test]\n    fn square_small_polynomial() {\n        let mut polynomial = vec![1.0f64, 1.0, 0.0, 2.0];\n        polynomial.append(&mut vec![0.0; 4]);\n        let permutation = fast_fourier_transform_input_permutation(polynomial.len());\n        let mut fft = fast_fourier_transform(&polynomial, &permutation);\n        for num in fft.iter_mut() {\n            *num *= *num;\n        }\n        let ifft = inverse_fast_fourier_transform(&fft, &permutation);\n        let expected = [1.0, 2.0, 1.0, 4.0, 4.0, 0.0, 4.0, 0.0, 0.0];\n        for (x, y) in ifft.iter().zip(expected.iter()) {\n            assert!(almost_equal(*x, *y, EPSILON));\n        }\n    }\n\n    #[test]\n    #[ignore]\n    fn square_big_polynomial() {\n        // This test case takes ~1050ms on my machine in unoptimized mode,\n        // but it takes ~70ms in release mode.\n        let n = 1 << 17; // ~100_000\n        let mut polynomial = vec![1.0f64; n];\n        polynomial.append(&mut vec![0.0f64; n]);\n        let permutation = fast_fourier_transform_input_permutation(polynomial.len());\n        let mut fft = fast_fourier_transform(&polynomial, &permutation);\n        for num in fft.iter_mut() {\n            *num *= *num;\n        }\n        let ifft = inverse_fast_fourier_transform(&fft, &permutation);\n        let expected = (0..((n << 1) - 1)).map(|i| std::cmp::min(i + 1, (n << 1) - 1 - i) as f64);\n        for (&x, y) in ifft.iter().zip(expected) {\n            assert!(almost_equal(x, y, EPSILON));\n        }\n    }\n}\n"
  },
  {
    "path": "src/math/fast_power.rs",
    "content": "/// fast_power returns the result of base^power mod modulus\npub fn fast_power(mut base: usize, mut power: usize, modulus: usize) -> usize {\n    assert!(base >= 1);\n\n    let mut res = 1;\n    while power > 0 {\n        if power & 1 == 1 {\n            res = (res * base) % modulus;\n        }\n        base = (base * base) % modulus;\n        power >>= 1;\n    }\n    res\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test() {\n        const MOD: usize = 1000000007;\n        assert_eq!(fast_power(2, 1, MOD), 2);\n        assert_eq!(fast_power(2, 2, MOD), 4);\n        assert_eq!(fast_power(2, 4, MOD), 16);\n        assert_eq!(fast_power(3, 4, MOD), 81);\n        assert_eq!(fast_power(2, 100, MOD), 976371285);\n    }\n}\n"
  },
  {
    "path": "src/math/faster_perfect_numbers.rs",
    "content": "use super::{mersenne_primes::is_mersenne_prime, prime_numbers::prime_numbers};\nuse std::convert::TryInto;\n\n/*\n    Generates a list of perfect numbers till `num` using the Lucas Lehmer test algorithm.\n    url : https://en.wikipedia.org/wiki/Lucas%E2%80%93Lehmer_primality_test\n*/\npub fn generate_perfect_numbers(num: usize) -> Vec<usize> {\n    let mut results = Vec::new();\n    let prime_limit = get_prime_limit(num);\n\n    for i in prime_numbers(prime_limit).iter() {\n        let prime = *i;\n        if is_mersenne_prime(prime) {\n            results.push(\n                (2_usize.pow(prime.try_into().unwrap()) - 1)\n                    * (2_usize.pow((prime - 1).try_into().unwrap())),\n            );\n        }\n    }\n    results.into_iter().filter(|x| *x <= num).collect()\n}\n\n// Gets an approximate limit for the generate_perfect_numbers function\nfn get_prime_limit(num: usize) -> usize {\n    (((num * 8 + 1) as f64).log2() as usize) / 2_usize\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn perfect_numbers_till_n() {\n        let n = 335564540;\n        assert_eq!(generate_perfect_numbers(n), [6, 28, 496, 8128, 33550336]);\n        assert_eq!(generate_perfect_numbers(40), [6, 28]);\n        assert_eq!(generate_perfect_numbers(0), []);\n    }\n}\n"
  },
  {
    "path": "src/math/field.rs",
    "content": "use core::fmt;\nuse std::hash::{Hash, Hasher};\nuse std::ops::{Add, Div, Mul, Neg, Sub};\n\n/// A field\n///\n/// <https://en.wikipedia.org/wiki/Field_(mathematics)>\npub trait Field:\n    Neg<Output = Self>\n    + Add<Output = Self>\n    + Sub<Output = Self>\n    + Mul<Output = Self>\n    + Div<Output = Self>\n    + Eq\n    + Copy\n    + fmt::Debug\n{\n    const CHARACTERISTIC: u64;\n    const ZERO: Self;\n    const ONE: Self;\n\n    /// Multiplicative inverse\n    fn inverse(self) -> Self;\n\n    /// Z-mod structure\n    fn integer_mul(self, a: i64) -> Self;\n    fn from_integer(a: i64) -> Self {\n        Self::ONE.integer_mul(a)\n    }\n\n    /// Iterate over all elements in this field\n    ///\n    /// The iterator finishes only for finite fields.\n    type ElementsIter: Iterator<Item = Self>;\n    fn elements() -> Self::ElementsIter;\n}\n\n/// Prime field of order `P`, that is, finite field `GF(P) = ℤ/Pℤ`\n///\n/// Only primes `P` <= 2^63 - 25 are supported, because the field elements are represented by `i64`.\n// TODO: Extend field implementation for any prime `P` by e.g. using u32 blocks.\n#[derive(Clone, Copy)]\npub struct PrimeField<const P: u64> {\n    a: i64,\n}\n\nimpl<const P: u64> PrimeField<P> {\n    /// Reduces the representation into the range [0, p)\n    fn reduce(self) -> Self {\n        let Self { a } = self;\n        let p: i64 = P.try_into().expect(\"module not fitting into signed 64 bit\");\n        let a = a.rem_euclid(p);\n        assert!(a >= 0);\n        Self { a }\n    }\n\n    /// Returns the positive integer in the range [0, p) representing this element\n    pub fn to_integer(&self) -> u64 {\n        self.reduce().a as u64\n    }\n}\n\nimpl<const P: u64> From<i64> for PrimeField<P> {\n    fn from(a: i64) -> Self {\n        Self { a }\n    }\n}\n\nimpl<const P: u64> PartialEq for PrimeField<P> {\n    fn eq(&self, other: &Self) -> bool {\n        self.reduce().a == other.reduce().a\n    }\n}\n\nimpl<const P: u64> Eq for PrimeField<P> {}\n\nimpl<const P: u64> Neg for PrimeField<P> {\n    type Output = Self;\n\n    fn neg(self) -> Self::Output {\n        Self { a: -self.a }\n    }\n}\n\nimpl<const P: u64> Add for PrimeField<P> {\n    type Output = Self;\n\n    fn add(self, rhs: Self) -> Self::Output {\n        Self {\n            a: self.a.checked_add(rhs.a).unwrap_or_else(|| {\n                let x = self.reduce();\n                let y = rhs.reduce();\n                x.a + y.a\n            }),\n        }\n    }\n}\n\nimpl<const P: u64> Sub for PrimeField<P> {\n    type Output = Self;\n\n    fn sub(self, rhs: Self) -> Self::Output {\n        Self {\n            a: self.a.checked_sub(rhs.a).unwrap_or_else(|| {\n                let x = self.reduce();\n                let y = rhs.reduce();\n                x.a - y.a\n            }),\n        }\n    }\n}\n\nimpl<const P: u64> Mul for PrimeField<P> {\n    type Output = Self;\n\n    fn mul(self, rhs: Self) -> Self::Output {\n        Self {\n            a: self.a.checked_mul(rhs.a).unwrap_or_else(|| {\n                let x = self.reduce();\n                let y = rhs.reduce();\n                x.a * y.a\n            }),\n        }\n    }\n}\n\nimpl<const P: u64> Div for PrimeField<P> {\n    type Output = Self;\n\n    #[allow(clippy::suspicious_arithmetic_impl)]\n    fn div(self, rhs: Self) -> Self::Output {\n        self * rhs.inverse()\n    }\n}\n\nimpl<const P: u64> fmt::Debug for PrimeField<P> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let x = self.reduce();\n        write!(f, \"{}\", x.reduce().a)\n    }\n}\n\nimpl<const P: u64> Field for PrimeField<P> {\n    const CHARACTERISTIC: u64 = P;\n    const ZERO: Self = Self { a: 0 };\n    const ONE: Self = Self { a: 1 };\n\n    fn inverse(self) -> Self {\n        assert_ne!(self.a, 0);\n        Self {\n            a: mod_inverse(\n                self.a,\n                P.try_into().expect(\"module not fitting into signed 64 bit\"),\n            ),\n        }\n    }\n\n    fn integer_mul(self, mut n: i64) -> Self {\n        if n == 0 {\n            return Self::ZERO;\n        }\n        let mut x = self;\n        if n < 0 {\n            x = -x;\n            n = -n;\n        }\n        let mut y = Self::ZERO;\n        while n > 1 {\n            if n % 2 == 1 {\n                y = y + x;\n                n -= 1;\n            }\n            x = x + x;\n            n /= 2;\n        }\n        x + y\n    }\n\n    type ElementsIter = PrimeFieldElementsIter<P>;\n\n    fn elements() -> Self::ElementsIter {\n        PrimeFieldElementsIter::default()\n    }\n}\n\n#[derive(Default)]\npub struct PrimeFieldElementsIter<const P: u64> {\n    x: i64,\n}\n\nimpl<const P: u64> Iterator for PrimeFieldElementsIter<P> {\n    type Item = PrimeField<P>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        if self.x as u64 == P {\n            None\n        } else {\n            let res = PrimeField::from_integer(self.x);\n            self.x += 1;\n            Some(res)\n        }\n    }\n}\n\nimpl<const P: u64> Hash for PrimeField<P> {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        let Self { a } = self.reduce();\n        state.write_i64(a);\n    }\n}\n\n// TODO: should we use extended_euclidean_algorithm adjusted to i64?\nfn mod_inverse(mut a: i64, mut b: i64) -> i64 {\n    let mut s = 1;\n    let mut t = 0;\n    let step = |x, y, q| (y, x - q * y);\n    while b != 0 {\n        let q = a / b;\n        (a, b) = step(a, b, q);\n        (s, t) = step(s, t, q);\n    }\n    assert!(a == 1 || a == -1);\n    a * s\n}\n\n#[cfg(test)]\nmod tests {\n    use std::collections::HashSet;\n\n    use super::*;\n\n    #[test]\n    fn test_field_elements() {\n        fn test<const P: u64>() {\n            let expected: HashSet<PrimeField<P>> = (0..P as i64).map(Into::into).collect();\n            for gen in 1..P - 1 {\n                // every field element != 0 generates the whole field additively\n                let gen = PrimeField::from(gen as i64);\n                let mut generated: HashSet<PrimeField<P>> = std::iter::once(gen).collect();\n                let mut x = gen;\n                for _ in 0..P {\n                    x = x + gen;\n                    generated.insert(x);\n                }\n                assert_eq!(generated, expected);\n            }\n        }\n        test::<5>();\n        test::<7>();\n        test::<11>();\n        test::<13>();\n        test::<17>();\n        test::<19>();\n        test::<23>();\n        test::<71>();\n        test::<101>();\n    }\n\n    #[test]\n    fn large_prime_field() {\n        const P: u64 = 2_u64.pow(63) - 25; // largest prime fitting into i64\n        type F = PrimeField<P>;\n        let x = F::from(P as i64 - 1);\n        let y = x.inverse();\n        assert_eq!(x * y, F::ONE);\n    }\n\n    #[test]\n    fn inverse() {\n        fn test<const P: u64>() {\n            for x in -7..7 {\n                let x = PrimeField::<P>::from(x);\n                if x != PrimeField::ZERO {\n                    // multiplicative\n                    assert_eq!(x.inverse() * x, PrimeField::ONE);\n                    assert_eq!(x * x.inverse(), PrimeField::ONE);\n                    assert_eq!((x.inverse().a * x.a).rem_euclid(P as i64), 1);\n                    assert_eq!(x / x, PrimeField::ONE);\n                }\n                // additive\n                assert_eq!(x + (-x), PrimeField::ZERO);\n                assert_eq!((-x) + x, PrimeField::ZERO);\n                assert_eq!(x - x, PrimeField::ZERO);\n            }\n        }\n        test::<5>();\n        test::<7>();\n        test::<11>();\n        test::<13>();\n        test::<17>();\n        test::<19>();\n        test::<23>();\n        test::<71>();\n        test::<101>();\n    }\n\n    #[test]\n    fn test_mod_inverse() {\n        assert_eq!(mod_inverse(-6, 7), 1);\n        assert_eq!(mod_inverse(-5, 7), -3);\n        assert_eq!(mod_inverse(-4, 7), -2);\n        assert_eq!(mod_inverse(-3, 7), 2);\n        assert_eq!(mod_inverse(-2, 7), 3);\n        assert_eq!(mod_inverse(-1, 7), -1);\n        assert_eq!(mod_inverse(1, 7), 1);\n        assert_eq!(mod_inverse(2, 7), -3);\n        assert_eq!(mod_inverse(3, 7), -2);\n        assert_eq!(mod_inverse(4, 7), 2);\n        assert_eq!(mod_inverse(5, 7), 3);\n        assert_eq!(mod_inverse(6, 7), -1);\n    }\n\n    #[test]\n    fn integer_mul() {\n        type F = PrimeField<23>;\n        for x in 0..23 {\n            let x = F { a: x };\n            for n in -7..7 {\n                assert_eq!(x.integer_mul(n), F { a: n * x.a });\n            }\n        }\n    }\n\n    #[test]\n    fn from_integer() {\n        type F = PrimeField<23>;\n        for x in -100..100 {\n            assert_eq!(F::from_integer(x), F { a: x });\n        }\n        assert_eq!(F::from(0), F::ZERO);\n        assert_eq!(F::from(1), F::ONE);\n    }\n}\n"
  },
  {
    "path": "src/math/frizzy_number.rs",
    "content": "/// This Rust program calculates the n-th Frizzy number for a given base.\n/// A Frizzy number is defined as the n-th number that is a sum of powers\n/// of the given base, with the powers corresponding to the binary representation\n/// of n.\n\n/// The `get_nth_frizzy` function takes two arguments:\n/// * `base` - The base whose n-th sum of powers is required.\n/// * `n` - Index from ascending order of the sum of powers of the base.\n\n/// It returns the n-th sum of powers of the base.\n\n/// # Example\n/// To find the Frizzy number with a base of 3 and n equal to 4:\n/// - Ascending order of sums of powers of 3: 3^0 = 1, 3^1 = 3, 3^1 + 3^0 = 4, 3^2 + 3^0 = 9.\n/// - The answer is 9.\n///\n/// # Arguments\n/// * `base` - The base whose n-th sum of powers is required.\n/// * `n` - Index from ascending order of the sum of powers of the base.\n///\n/// # Returns\n/// The n-th sum of powers of the base.\n\npub fn get_nth_frizzy(base: i32, mut n: i32) -> f64 {\n    let mut final1 = 0.0;\n    let mut i = 0;\n    while n > 0 {\n        final1 += (base.pow(i) as f64) * ((n % 2) as f64);\n        i += 1;\n        n /= 2;\n    }\n    final1\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_get_nth_frizzy() {\n        // Test case 1: base = 3, n = 4\n        // 3^2 + 3^0 = 9\n        assert_eq!(get_nth_frizzy(3, 4), 9.0);\n\n        // Test case 2: base = 2, n = 5\n        // 2^2 + 2^0 = 5\n        assert_eq!(get_nth_frizzy(2, 5), 5.0);\n\n        // Test case 3: base = 4, n = 3\n        // 4^1 + 4^0 = 5\n        assert_eq!(get_nth_frizzy(4, 3), 5.0);\n\n        // Test case 4: base = 5, n = 2\n        // 5^1 + 5^0 = 5\n        assert_eq!(get_nth_frizzy(5, 2), 5.0);\n\n        // Test case 5: base = 6, n = 1\n        // 6^0 = 1\n        assert_eq!(get_nth_frizzy(6, 1), 1.0);\n    }\n}\n"
  },
  {
    "path": "src/math/gaussian_elimination.rs",
    "content": "// Gaussian Elimination of Quadratic Matrices\n// Takes an augmented matrix as input, returns vector of results\n// Wikipedia reference: augmented matrix: https://en.wikipedia.org/wiki/Augmented_matrix\n// Wikipedia reference: algorithm: https://en.wikipedia.org/wiki/Gaussian_elimination\n\npub fn gaussian_elimination(matrix: &mut [Vec<f32>]) -> Vec<f32> {\n    let size = matrix.len();\n    assert_eq!(size, matrix[0].len() - 1);\n\n    for i in 0..size - 1 {\n        for j in i..size - 1 {\n            echelon(matrix, i, j);\n        }\n    }\n\n    for i in (1..size).rev() {\n        eliminate(matrix, i);\n    }\n\n    // Disable cargo clippy warnings about needless range loops.\n    // Checking the diagonal like this is simpler than any alternative.\n    #[allow(clippy::needless_range_loop)]\n    for i in 0..size {\n        if matrix[i][i] == 0f32 {\n            println!(\"Infinitely many solutions\");\n        }\n    }\n\n    let mut result: Vec<f32> = vec![0f32; size];\n    for i in 0..size {\n        result[i] = matrix[i][size] / matrix[i][i];\n    }\n    result\n}\n\nfn echelon(matrix: &mut [Vec<f32>], i: usize, j: usize) {\n    let size = matrix.len();\n    if matrix[i][i] == 0f32 {\n    } else {\n        let factor = matrix[j + 1][i] / matrix[i][i];\n        (i..=size).for_each(|k| {\n            matrix[j + 1][k] -= factor * matrix[i][k];\n        });\n    }\n}\n\nfn eliminate(matrix: &mut [Vec<f32>], i: usize) {\n    let size = matrix.len();\n    if matrix[i][i] == 0f32 {\n    } else {\n        for j in (1..=i).rev() {\n            let factor = matrix[j - 1][i] / matrix[i][i];\n            for k in (0..=size).rev() {\n                matrix[j - 1][k] -= factor * matrix[i][k];\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::gaussian_elimination;\n\n    #[test]\n    fn test_gauss() {\n        let mut matrix: Vec<Vec<f32>> = vec![\n            vec![1.5, 2.0, 1.0, -1.0, -2.0, 1.0, 1.0],\n            vec![3.0, 3.0, -1.0, 16.0, 18.0, 1.0, 1.0],\n            vec![1.0, 1.0, 3.0, -2.0, -6.0, 1.0, 1.0],\n            vec![1.0, 1.0, 99.0, 19.0, 2.0, 1.0, 1.0],\n            vec![1.0, -2.0, 16.0, 1.0, 9.0, 10.0, 1.0],\n            vec![1.0, 3.0, 1.0, -5.0, 1.0, 1.0, 95.0],\n        ];\n        let result = vec![\n            -264.05893, 159.63196, -6.156921, 35.310387, -18.806696, 81.67839,\n        ];\n        assert_eq!(gaussian_elimination(&mut matrix), result);\n    }\n}\n"
  },
  {
    "path": "src/math/gaussian_error_linear_unit.rs",
    "content": "//! # Gaussian Error Linear Unit (GELU) Function\n//!\n//! The `gaussian_error_linear_unit` function computes the Gaussian Error Linear Unit (GELU) values of a given f64 number or a vector of f64 numbers.\n//!\n//! GELU is an activation function used in neural networks that introduces a smooth approximation of the rectifier function (ReLU).\n//! It is defined using the Gaussian cumulative distribution function and can help mitigate the vanishing gradient problem.\n//!\n//! ## Formula\n//!\n//! For a given input value `x`, the GELU function computes the output `y` as follows:\n//!\n//! `y = 0.5 * (1.0 + tanh(2.0 / sqrt(π) * (x + 0.044715 * x^3)))`\n//!\n//! Where `tanh` is the hyperbolic tangent function and `π` is the mathematical constant (approximately 3.14159).\n//!\n//! ## Gaussian Error Linear Unit (GELU) Function Implementation\n//!\n//! This implementation takes either a single f64 value or a reference to a vector of f64 values and returns the GELU transformation applied to each element. The input values are not altered.\n//!\nuse std::f64::consts::E;\nuse std::f64::consts::PI;\n\nfn tanh(vector: f64) -> f64 {\n    (2. / (1. + E.powf(-2. * vector.to_owned()))) - 1.\n}\n\npub fn gaussian_error_linear_unit(vector: &Vec<f64>) -> Vec<f64> {\n    let mut gelu_vec = vector.to_owned();\n    for value in &mut gelu_vec {\n        *value = *value\n            * 0.5\n            * (1. + tanh(f64::powf(2. / PI, 0.5) * (*value + 0.044715 * value.powf(3.))));\n    }\n\n    gelu_vec\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_gaussian_error_linear_unit() {\n        let test_vector = vec![-10., 2., -3., 4., -5., 10., 0.05];\n        assert_eq!(\n            gaussian_error_linear_unit(&test_vector),\n            vec![\n                -0.0,\n                1.9545976940877752,\n                -0.0036373920817729943,\n                3.9999297540518075,\n                -2.2917961972623857e-7,\n                10.0,\n                0.025996938238622008\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/gcd_of_n_numbers.rs",
    "content": "/// returns the greatest common divisor of n numbers\npub fn gcd(nums: &[usize]) -> usize {\n    if nums.len() == 1 {\n        return nums[0];\n    }\n    let a = nums[0];\n    let b = gcd(&nums[1..]);\n    gcd_of_two_numbers(a, b)\n}\n\nfn gcd_of_two_numbers(a: usize, b: usize) -> usize {\n    if b == 0 {\n        return a;\n    }\n    gcd_of_two_numbers(b, a % b)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn it_works() {\n        assert_eq!(gcd(&[1, 2, 3, 4, 5]), 1);\n        assert_eq!(gcd(&[2, 4, 6, 8, 10]), 2);\n        assert_eq!(gcd(&[3, 6, 9, 12, 15]), 3);\n        assert_eq!(gcd(&[10]), 10);\n        assert_eq!(gcd(&[21, 110]), 1);\n    }\n}\n"
  },
  {
    "path": "src/math/geometric_series.rs",
    "content": "// Author : cyrixninja\n// Wikipedia : https://en.wikipedia.org/wiki/Geometric_series\n// Calculate a geometric series.\n\npub fn geometric_series(nth_term: f64, start_term_a: f64, common_ratio_r: f64) -> Vec<f64> {\n    let mut series = Vec::new();\n    let mut multiple = 1.0;\n\n    for _ in 0..(nth_term as i32) {\n        series.push(start_term_a * multiple);\n        multiple *= common_ratio_r;\n    }\n\n    series\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn assert_approx_eq(a: f64, b: f64) {\n        let epsilon = 1e-10;\n        assert!((a - b).abs() < epsilon, \"Expected {a}, found {b}\");\n    }\n\n    #[test]\n    fn test_geometric_series() {\n        let result = geometric_series(4.0, 2.0, 2.0);\n        assert_eq!(result.len(), 4);\n        assert_approx_eq(result[0], 2.0);\n        assert_approx_eq(result[1], 4.0);\n        assert_approx_eq(result[2], 8.0);\n        assert_approx_eq(result[3], 16.0);\n\n        let result = geometric_series(4.1, 2.1, 2.1);\n        assert_eq!(result.len(), 4);\n        assert_approx_eq(result[0], 2.1);\n        assert_approx_eq(result[1], 4.41);\n        assert_approx_eq(result[2], 9.261);\n        assert_approx_eq(result[3], 19.4481);\n\n        let result = geometric_series(4.0, -2.0, 2.0);\n        assert_eq!(result.len(), 4);\n        assert_approx_eq(result[0], -2.0);\n        assert_approx_eq(result[1], -4.0);\n        assert_approx_eq(result[2], -8.0);\n        assert_approx_eq(result[3], -16.0);\n    }\n}\n"
  },
  {
    "path": "src/math/greatest_common_divisor.rs",
    "content": "/// Greatest Common Divisor.\n///\n/// greatest_common_divisor(num1, num2) returns the greatest number of num1 and num2.\n///\n/// Wikipedia reference: https://en.wikipedia.org/wiki/Greatest_common_divisor\n/// gcd(a, b) = gcd(a, -b) = gcd(-a, b) = gcd(-a, -b) by definition of divisibility\nuse std::cmp::{max, min};\n\npub fn greatest_common_divisor_recursive(a: i64, b: i64) -> i64 {\n    if a == 0 {\n        b.abs()\n    } else {\n        greatest_common_divisor_recursive(b % a, a)\n    }\n}\n\npub fn greatest_common_divisor_iterative(mut a: i64, mut b: i64) -> i64 {\n    while a != 0 {\n        let remainder = b % a;\n        b = a;\n        a = remainder;\n    }\n    b.abs()\n}\n\npub fn greatest_common_divisor_stein(a: u64, b: u64) -> u64 {\n    match ((a, b), (a & 1, b & 1)) {\n        // gcd(x, x) = x\n        ((x, y), _) if x == y => y,\n        // gcd(x, 0) = gcd(0, x) = x\n        ((0, x), _) | ((x, 0), _) => x,\n        // gcd(x, y) = gcd(x / 2, y) if x is even and y is odd\n        // gcd(x, y) = gcd(x, y / 2) if y is even and x is odd\n        ((x, y), (0, 1)) | ((y, x), (1, 0)) => greatest_common_divisor_stein(x >> 1, y),\n        // gcd(x, y) = 2 * gcd(x / 2, y / 2) if x and y are both even\n        ((x, y), (0, 0)) => greatest_common_divisor_stein(x >> 1, y >> 1) << 1,\n        // if x and y are both odd\n        ((x, y), (1, 1)) => {\n            // then gcd(x, y) = gcd((x - y) / 2, y)  if x >= y\n            //      gcd(x, y) = gcd((y - x) / 2, x)  otherwise\n            let (x, y) = (min(x, y), max(x, y));\n            greatest_common_divisor_stein((y - x) >> 1, x)\n        }\n        _ => unreachable!(),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn positive_number_recursive() {\n        assert_eq!(greatest_common_divisor_recursive(4, 16), 4);\n        assert_eq!(greatest_common_divisor_recursive(16, 4), 4);\n        assert_eq!(greatest_common_divisor_recursive(3, 5), 1);\n        assert_eq!(greatest_common_divisor_recursive(40, 40), 40);\n        assert_eq!(greatest_common_divisor_recursive(27, 12), 3);\n    }\n\n    #[test]\n    fn positive_number_iterative() {\n        assert_eq!(greatest_common_divisor_iterative(4, 16), 4);\n        assert_eq!(greatest_common_divisor_iterative(16, 4), 4);\n        assert_eq!(greatest_common_divisor_iterative(3, 5), 1);\n        assert_eq!(greatest_common_divisor_iterative(40, 40), 40);\n        assert_eq!(greatest_common_divisor_iterative(27, 12), 3);\n    }\n\n    #[test]\n    fn positive_number_stein() {\n        assert_eq!(greatest_common_divisor_stein(4, 16), 4);\n        assert_eq!(greatest_common_divisor_stein(16, 4), 4);\n        assert_eq!(greatest_common_divisor_stein(3, 5), 1);\n        assert_eq!(greatest_common_divisor_stein(40, 40), 40);\n        assert_eq!(greatest_common_divisor_stein(27, 12), 3);\n    }\n\n    #[test]\n    fn negative_number_recursive() {\n        assert_eq!(greatest_common_divisor_recursive(-32, -8), 8);\n        assert_eq!(greatest_common_divisor_recursive(-8, -32), 8);\n        assert_eq!(greatest_common_divisor_recursive(-3, -5), 1);\n        assert_eq!(greatest_common_divisor_recursive(-40, -40), 40);\n        assert_eq!(greatest_common_divisor_recursive(-12, -27), 3);\n    }\n\n    #[test]\n    fn negative_number_iterative() {\n        assert_eq!(greatest_common_divisor_iterative(-32, -8), 8);\n        assert_eq!(greatest_common_divisor_iterative(-8, -32), 8);\n        assert_eq!(greatest_common_divisor_iterative(-3, -5), 1);\n        assert_eq!(greatest_common_divisor_iterative(-40, -40), 40);\n        assert_eq!(greatest_common_divisor_iterative(-12, -27), 3);\n    }\n\n    #[test]\n    fn mix_recursive() {\n        assert_eq!(greatest_common_divisor_recursive(0, -5), 5);\n        assert_eq!(greatest_common_divisor_recursive(-5, 0), 5);\n        assert_eq!(greatest_common_divisor_recursive(-64, 32), 32);\n        assert_eq!(greatest_common_divisor_recursive(-32, 64), 32);\n        assert_eq!(greatest_common_divisor_recursive(-40, 40), 40);\n        assert_eq!(greatest_common_divisor_recursive(12, -27), 3);\n    }\n\n    #[test]\n    fn mix_iterative() {\n        assert_eq!(greatest_common_divisor_iterative(0, -5), 5);\n        assert_eq!(greatest_common_divisor_iterative(-5, 0), 5);\n        assert_eq!(greatest_common_divisor_iterative(-64, 32), 32);\n        assert_eq!(greatest_common_divisor_iterative(-32, 64), 32);\n        assert_eq!(greatest_common_divisor_iterative(-40, 40), 40);\n        assert_eq!(greatest_common_divisor_iterative(12, -27), 3);\n    }\n}\n"
  },
  {
    "path": "src/math/huber_loss.rs",
    "content": "//! # Huber Loss Function\n//!\n//! The `huber_loss` function calculates the Huber loss, which is a robust loss function used in machine learning, particularly in regression problems.\n//!\n//! Huber loss combines the benefits of mean squared error (MSE) and mean absolute error (MAE). It behaves like MSE when the difference between actual and predicted values is small (less than a specified `delta`), and like MAE when the difference is large.\n//!\n//! ## Formula\n//!\n//! For a pair of actual and predicted values, represented as vectors `actual` and `predicted`, and a specified `delta` value, the Huber loss is calculated as:\n//!\n//! - If the absolute difference between `actual[i]` and `predicted[i]` is less than or equal to `delta`, the loss is `0.5 * (actual[i] - predicted[i])^2`.\n//! - If the absolute difference is greater than `delta`, the loss is `delta * |actual[i] - predicted[i]| - 0.5 * delta`.\n//!\n//! The total loss is the sum of individual losses over all elements.\n//!\n//! ## Huber Loss Function Implementation\n//!\n//! This implementation takes two references to vectors of f64 values, `actual` and `predicted`, and a `delta` value. It returns the Huber loss between them, providing a robust measure of dissimilarity between actual and predicted values.\n//!\npub fn huber_loss(actual: &[f64], predicted: &[f64], delta: f64) -> f64 {\n    let mut loss: Vec<f64> = Vec::new();\n    for (a, p) in actual.iter().zip(predicted.iter()) {\n        if (a - p).abs() <= delta {\n            loss.push(0.5 * (a - p).powf(2.));\n        } else {\n            loss.push(delta * (a - p).abs() - (0.5 * delta));\n        }\n    }\n\n    loss.iter().sum()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_huber_loss() {\n        let test_vector_actual = vec![1.0, 2.0, 3.0, 4.0, 5.0];\n        let test_vector = vec![5.0, 7.0, 9.0, 11.0, 13.0];\n        assert_eq!(huber_loss(&test_vector_actual, &test_vector, 1.0), 27.5);\n    }\n}\n"
  },
  {
    "path": "src/math/infix_to_postfix.rs",
    "content": "#[derive(Debug, Clone, PartialEq, Eq)]\npub enum InfixToPostfixError {\n    UnknownCharacter(char),\n    UnmatchedParent,\n}\n\n/// Function to convert [infix expression](https://en.wikipedia.org/wiki/Infix_notation) to [postfix expression](https://en.wikipedia.org/wiki/Reverse_Polish_notation)\npub fn infix_to_postfix(infix: &str) -> Result<String, InfixToPostfixError> {\n    let mut postfix = String::new();\n    let mut stack: Vec<char> = Vec::new();\n\n    // Define the precedence of operators\n    let precedence = |op: char| -> u8 {\n        match op {\n            '+' | '-' => 1,\n            '*' | '/' => 2,\n            '^' => 3,\n            _ => 0,\n        }\n    };\n\n    for token in infix.chars() {\n        match token {\n            c if c.is_alphanumeric() => {\n                postfix.push(c);\n            }\n            '(' => {\n                stack.push('(');\n            }\n            ')' => {\n                while let Some(top) = stack.pop() {\n                    if top == '(' {\n                        break;\n                    }\n                    postfix.push(top);\n                }\n            }\n            '+' | '-' | '*' | '/' | '^' => {\n                while let Some(top) = stack.last() {\n                    if *top == '(' || precedence(*top) < precedence(token) {\n                        break;\n                    }\n                    postfix.push(stack.pop().unwrap());\n                }\n                stack.push(token);\n            }\n            other => return Err(InfixToPostfixError::UnknownCharacter(other)),\n        }\n    }\n\n    while let Some(top) = stack.pop() {\n        if top == '(' {\n            return Err(InfixToPostfixError::UnmatchedParent);\n        }\n\n        postfix.push(top);\n    }\n\n    Ok(postfix)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_infix_to_postfix {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (infix, expected) = $inputs;\n                    assert_eq!(infix_to_postfix(infix), expected)\n                }\n            )*\n        }\n    }\n\n    test_infix_to_postfix! {\n        single_symbol: (\"x\", Ok(String::from(\"x\"))),\n        simple_sum: (\"x+y\", Ok(String::from(\"xy+\"))),\n        multiply_sum_left: (\"x*(y+z)\", Ok(String::from(\"xyz+*\"))),\n        multiply_sum_right: (\"(x+y)*z\", Ok(String::from(\"xy+z*\"))),\n        multiply_two_sums: (\"(a+b)*(c+d)\", Ok(String::from(\"ab+cd+*\"))),\n        product_and_power: (\"a*b^c\", Ok(String::from(\"abc^*\"))),\n        power_and_product: (\"a^b*c\", Ok(String::from(\"ab^c*\"))),\n        product_of_powers: (\"(a*b)^c\", Ok(String::from(\"ab*c^\"))),\n        product_in_exponent: (\"a^(b*c)\", Ok(String::from(\"abc*^\"))),\n        regular_0: (\"a-b+c-d*e\", Ok(String::from(\"ab-c+de*-\"))),\n        regular_1: (\"a*(b+c)+d/(e+f)\", Ok(String::from(\"abc+*def+/+\"))),\n        regular_2: (\"(a-b+c)*(d+e*f)\", Ok(String::from(\"ab-c+def*+*\"))),\n        unknown_character: (\"(a-b)*#\", Err(InfixToPostfixError::UnknownCharacter('#'))),\n        unmatched_paren: (\"((a-b)\", Err(InfixToPostfixError::UnmatchedParent)),\n    }\n}\n"
  },
  {
    "path": "src/math/interest.rs",
    "content": "// value of e\nuse std::f64::consts::E;\n\n// function to calculate simple interest\npub fn simple_interest(principal: f64, annual_rate: f64, years: f64) -> (f64, f64) {\n    let interest = principal * annual_rate * years;\n    let value = principal * (1.0 + (annual_rate * years));\n\n    println!(\"Interest earned: {interest}\");\n    println!(\"Future value: {value}\");\n\n    (interest, value)\n}\n\n// function to calculate compound interest compounded over periods or continuously\npub fn compound_interest(principal: f64, annual_rate: f64, years: f64, period: Option<f64>) -> f64 {\n    // checks if the period is None type, if so calculates continuous compounding interest\n    let value = if period.is_none() {\n        principal * E.powf(annual_rate * years)\n    } else {\n        // unwraps the option type or defaults to 0 if None type and assigns it to prim_period\n        let prim_period: f64 = period.unwrap_or(0.0);\n        // checks if the period is less than or equal to zero\n        if prim_period <= 0.0_f64 {\n            return f64::NAN;\n        }\n        principal * (1.0 + (annual_rate / prim_period).powf(prim_period * years))\n    };\n    println!(\"Future value: {value}\");\n    value\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn test_simple() {\n        let x = 385.65_f64 * 0.03_f64 * 5.0_f64;\n        let y = 385.65_f64 * (1.0 + (0.03_f64 * 5.0_f64));\n        assert_eq!(simple_interest(385.65_f64, 0.03_f64, 5.0_f64), (x, y));\n    }\n    #[test]\n    fn test_compounding() {\n        let x = 385.65_f64 * E.powf(0.03_f64 * 5.0_f64);\n        assert_eq!(compound_interest(385.65_f64, 0.03_f64, 5.0_f64, None), x);\n\n        let y = 385.65_f64 * (1.0 + (0.03_f64 / 5.0_f64).powf(5.0_f64 * 5.0_f64));\n        assert_eq!(\n            compound_interest(385.65_f64, 0.03_f64, 5.0_f64, Some(5.0_f64)),\n            y\n        );\n        assert!(compound_interest(385.65_f64, 0.03_f64, 5.0_f64, Some(-5.0_f64)).is_nan());\n        assert!(compound_interest(385.65_f64, 0.03_f64, 5.0_f64, Some(0.0_f64)).is_nan());\n    }\n}\n"
  },
  {
    "path": "src/math/interpolation.rs",
    "content": "/// In mathematics, linear interpolation is a method of curve fitting\n/// using linear polynomials to construct new data points within the range of a discrete set of known data points.\n/// Formula: y = y0 + (x - x0) * (y1 - y0) / (x1 - x0)\n/// Source: https://en.wikipedia.org/wiki/Linear_interpolation\n/// point0 and point1 are a tuple containing x and y values we want to interpolate between\npub fn linear_interpolation(x: f64, point0: (f64, f64), point1: (f64, f64)) -> f64 {\n    point0.1 + (x - point0.0) * (point1.1 - point0.1) / (point1.0 - point0.0)\n}\n\n/// In numerical analysis, the Lagrange interpolating polynomial\n/// is the unique polynomial of lowest degree that interpolates a given set of data.\n///\n/// Source: https://en.wikipedia.org/wiki/Lagrange_polynomial\n/// Source: https://mathworld.wolfram.com/LagrangeInterpolatingPolynomial.html\n/// x is the point we wish to interpolate\n/// defined points are a vector of tuples containing known x and y values of our function\npub fn lagrange_polynomial_interpolation(x: f64, defined_points: &Vec<(f64, f64)>) -> f64 {\n    let mut defined_x_values: Vec<f64> = Vec::new();\n    let mut defined_y_values: Vec<f64> = Vec::new();\n\n    for (x, y) in defined_points {\n        defined_x_values.push(*x);\n        defined_y_values.push(*y);\n    }\n\n    let mut sum = 0.0;\n\n    for y_index in 0..defined_y_values.len() {\n        let mut numerator = 1.0;\n        let mut denominator = 1.0;\n        for x_index in 0..defined_x_values.len() {\n            if y_index == x_index {\n                continue;\n            }\n            denominator *= defined_x_values[y_index] - defined_x_values[x_index];\n            numerator *= x - defined_x_values[x_index];\n        }\n\n        sum += numerator / denominator * defined_y_values[y_index];\n    }\n    sum\n}\n\n#[cfg(test)]\nmod tests {\n\n    use std::assert_eq;\n\n    use super::*;\n    #[test]\n    fn test_linear_intepolation() {\n        let point1 = (0.0, 0.0);\n        let point2 = (1.0, 1.0);\n        let point3 = (2.0, 2.0);\n\n        let x1 = 0.5;\n        let x2 = 1.5;\n\n        let y1 = linear_interpolation(x1, point1, point2);\n        let y2 = linear_interpolation(x2, point2, point3);\n\n        assert_eq!(y1, x1);\n        assert_eq!(y2, x2);\n        assert_eq!(\n            linear_interpolation(x1, point1, point2),\n            linear_interpolation(x1, point2, point1)\n        );\n    }\n\n    #[test]\n    fn test_lagrange_polynomial_interpolation() {\n        // defined values for x^2 function\n        let defined_points = vec![(0.0, 0.0), (1.0, 1.0), (2.0, 4.0), (3.0, 9.0)];\n\n        // check for equality\n        assert_eq!(lagrange_polynomial_interpolation(1.0, &defined_points), 1.0);\n        assert_eq!(lagrange_polynomial_interpolation(2.0, &defined_points), 4.0);\n        assert_eq!(lagrange_polynomial_interpolation(3.0, &defined_points), 9.0);\n\n        //other\n        assert_eq!(\n            lagrange_polynomial_interpolation(0.5, &defined_points),\n            0.25\n        );\n        assert_eq!(\n            lagrange_polynomial_interpolation(2.5, &defined_points),\n            6.25\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/interquartile_range.rs",
    "content": "// Author : cyrixninja\n// Interquartile Range  : An implementation of interquartile range (IQR) which is a measure of statistical\n//                        dispersion, which is the spread of the data.\n// Wikipedia Reference  : https://en.wikipedia.org/wiki/Interquartile_range\n\nuse std::cmp::Ordering;\n\npub fn find_median(numbers: &[f64]) -> f64 {\n    let mut numbers = numbers.to_vec();\n    numbers.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));\n\n    let length = numbers.len();\n    let mid = length / 2;\n\n    if length.is_multiple_of(2) {\n        f64::midpoint(numbers[mid - 1], numbers[mid])\n    } else {\n        numbers[mid]\n    }\n}\n\npub fn interquartile_range(numbers: &[f64]) -> f64 {\n    if numbers.is_empty() {\n        panic!(\"Error: The list is empty. Please provide a non-empty list.\");\n    }\n\n    let mut numbers = numbers.to_vec();\n    numbers.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));\n\n    let length = numbers.len();\n    let mid = length / 2;\n    let (q1, q3) = if length.is_multiple_of(2) {\n        let first_half = &numbers[0..mid];\n        let second_half = &numbers[mid..length];\n        (find_median(first_half), find_median(second_half))\n    } else {\n        let first_half = &numbers[0..mid];\n        let second_half = &numbers[mid + 1..length];\n        (find_median(first_half), find_median(second_half))\n    };\n\n    q3 - q1\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_find_median() {\n        let numbers1 = vec![1.0, 2.0, 2.0, 3.0, 4.0];\n        assert_eq!(find_median(&numbers1), 2.0);\n\n        let numbers2 = vec![1.0, 2.0, 2.0, 3.0, 4.0, 4.0];\n        assert_eq!(find_median(&numbers2), 2.5);\n\n        let numbers3 = vec![-1.0, 2.0, 0.0, 3.0, 4.0, -4.0];\n        assert_eq!(find_median(&numbers3), 1.0);\n\n        let numbers4 = vec![1.1, 2.2, 2.0, 3.3, 4.4, 4.0];\n        assert_eq!(find_median(&numbers4), 2.75);\n    }\n\n    #[test]\n    fn test_interquartile_range() {\n        let numbers1 = vec![4.0, 1.0, 2.0, 3.0, 2.0];\n        assert_eq!(interquartile_range(&numbers1), 2.0);\n\n        let numbers2 = vec![-2.0, -7.0, -10.0, 9.0, 8.0, 4.0, -67.0, 45.0];\n        assert_eq!(interquartile_range(&numbers2), 17.0);\n\n        let numbers3 = vec![-2.1, -7.1, -10.1, 9.1, 8.1, 4.1, -67.1, 45.1];\n        assert_eq!(interquartile_range(&numbers3), 17.2);\n\n        let numbers4 = vec![0.0, 0.0, 0.0, 0.0, 0.0];\n        assert_eq!(interquartile_range(&numbers4), 0.0);\n    }\n\n    #[test]\n    #[should_panic(expected = \"Error: The list is empty. Please provide a non-empty list.\")]\n    fn test_interquartile_range_empty_list() {\n        let numbers: Vec<f64> = vec![];\n        interquartile_range(&numbers);\n    }\n}\n"
  },
  {
    "path": "src/math/karatsuba_multiplication.rs",
    "content": "/*\nFinds the product of two numbers using Karatsuba Algorithm\n */\nuse std::cmp::max;\nconst TEN: i128 = 10;\n\npub fn multiply(num1: i128, num2: i128) -> i128 {\n    _multiply(num1, num2)\n}\n\nfn _multiply(num1: i128, num2: i128) -> i128 {\n    if num1 < 10 || num2 < 10 {\n        return num1 * num2;\n    }\n    let mut num1_str = num1.to_string();\n    let mut num2_str = num2.to_string();\n\n    let n = max(num1_str.len(), num2_str.len());\n    num1_str = normalize(num1_str, n);\n    num2_str = normalize(num2_str, n);\n\n    let a = &num1_str[0..n / 2];\n    let b = &num1_str[n / 2..];\n    let c = &num2_str[0..n / 2];\n    let d = &num2_str[n / 2..];\n\n    let ac = _multiply(a.parse().unwrap(), c.parse().unwrap());\n    let bd = _multiply(b.parse().unwrap(), d.parse().unwrap());\n    let a_b: i128 = a.parse::<i128>().unwrap() + b.parse::<i128>().unwrap();\n    let c_d: i128 = c.parse::<i128>().unwrap() + d.parse::<i128>().unwrap();\n    let ad_bc = _multiply(a_b, c_d) - (ac + bd);\n\n    let m = n / 2 + n % 2;\n    (TEN.pow(2 * m as u32) * ac) + (TEN.pow(m as u32) * ad_bc) + (bd)\n}\n\nfn normalize(mut a: String, n: usize) -> String {\n    let padding = n.saturating_sub(a.len());\n    a.insert_str(0, &\"0\".repeat(padding));\n    a\n}\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_1() {\n        let n1: i128 = 314159265;\n        let n2: i128 = 314159265;\n        let ans = multiply(n1, n2);\n        assert_eq!(ans, n1 * n2);\n    }\n\n    #[test]\n    fn test_2() {\n        let n1: i128 = 3141592653589793232;\n        let n2: i128 = 2718281828459045233;\n        let ans = multiply(n1, n2);\n        assert_eq!(ans, n1 * n2);\n    }\n\n    #[test]\n    fn test_3() {\n        let n1: i128 = 123456789;\n        let n2: i128 = 101112131415;\n        let ans = multiply(n1, n2);\n        assert_eq!(ans, n1 * n2);\n    }\n}\n"
  },
  {
    "path": "src/math/lcm_of_n_numbers.rs",
    "content": "// returns the least common multiple of n numbers\n\npub fn lcm(nums: &[usize]) -> usize {\n    if nums.len() == 1 {\n        return nums[0];\n    }\n    let a = nums[0];\n    let b = lcm(&nums[1..]);\n    a * b / gcd_of_two_numbers(a, b)\n}\n\nfn gcd_of_two_numbers(a: usize, b: usize) -> usize {\n    if b == 0 {\n        return a;\n    }\n    gcd_of_two_numbers(b, a % b)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn it_works() {\n        assert_eq!(lcm(&[1, 2, 3, 4, 5]), 60);\n        assert_eq!(lcm(&[2, 4, 6, 8, 10]), 120);\n        assert_eq!(lcm(&[3, 6, 9, 12, 15]), 180);\n        assert_eq!(lcm(&[10]), 10);\n        assert_eq!(lcm(&[21, 110]), 2310);\n    }\n}\n"
  },
  {
    "path": "src/math/leaky_relu.rs",
    "content": "//! # Leaky ReLU Function\n//!\n//! The `leaky_relu` function computes the Leaky Rectified Linear Unit (ReLU) values of a given vector\n//! of f64 numbers with a specified alpha parameter.\n//!\n//! The Leaky ReLU activation function is commonly used in neural networks to introduce a small negative\n//! slope (controlled by the alpha parameter) for the negative input values, preventing neurons from dying\n//! during training.\n//!\n//! ## Formula\n//!\n//! For a given input vector `x` and an alpha parameter `alpha`, the Leaky ReLU function computes the output\n//! `y` as follows:\n//!\n//! `y_i = { x_i if x_i >= 0, alpha * x_i if x_i < 0 }`\n//!\n//! ## Leaky ReLU Function Implementation\n//!\n//! This implementation takes a reference to a vector of f64 values and an alpha parameter, and returns a new\n//! vector with the Leaky ReLU transformation applied to each element. The input vector is not altered.\n//!\npub fn leaky_relu(vector: &Vec<f64>, alpha: f64) -> Vec<f64> {\n    let mut _vector = vector.to_owned();\n\n    for value in &mut _vector {\n        if value < &mut 0. {\n            *value *= alpha;\n        }\n    }\n\n    _vector\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_leaky_relu() {\n        let test_vector = vec![-10., 2., -3., 4., -5., 10., 0.05];\n        let alpha = 0.01;\n        assert_eq!(\n            leaky_relu(&test_vector, alpha),\n            vec![-0.1, 2.0, -0.03, 4.0, -0.05, 10.0, 0.05]\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/least_square_approx.rs",
    "content": "/// Least Square Approximation <p>\n/// Function that returns a polynomial which very closely passes through the given points (in 2D)\n///\n/// The result is made of coeficients, in descending order (from x^degree to free term)\n///\n/// Parameters:\n///\n/// points -> coordinates of given points\n///\n/// degree -> degree of the polynomial\n///\npub fn least_square_approx<T: Into<f64> + Copy, U: Into<f64> + Copy>(\n    points: &[(T, U)],\n    degree: i32,\n) -> Option<Vec<f64>> {\n    use nalgebra::{DMatrix, DVector};\n\n    /* Used for rounding floating numbers */\n    fn round_to_decimals(value: f64, decimals: i32) -> f64 {\n        let multiplier = 10f64.powi(decimals);\n        (value * multiplier).round() / multiplier\n    }\n\n    /* Casting the data parsed to this function to f64 (as some points can have decimals) */\n    let vals: Vec<(f64, f64)> = points\n        .iter()\n        .map(|(x, y)| ((*x).into(), (*y).into()))\n        .collect();\n    /* Because of collect we need the Copy Trait for T and U */\n\n    /* Computes the sums in the system of equations */\n    let mut sums = Vec::<f64>::new();\n    for i in 1..=(2 * degree + 1) {\n        sums.push(vals.iter().map(|(x, _)| x.powi(i - 1)).sum());\n    }\n\n    /* Compute the free terms column vector */\n    let mut free_col = Vec::<f64>::new();\n    for i in 1..=(degree + 1) {\n        free_col.push(vals.iter().map(|(x, y)| y * (x.powi(i - 1))).sum());\n    }\n    let b = DVector::from_row_slice(&free_col);\n\n    /* Create and fill the system's matrix */\n    let size = (degree + 1) as usize;\n    let a = DMatrix::from_fn(size, size, |i, j| sums[degree as usize + i - j]);\n\n    /* Solve the system of equations: A * x = b */\n    match a.qr().solve(&b) {\n        Some(x) => {\n            let rez: Vec<f64> = x.iter().map(|x| round_to_decimals(*x, 5)).collect();\n            Some(rez)\n        }\n        None => None, //<-- The system cannot be solved (badly conditioned system's matrix)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn ten_points_1st_degree() {\n        let points = vec![\n            (5.3, 7.8),\n            (4.9, 8.1),\n            (6.1, 6.9),\n            (4.7, 8.3),\n            (6.5, 7.7),\n            (5.6, 7.0),\n            (5.8, 8.2),\n            (4.5, 8.0),\n            (6.3, 7.2),\n            (5.1, 8.4),\n        ];\n\n        assert_eq!(\n            least_square_approx(&points, 1),\n            Some(vec![-0.49069, 10.44898])\n        );\n    }\n\n    #[test]\n    fn eight_points_5th_degree() {\n        let points = vec![\n            (4f64, 8f64),\n            (8f64, 2f64),\n            (1f64, 7f64),\n            (10f64, 3f64),\n            (11.0, 0.0),\n            (7.0, 3.0),\n            (10.0, 1.0),\n            (13.0, 13.0),\n        ];\n\n        assert_eq!(\n            least_square_approx(&points, 5),\n            Some(vec![\n                0.00603, -0.21304, 2.79929, -16.53468, 40.29473, -19.35771\n            ])\n        );\n    }\n\n    #[test]\n    fn four_points_2nd_degree() {\n        let points = vec![\n            (2.312, 8.345344),\n            (-2.312, 8.345344),\n            (-0.7051, 3.49716601),\n            (0.7051, 3.49716601),\n        ];\n\n        assert_eq!(least_square_approx(&points, 2), Some(vec![1.0, 0.0, 3.0]));\n    }\n}\n"
  },
  {
    "path": "src/math/linear_sieve.rs",
    "content": "/*\nLinear Sieve algorithm:\nTime complexity is indeed O(n) with O(n) memory, but the sieve generally\nruns slower than a well implemented sieve of Eratosthenes. Some use cases are:\n- factorizing any number k in the sieve in O(log(k))\n- calculating arbitrary multiplicative functions on sieve numbers\n  without increasing the time complexity\n- As a by product, all prime numbers less than `max_number` are stored\n  in `primes` vector.\n */\npub struct LinearSieve {\n    max_number: usize,\n    pub primes: Vec<usize>,\n    pub minimum_prime_factor: Vec<usize>,\n}\n\nimpl LinearSieve {\n    pub const fn new() -> Self {\n        LinearSieve {\n            max_number: 0,\n            primes: vec![],\n            minimum_prime_factor: vec![],\n        }\n    }\n\n    pub fn prepare(&mut self, max_number: usize) -> Result<(), &'static str> {\n        if max_number <= 1 {\n            return Err(\"Sieve size should be more than 1\");\n        }\n        if self.max_number > 0 {\n            return Err(\"Sieve already initialized\");\n        }\n        self.max_number = max_number;\n        self.minimum_prime_factor.resize(max_number + 1, 0);\n        for i in 2..=max_number {\n            if self.minimum_prime_factor[i] == 0 {\n                self.minimum_prime_factor[i] = i;\n                self.primes.push(i);\n                /*\n                   if needed, a multiplicative function can be\n                   calculated for this prime number here:\n                   function[i] = base_case(i);\n                */\n            }\n            for p in self.primes.iter() {\n                let mlt = (*p) * i;\n                if *p > i || mlt > max_number {\n                    break;\n                }\n                self.minimum_prime_factor[mlt] = *p;\n                /*\n                   multiplicative function for mlt can be calculated here:\n                   if i % p:\n                       function[mlt] = add_to_prime_exponent(function[i], i, p);\n                   else:\n                       function[mlt] = function[i] * function[p]\n                */\n            }\n        }\n        Ok(())\n    }\n\n    pub fn factorize(&self, mut number: usize) -> Result<Vec<usize>, &'static str> {\n        if number > self.max_number {\n            return Err(\"Number is too big, its minimum_prime_factor was not calculated\");\n        }\n        if number == 0 {\n            return Err(\"Number is zero\");\n        }\n        let mut result: Vec<usize> = Vec::new();\n        while number > 1 {\n            result.push(self.minimum_prime_factor[number]);\n            number /= self.minimum_prime_factor[number];\n        }\n        Ok(result)\n    }\n}\n\nimpl Default for LinearSieve {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::LinearSieve;\n\n    #[test]\n    fn small_primes_list() {\n        let mut ls = LinearSieve::new();\n        ls.prepare(25).unwrap();\n        assert_eq!(ls.primes, vec![2, 3, 5, 7, 11, 13, 17, 19, 23]);\n    }\n\n    #[test]\n    fn divisible_by_mpf() {\n        let mut ls = LinearSieve::new();\n        ls.prepare(1000).unwrap();\n        for i in 2..=1000 {\n            let div = i / ls.minimum_prime_factor[i];\n            assert_eq!(i % ls.minimum_prime_factor[i], 0);\n            if div == 1 {\n                // Number must be prime\n                assert!(ls.primes.binary_search(&i).is_ok());\n            }\n        }\n    }\n\n    #[test]\n    fn check_factorization() {\n        let mut ls = LinearSieve::new();\n        ls.prepare(1000).unwrap();\n        for i in 1..=1000 {\n            let factorization = ls.factorize(i).unwrap();\n            let mut product = 1usize;\n            for (idx, p) in factorization.iter().enumerate() {\n                assert!(ls.primes.binary_search(p).is_ok());\n                product *= *p;\n                if idx > 0 {\n                    assert!(*p >= factorization[idx - 1]);\n                }\n            }\n            assert_eq!(product, i);\n        }\n    }\n\n    #[test]\n    fn check_number_of_primes() {\n        let mut ls = LinearSieve::new();\n        ls.prepare(100_000).unwrap();\n        assert_eq!(ls.primes.len(), 9592);\n    }\n}\n"
  },
  {
    "path": "src/math/logarithm.rs",
    "content": "use std::f64::consts::E;\n\n/// Calculates the **log<sub>base</sub>(x)**\n///\n/// Parameters:\n///   <p>-> base: base of log\n///   <p>-> x: value for which log shall be evaluated\n///   <p>-> tol: tolerance; the precision of the approximation (submultiples of 10<sup>-1</sup>)\n///\n/// Advisable to use **std::f64::consts::*** for specific bases (like 'e')\npub fn log<T: Into<f64>, U: Into<f64>>(base: U, x: T, tol: f64) -> f64 {\n    let mut rez = 0f64;\n    let mut argument: f64 = x.into();\n    let usable_base: f64 = base.into();\n\n    if argument <= 0f64 || usable_base <= 0f64 {\n        println!(\"Log does not support negative argument or negative base.\");\n        f64::NAN\n    } else if argument < 1f64 && usable_base == E {\n        argument -= 1f64;\n        let mut prev_rez = 1f64;\n        let mut step: i32 = 1;\n        /*\n            For x in (0, 1) and base 'e', the function is using MacLaurin Series:\n            ln(|1 + x|) = Σ \"(-1)^n-1 * x^n / n\", for n = 1..inf\n            Substituting x with x-1 yields:\n            ln(|x|) = Σ \"(-1)^n-1 * (x-1)^n / n\"\n        */\n        while (prev_rez - rez).abs() > tol {\n            prev_rez = rez;\n            rez += (-1f64).powi(step - 1) * argument.powi(step) / step as f64;\n            step += 1;\n        }\n\n        rez\n    } else {\n        /* Using the basic change of base formula for log */\n        let ln_x = argument.ln();\n        let ln_base = usable_base.ln();\n\n        ln_x / ln_base\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn basic() {\n        assert_eq!(log(E, E, 0.0), 1.0);\n        assert_eq!(log(E, E.powi(100), 0.0), 100.0);\n        assert_eq!(log(10, 10000.0, 0.0), 4.0);\n        assert_eq!(log(234501.0, 1.0, 1.0), 0.0);\n    }\n\n    #[test]\n    fn test_log_positive_base() {\n        assert_eq!(log(10.0, 100.0, 0.00001), 2.0);\n        assert_eq!(log(2.0, 8.0, 0.00001), 3.0);\n    }\n\n    #[test]\n    fn test_log_zero_base() {\n        assert!(log(0.0, 100.0, 0.00001).is_nan());\n    }\n\n    #[test]\n    fn test_log_negative_base() {\n        assert!(log(-1.0, 100.0, 0.00001).is_nan());\n    }\n\n    #[test]\n    fn test_log_tolerance() {\n        assert_eq!(log(10.0, 100.0, 1e-10), 2.0);\n    }\n}\n"
  },
  {
    "path": "src/math/lucas_series.rs",
    "content": "// Author : cyrixninja\n// Lucas Series : Function to get the Nth Lucas Number\n// Wikipedia Reference  :  https://en.wikipedia.org/wiki/Lucas_number\n// Other References     :  https://the-algorithms.com/algorithm/lucas-series?lang=python\n\npub fn recursive_lucas_number(n: u32) -> u32 {\n    match n {\n        0 => 2,\n        1 => 1,\n        _ => recursive_lucas_number(n - 1) + recursive_lucas_number(n - 2),\n    }\n}\n\npub fn dynamic_lucas_number(n: u32) -> u32 {\n    let mut a = 2;\n    let mut b = 1;\n\n    for _ in 0..n {\n        let temp = a;\n        a = b;\n        b += temp;\n    }\n\n    a\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_lucas_number {\n        ($($name:ident: $inputs:expr,)*) => {\n        $(\n            #[test]\n            fn $name() {\n                let (n, expected) = $inputs;\n                assert_eq!(recursive_lucas_number(n), expected);\n                assert_eq!(dynamic_lucas_number(n), expected);\n            }\n        )*\n        }\n    }\n\n    test_lucas_number! {\n        input_0: (0, 2),\n        input_1: (1, 1),\n        input_2: (2, 3),\n        input_3: (3, 4),\n        input_4: (4, 7),\n        input_5: (5, 11),\n        input_6: (6, 18),\n        input_7: (7, 29),\n        input_8: (8, 47),\n        input_9: (9, 76),\n        input_10: (10, 123),\n        input_15: (15, 1364),\n        input_20: (20, 15127),\n        input_25: (25, 167761),\n    }\n}\n"
  },
  {
    "path": "src/math/matrix_ops.rs",
    "content": "// Basic matrix operations using a Matrix type with internally uses\n// a vector representation to store matrix elements.\n// Generic using the MatrixElement trait, which can be implemented with\n// the matrix_element_type_def macro.\n// Wikipedia reference: https://www.wikiwand.com/en/Matrix_(mathematics)\nuse std::ops::{Add, AddAssign, Index, IndexMut, Mul, Sub};\n\n// Define macro to build a matrix idiomatically\n#[macro_export]\nmacro_rules! matrix {\n    [$([$($x:expr),* $(,)*]),* $(,)*] => {{\n        Matrix::from(vec![$(vec![$($x,)*],)*])\n    }};\n}\n\n// Define a trait \"alias\" for suitable matrix elements\npub trait MatrixElement:\n    Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self> + AddAssign + Copy + From<u8>\n{\n}\n\n// Define a macro to implement the MatrixElement trait for desired types\n#[macro_export]\nmacro_rules! matrix_element_type_def {\n    ($T: ty) => {\n        // Implement trait for type\n        impl MatrixElement for $T {}\n\n        // Defining left-hand multiplication in this form\n        // prevents errors for uncovered types\n        impl Mul<&Matrix<$T>> for $T {\n            type Output = Matrix<$T>;\n\n            fn mul(self, rhs: &Matrix<$T>) -> Self::Output {\n                rhs * self\n            }\n        }\n    };\n\n    ($T: ty, $($Ti: ty),+) => {\n        // Decompose type definitions recursively\n        matrix_element_type_def!($T);\n        matrix_element_type_def!($($Ti),+);\n    };\n}\n\nmatrix_element_type_def!(i16, i32, i64, i128, u8, u16, u32, u128, f32, f64);\n\n#[derive(PartialEq, Eq, Debug)]\npub struct Matrix<T: MatrixElement> {\n    data: Vec<T>,\n    rows: usize,\n    cols: usize,\n}\n\nimpl<T: MatrixElement> Matrix<T> {\n    pub fn new(data: Vec<T>, rows: usize, cols: usize) -> Self {\n        // Build a matrix from the internal vector representation\n        if data.len() != rows * cols {\n            panic!(\"Inconsistent data and dimensions combination for matrix\")\n        }\n        Matrix { data, rows, cols }\n    }\n\n    pub fn zero(rows: usize, cols: usize) -> Self {\n        // Build a matrix of zeros\n        Matrix {\n            data: vec![0.into(); rows * cols],\n            rows,\n            cols,\n        }\n    }\n\n    pub fn identity(len: usize) -> Self {\n        // Build an identity matrix\n        let mut identity = Matrix::zero(len, len);\n        // Diagonal of ones\n        for i in 0..len {\n            identity[[i, i]] = 1.into();\n        }\n        identity\n    }\n\n    pub fn transpose(&self) -> Self {\n        // Transpose a matrix of any size\n        let mut result = Matrix::zero(self.cols, self.rows);\n        for i in 0..self.rows {\n            for j in 0..self.cols {\n                result[[i, j]] = self[[j, i]];\n            }\n        }\n        result\n    }\n}\n\nimpl<T: MatrixElement> Index<[usize; 2]> for Matrix<T> {\n    type Output = T;\n\n    fn index(&self, index: [usize; 2]) -> &Self::Output {\n        let [i, j] = index;\n        if i >= self.rows || j >= self.cols {\n            panic!(\"Matrix index out of bounds\");\n        }\n\n        &self.data[(self.cols * i) + j]\n    }\n}\n\nimpl<T: MatrixElement> IndexMut<[usize; 2]> for Matrix<T> {\n    fn index_mut(&mut self, index: [usize; 2]) -> &mut Self::Output {\n        let [i, j] = index;\n        if i >= self.rows || j >= self.cols {\n            panic!(\"Matrix index out of bounds\");\n        }\n\n        &mut self.data[(self.cols * i) + j]\n    }\n}\n\nimpl<T: MatrixElement> Add<&Matrix<T>> for &Matrix<T> {\n    type Output = Matrix<T>;\n\n    fn add(self, rhs: &Matrix<T>) -> Self::Output {\n        // Add two matrices. They need to have identical dimensions.\n        if self.rows != rhs.rows || self.cols != rhs.cols {\n            panic!(\"Matrix dimensions do not match\");\n        }\n\n        let mut result = Matrix::zero(self.rows, self.cols);\n        for i in 0..self.rows {\n            for j in 0..self.cols {\n                result[[i, j]] = self[[i, j]] + rhs[[i, j]];\n            }\n        }\n        result\n    }\n}\n\nimpl<T: MatrixElement> Sub for &Matrix<T> {\n    type Output = Matrix<T>;\n\n    fn sub(self, rhs: Self) -> Self::Output {\n        // Subtract one matrix from another. They need to have identical dimensions.\n        if self.rows != rhs.rows || self.cols != rhs.cols {\n            panic!(\"Matrix dimensions do not match\");\n        }\n\n        let mut result = Matrix::zero(self.rows, self.cols);\n        for i in 0..self.rows {\n            for j in 0..self.cols {\n                result[[i, j]] = self[[i, j]] - rhs[[i, j]];\n            }\n        }\n        result\n    }\n}\n\nimpl<T: MatrixElement> Mul for &Matrix<T> {\n    type Output = Matrix<T>;\n\n    fn mul(self, rhs: Self) -> Self::Output {\n        // Multiply two matrices. The multiplier needs to have the same amount\n        // of columns as the multiplicand has rows.\n        if self.cols != rhs.rows {\n            panic!(\"Matrix dimensions do not match\");\n        }\n\n        let mut result = Matrix::zero(self.rows, rhs.cols);\n        for i in 0..self.rows {\n            for j in 0..rhs.cols {\n                result[[i, j]] = {\n                    let mut sum = 0.into();\n                    for k in 0..self.cols {\n                        sum += self[[i, k]] * rhs[[k, j]];\n                    }\n                    sum\n                };\n            }\n        }\n        result\n    }\n}\n\nimpl<T: MatrixElement> Mul<T> for &Matrix<T> {\n    type Output = Matrix<T>;\n\n    fn mul(self, rhs: T) -> Self::Output {\n        // Multiply a matrix of any size with a scalar\n        let mut result = Matrix::zero(self.rows, self.cols);\n        for i in 0..self.rows {\n            for j in 0..self.cols {\n                result[[i, j]] = rhs * self[[i, j]];\n            }\n        }\n        result\n    }\n}\n\nimpl<T: MatrixElement> From<Vec<Vec<T>>> for Matrix<T> {\n    fn from(v: Vec<Vec<T>>) -> Self {\n        let rows = v.len();\n        let cols = v.first().map_or(0, |row| row.len());\n\n        // Ensure consistent dimensions\n        for row in v.iter().skip(1) {\n            if row.len() != cols {\n                panic!(\"Invalid matrix dimensions. Columns must be consistent.\");\n            }\n        }\n        if rows != 0 && cols == 0 {\n            panic!(\"Invalid matrix dimensions. Multiple empty rows\");\n        }\n\n        let data = v.into_iter().flat_map(|row| row.into_iter()).collect();\n        Self::new(data, rows, cols)\n    }\n}\n\n#[cfg(test)]\n// rustfmt skipped to prevent unformatting matrix definitions to a single line\n#[rustfmt::skip] \nmod tests {\n    use super::Matrix;\n    use std::panic;\n\n    const DELTA: f64 = 1e-3;\n\n    macro_rules! assert_f64_eq {\n        ($a:expr, $b:expr) => {\n            assert_eq!($a.data.len(), $b.data.len());\n            if !$a\n                .data\n                .iter()\n                .zip($b.data.iter())\n                .all(|(x, y)| (*x as f64 - *y as f64).abs() < DELTA)\n            {\n                panic!();\n            }\n        };\n    }\n\n    #[test]\n    fn test_invalid_matrix() {\n        let result = panic::catch_unwind(|| matrix![\n            [1, 0, 0, 4],\n            [0, 1, 0],\n            [0, 0, 1],\n        ]);\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn test_empty_matrix() {\n        let a: Matrix<i32> = matrix![];\n\n        let result = panic::catch_unwind(|| a[[0, 0]]);\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn test_zero_matrix() {\n        let a: Matrix<f64> = Matrix::zero(3, 5);\n\n        let z = matrix![\n            [0.0, 0.0, 0.0, 0.0, 0.0],\n            [0.0, 0.0, 0.0, 0.0, 0.0],\n            [0.0, 0.0, 0.0, 0.0, 0.0],\n        ];\n\n        assert_f64_eq!(a, z);\n    }\n\n    #[test]\n    fn test_identity_matrix() {\n        let a: Matrix<f64> = Matrix::identity(5);\n\n        let id = matrix![\n            [1.0, 0.0, 0.0, 0.0, 0.0],\n            [0.0, 1.0, 0.0, 0.0, 0.0],\n            [0.0, 0.0, 1.0, 0.0, 0.0],\n            [0.0, 0.0, 0.0, 1.0, 0.0],\n            [0.0, 0.0, 0.0, 0.0, 1.0],\n        ];\n\n        assert_f64_eq!(a, id);\n    }\n\n    #[test]\n    fn test_invalid_add() {\n        let a = matrix![\n            [1, 0, 1],\n            [0, 2, 0],\n            [5, 0, 1]\n        ];\n\n        let err = matrix![\n            [1, 2],\n            [2, 4],\n        ];\n\n        let result = panic::catch_unwind(|| &a + &err);\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn test_add_i32() {\n        let a = matrix![\n            [1, 0, 1],\n            [0, 2, 0],\n            [5, 0, 1]\n        ];\n\n        let b = matrix![\n            [1, 0, 0],\n            [0, 1, 0],\n            [0, 0, 1],\n        ];\n\n        let add = matrix![\n            [2, 0, 1],\n            [0, 3, 0],\n            [5, 0, 2],\n        ];\n\n        assert_eq!(&a + &b, add);\n    }\n\n    #[test]\n    fn test_add_f64() {\n        let a = matrix![\n            [1.0, 2.0, 1.0],\n            [3.0, 2.0, 0.0],\n            [5.0, 0.0, 1.0],\n        ];\n\n        let b = matrix![\n            [1.0, 10.0, 0.0],\n            [0.0, 1.0, 0.0],\n            [0.0, 0.0, 1.0],\n        ];\n\n        let add = matrix![\n            [2.0, 12.0, 1.0],\n            [3.0, 3.0, 0.0],\n            [5.0, 0.0, 2.0],\n        ];\n\n        assert_f64_eq!(&a + &b, add);\n    }\n\n    #[test]\n    fn test_invalid_sub() {\n        let a = matrix![\n            [2, 3],\n            [10, 2],\n        ];\n\n        let err = matrix![\n            [5, 6, 10],\n            [7, 2, 2],\n            [12, 0, 1],\n        ];\n\n        let result = panic::catch_unwind(|| &a - &err);\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn test_subtract_i32() {\n        let a = matrix![\n            [1, 0, 1],\n            [0, 2, 0],\n            [5, 0, 1],\n        ];\n\n        let b = matrix![\n            [1, 0, 0],\n            [0, 1, 3],\n            [0, 0, 1],\n        ];\n\n        let sub = matrix![\n            [0, 0, 1],\n            [0, 1, -3],\n            [5, 0, 0],\n        ];\n\n        assert_eq!(&a - &b, sub);\n    }\n\n    #[test]\n    fn test_subtract_f64() {\n        let a = matrix![\n            [7.0, 2.0, 1.0],\n            [0.0, 3.0, 2.0],\n            [5.3, 8.8, std::f64::consts::PI],\n        ];\n\n        let b = matrix![\n            [1.0, 0.0, 5.0],\n            [-2.0, 1.0, 3.0],\n            [0.0, 2.2, std::f64::consts::PI],\n        ];\n\n        let sub = matrix![\n            [6.0, 2.0, -4.0],\n            [2.0, 2.0, -1.0],\n            [5.3, 6.6, 0.0],\n        ];\n\n        assert_f64_eq!(&a - &b, sub);\n    }\n\n    #[test]\n    fn test_invalid_mul() {\n        let a = matrix![\n            [1, 2, 3],\n            [4, 2, 6],\n            [3, 4, 1],\n            [2, 4, 8],\n        ];\n\n        let err = matrix![\n            [1, 3, 3, 2],\n            [7, 6, 2, 1],\n            [3, 4, 2, 1],\n            [3, 4, 2, 1],\n        ];\n\n        let result = panic::catch_unwind(|| &a * &err);\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn test_mul_i32() {\n        let a = matrix![\n            [1, 2, 3],\n            [4, 2, 6],\n            [3, 4, 1],\n            [2, 4, 8],\n        ];\n\n        let b = matrix![\n            [1, 3, 3, 2],\n            [7, 6, 2, 1],\n            [3, 4, 2, 1],\n        ];\n\n        let mul = matrix![\n            [24, 27, 13, 7],\n            [36, 48, 28, 16],\n            [34, 37, 19, 11],\n            [54, 62, 30, 16],\n        ];\n\n        assert_eq!(&a * &b, mul);\n    }\n\n    #[test]\n    fn test_mul_f64() {\n        let a = matrix![\n            [5.5, 2.9, 1.13, 9.0],\n            [0.0, 3.0, 11.0, 17.2],\n            [5.3, 8.8, 2.76, 3.3],\n        ];\n\n        let b = matrix![\n            [1.0, 0.3, 5.0],\n            [-2.0, 1.0, 3.0],\n            [-3.6, 1.5, 3.0],\n            [0.0, 2.2, 2.0],\n        ];\n\n        let mul = matrix![\n            [-4.368, 26.045, 57.59],\n            [-45.6, 57.34, 76.4],\n            [-22.236, 21.79, 67.78],\n        ];\n\n        assert_f64_eq!(&a * &b, mul);\n    }\n\n    #[test]\n    fn test_transpose_i32() {\n        let a = matrix![\n            [1, 0, 1],\n            [0, 2, 0],\n            [5, 0, 1],\n        ];\n\n        let t = matrix![\n            [1, 0, 5],\n            [0, 2, 0],\n            [1, 0, 1],\n        ];\n\n        assert_eq!(a.transpose(), t);\n    }\n\n    #[test]\n    fn test_transpose_f64() {\n        let a = matrix![\n            [3.0, 4.0, 2.0],\n            [0.0, 1.0, 3.0],\n            [3.0, 1.0, 1.0],\n        ];\n\n        let t = matrix![\n            [3.0, 0.0, 3.0],\n            [4.0, 1.0, 1.0],\n            [2.0, 3.0, 1.0],\n        ];\n\n        assert_eq!(a.transpose(), t);\n    }\n\n    #[test]\n    fn test_matrix_scalar_zero_mul() {\n        let a = matrix![\n            [3, 2, 2],\n            [0, 2, 0],\n            [5, 4, 1],\n        ];\n\n        let scalar = 0;\n\n        let scalar_mul = Matrix::zero(3, 3);\n\n        assert_eq!(scalar * &a, scalar_mul);\n    }\n\n    #[test]\n    fn test_matrix_scalar_mul_i32() {\n        let a = matrix![\n            [3, 2, 2],\n            [0, 2, 0],\n            [5, 4, 1],\n        ];\n\n        let scalar = 3;\n\n        let scalar_mul = matrix![\n            [9, 6, 6],\n            [0, 6, 0],\n            [15, 12, 3],\n        ];\n\n        assert_eq!(scalar * &a, scalar_mul);\n    }\n\n    #[test]\n    fn test_matrix_scalar_mul_f64() {\n        let a = matrix![\n            [3.2, 5.5, 9.2],\n            [1.1, 0.0, 2.3],\n            [0.3, 4.2, 0.0],\n        ];\n\n        let scalar = 1.5_f64;\n\n        let scalar_mul = matrix![\n            [4.8, 8.25, 13.8],\n            [1.65, 0.0, 3.45],\n            [0.45, 6.3, 0.0],\n        ];\n\n        assert_f64_eq!(scalar * &a, scalar_mul);\n    }\n}\n"
  },
  {
    "path": "src/math/mersenne_primes.rs",
    "content": "// mersenne prime : https://en.wikipedia.org/wiki/Mersenne_prime\npub fn is_mersenne_prime(n: usize) -> bool {\n    if n == 2 {\n        return true;\n    }\n    let mut s = 4;\n    let m = 2_usize.pow(std::convert::TryInto::try_into(n).unwrap()) - 1;\n    for _ in 0..n - 2 {\n        s = ((s * s) - 2) % m;\n    }\n    s == 0\n}\n\npub fn get_mersenne_primes(limit: usize) -> Vec<usize> {\n    let mut results: Vec<usize> = Vec::new();\n    for num in 1..=limit {\n        if is_mersenne_prime(num) {\n            results.push(num);\n        }\n    }\n    results\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{get_mersenne_primes, is_mersenne_prime};\n\n    #[test]\n    fn validity_check() {\n        assert!(is_mersenne_prime(3));\n        assert!(is_mersenne_prime(13));\n        assert!(!is_mersenne_prime(32));\n    }\n\n    #[allow(dead_code)]\n    fn generation_check() {\n        assert_eq!(get_mersenne_primes(30), [2, 3, 5, 7, 13, 17, 19]);\n    }\n}\n"
  },
  {
    "path": "src/math/miller_rabin.rs",
    "content": "use num_bigint::BigUint;\nuse num_traits::{One, ToPrimitive, Zero};\nuse std::cmp::Ordering;\n\nfn modulo_power(mut base: u64, mut power: u64, modulo: u64) -> u64 {\n    base %= modulo;\n    if base == 0 {\n        return 0; // return zero if base is divisible by modulo\n    }\n    let mut ans: u128 = 1;\n    let mut bbase: u128 = base as u128;\n    while power > 0 {\n        if (power % 2) == 1 {\n            ans = (ans * bbase) % (modulo as u128);\n        }\n        bbase = (bbase * bbase) % (modulo as u128);\n        power /= 2;\n    }\n    ans as u64\n}\n\nfn check_prime_base(number: u64, base: u64, two_power: u64, odd_power: u64) -> bool {\n    // returns false if base is a witness\n    let mut x: u128 = modulo_power(base, odd_power, number) as u128;\n    let bnumber: u128 = number as u128;\n    if x == 1 || x == (bnumber - 1) {\n        return true;\n    }\n    for _ in 1..two_power {\n        x = (x * x) % bnumber;\n        if x == (bnumber - 1) {\n            return true;\n        }\n    }\n    false\n}\n\npub fn miller_rabin(number: u64, bases: &[u64]) -> u64 {\n    // returns zero on a probable prime, and a witness if number is not prime\n    // A base set for deterministic performance on 64 bit numbers is:\n    // [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n    // another one for 32 bits:\n    // [2, 3, 5, 7], with smallest number to fail 3'215'031'751 = 151 * 751 * 28351\n    // note that all bases should be prime\n    if number <= 4 {\n        match number {\n            0 => {\n                panic!(\"0 is invalid input for Miller-Rabin. 0 is not prime by definition, but has no witness\");\n            }\n            2 | 3 => return 0,\n            _ => return number,\n        }\n    }\n    if bases.contains(&number) {\n        return 0;\n    }\n    let two_power: u64 = (number - 1).trailing_zeros() as u64;\n    let odd_power = (number - 1) >> two_power;\n    for base in bases {\n        if !check_prime_base(number, *base, two_power, odd_power) {\n            return *base;\n        }\n    }\n    0\n}\n\npub fn big_miller_rabin(number_ref: &BigUint, bases: &[u64]) -> u64 {\n    let number = number_ref.clone();\n\n    if BigUint::from(5u32).cmp(&number) == Ordering::Greater {\n        if number.eq(&BigUint::zero()) {\n            panic!(\"0 is invalid input for Miller-Rabin. 0 is not prime by definition, but has no witness\");\n        } else if number.eq(&BigUint::from(2u32)) || number.eq(&BigUint::from(3u32)) {\n            return 0;\n        } else {\n            return number.to_u64().unwrap();\n        }\n    }\n\n    if let Some(num) = number.to_u64() {\n        if bases.contains(&num) {\n            return 0;\n        }\n    }\n\n    let num_minus_one = &number - BigUint::one();\n\n    let two_power: u64 = num_minus_one.trailing_zeros().unwrap();\n    let odd_power: BigUint = &num_minus_one >> two_power;\n    for base in bases {\n        let mut x = BigUint::from(*base).modpow(&odd_power, &number);\n\n        if x.eq(&BigUint::one()) || x.eq(&num_minus_one) {\n            continue;\n        }\n\n        let mut not_a_witness = false;\n\n        for _ in 1..two_power {\n            x = (&x * &x) % &number;\n            if x.eq(&num_minus_one) {\n                not_a_witness = true;\n                break;\n            }\n        }\n\n        if not_a_witness {\n            continue;\n        }\n\n        return *base;\n    }\n\n    0\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    static DEFAULT_BASES: [u64; 12] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37];\n\n    #[test]\n    fn basic() {\n        // these bases make miller rabin deterministic for any number < 2 ^ 64\n        // can use smaller number of bases for deterministic performance for numbers < 2 ^ 32\n\n        assert_eq!(miller_rabin(3, &DEFAULT_BASES), 0);\n        assert_eq!(miller_rabin(7, &DEFAULT_BASES), 0);\n        assert_eq!(miller_rabin(11, &DEFAULT_BASES), 0);\n        assert_eq!(miller_rabin(2003, &DEFAULT_BASES), 0);\n\n        assert_ne!(miller_rabin(1, &DEFAULT_BASES), 0);\n        assert_ne!(miller_rabin(4, &DEFAULT_BASES), 0);\n        assert_ne!(miller_rabin(6, &DEFAULT_BASES), 0);\n        assert_ne!(miller_rabin(21, &DEFAULT_BASES), 0);\n        assert_ne!(miller_rabin(2004, &DEFAULT_BASES), 0);\n\n        // bigger test cases.\n        // primes are generated using openssl\n        // non primes are randomly picked and checked using openssl\n\n        // primes:\n        assert_eq!(miller_rabin(3629611793, &DEFAULT_BASES), 0);\n        assert_eq!(miller_rabin(871594686869, &DEFAULT_BASES), 0);\n        assert_eq!(miller_rabin(968236663804121, &DEFAULT_BASES), 0);\n        assert_eq!(miller_rabin(6920153791723773023, &DEFAULT_BASES), 0);\n\n        // random non primes:\n        assert_ne!(miller_rabin(4546167556336341257, &DEFAULT_BASES), 0);\n        assert_ne!(miller_rabin(4363186415423517377, &DEFAULT_BASES), 0);\n        assert_ne!(miller_rabin(815479701131020226, &DEFAULT_BASES), 0);\n        // these two are made of two 31 bit prime factors:\n        // 1950202127 * 2058609037 = 4014703722618821699\n        assert_ne!(miller_rabin(4014703722618821699, &DEFAULT_BASES), 0);\n        // 1679076769 * 2076341633 = 3486337000477823777\n        assert_ne!(miller_rabin(3486337000477823777, &DEFAULT_BASES), 0);\n    }\n\n    #[test]\n    fn big_basic() {\n        assert_eq!(big_miller_rabin(&BigUint::from(3u32), &DEFAULT_BASES), 0);\n        assert_eq!(big_miller_rabin(&BigUint::from(7u32), &DEFAULT_BASES), 0);\n        assert_eq!(big_miller_rabin(&BigUint::from(11u32), &DEFAULT_BASES), 0);\n        assert_eq!(big_miller_rabin(&BigUint::from(2003u32), &DEFAULT_BASES), 0);\n\n        assert_ne!(big_miller_rabin(&BigUint::from(1u32), &DEFAULT_BASES), 0);\n        assert_ne!(big_miller_rabin(&BigUint::from(4u32), &DEFAULT_BASES), 0);\n        assert_ne!(big_miller_rabin(&BigUint::from(6u32), &DEFAULT_BASES), 0);\n        assert_ne!(big_miller_rabin(&BigUint::from(21u32), &DEFAULT_BASES), 0);\n        assert_ne!(big_miller_rabin(&BigUint::from(2004u32), &DEFAULT_BASES), 0);\n\n        assert_eq!(\n            big_miller_rabin(&BigUint::from(3629611793u64), &DEFAULT_BASES),\n            0\n        );\n        assert_eq!(\n            big_miller_rabin(&BigUint::from(871594686869u64), &DEFAULT_BASES),\n            0\n        );\n        assert_eq!(\n            big_miller_rabin(&BigUint::from(968236663804121u64), &DEFAULT_BASES),\n            0\n        );\n        assert_eq!(\n            big_miller_rabin(&BigUint::from(6920153791723773023u64), &DEFAULT_BASES),\n            0\n        );\n\n        assert_ne!(\n            big_miller_rabin(&BigUint::from(4546167556336341257u64), &DEFAULT_BASES),\n            0\n        );\n        assert_ne!(\n            big_miller_rabin(&BigUint::from(4363186415423517377u64), &DEFAULT_BASES),\n            0\n        );\n        assert_ne!(\n            big_miller_rabin(&BigUint::from(815479701131020226u64), &DEFAULT_BASES),\n            0\n        );\n        assert_ne!(\n            big_miller_rabin(&BigUint::from(4014703722618821699u64), &DEFAULT_BASES),\n            0\n        );\n        assert_ne!(\n            big_miller_rabin(&BigUint::from(3486337000477823777u64), &DEFAULT_BASES),\n            0\n        );\n    }\n\n    #[test]\n    #[ignore]\n    fn big_primes() {\n        let p1 =\n            BigUint::parse_bytes(b\"4764862697132131451620315518348229845593592794669\", 10).unwrap();\n        assert_eq!(big_miller_rabin(&p1, &DEFAULT_BASES), 0);\n\n        let p2 = BigUint::parse_bytes(\n            b\"12550757946601963214089118080443488976766669415957018428703\",\n            10,\n        )\n        .unwrap();\n        assert_eq!(big_miller_rabin(&p2, &DEFAULT_BASES), 0);\n\n        // An RSA-worthy prime\n        let p3 = BigUint::parse_bytes(b\"157d6l5zkv45ve4azfw7nyyjt6rzir2gcjoytjev5iacnkaii8hlkyk3op7bx9qfqiie23vj9iw4qbp7zupydfq9ut6mq6m36etya6cshtqi1yi9q5xyiws92el79dqt8qk7l2pqmxaa0sxhmd2vpaibo9dkfd029j1rvkwlw4724ctgaqs5jzy0bqi5pqdjc2xerhn\", 36).unwrap();\n        assert_eq!(big_miller_rabin(&p3, &DEFAULT_BASES), 0);\n\n        let n1 = BigUint::parse_bytes(b\"coy6tkiaqswmce1r03ycdif3t796wzjwneewbe3cmncaplm85jxzcpdmvy0moic3lql70a81t5qdn2apac0dndhohewkspuk1wyndxsgxs3ux4a7730unru7dfmygh\", 36).unwrap();\n        assert_ne!(big_miller_rabin(&n1, &DEFAULT_BASES), 0);\n\n        // RSA-2048\n        let n2 = BigUint::parse_bytes(b\"4l91lq4a2sgekpv8ukx1gxsk7mfeks46haggorlkazm0oufxwijid6q6v44u5me3kz3ne6yczp4fcvo62oej72oe7pjjtyxgid5b8xdz1e8daafspbzcy1hd8i4urjh9hm0tyylsgqsss3jn372d6fmykpw4bb9cr1ngxnncsbod3kg49o7owzqnsci5pwqt8bch0t60gq0st2gyx7ii3mzhb1pp1yvjyor35hwvok1sxj3ih46rpd27li8y5yli3mgdttcn65k3szfa6rbcnbgkojqjjq72gar6raslnh6sjd2fy7yj3bwo43obvbg3ws8y28kpol3okb5b3fld03sq1kgrj2fugiaxgplva6x5ssilqq4g0b21xy2kiou3sqsgonmqx55v\", 36).unwrap();\n        assert_ne!(big_miller_rabin(&n2, &DEFAULT_BASES), 0);\n    }\n}\n"
  },
  {
    "path": "src/math/mod.rs",
    "content": "mod abs;\nmod aliquot_sum;\nmod amicable_numbers;\nmod area_of_polygon;\nmod area_under_curve;\nmod armstrong_number;\nmod average;\nmod baby_step_giant_step;\nmod bell_numbers;\nmod binary_exponentiation;\nmod binomial_coefficient;\nmod catalan_numbers;\nmod ceil;\nmod chinese_remainder_theorem;\nmod collatz_sequence;\nmod combinations;\nmod cross_entropy_loss;\nmod decimal_to_fraction;\nmod doomsday;\nmod elliptic_curve;\nmod euclidean_distance;\nmod exponential_linear_unit;\nmod extended_euclidean_algorithm;\npub mod factorial;\nmod factors;\nmod fast_fourier_transform;\nmod fast_power;\nmod faster_perfect_numbers;\nmod field;\nmod frizzy_number;\nmod gaussian_elimination;\nmod gaussian_error_linear_unit;\nmod gcd_of_n_numbers;\nmod geometric_series;\nmod greatest_common_divisor;\nmod huber_loss;\nmod infix_to_postfix;\nmod interest;\nmod interpolation;\nmod interquartile_range;\nmod karatsuba_multiplication;\nmod lcm_of_n_numbers;\nmod leaky_relu;\nmod least_square_approx;\nmod linear_sieve;\nmod logarithm;\nmod lucas_series;\nmod matrix_ops;\nmod mersenne_primes;\nmod miller_rabin;\nmod modular_exponential;\nmod newton_raphson;\nmod nthprime;\nmod pascal_triangle;\nmod perfect_cube;\nmod perfect_numbers;\nmod perfect_square;\nmod pollard_rho;\nmod postfix_evaluation;\nmod prime_check;\nmod prime_factors;\nmod prime_numbers;\nmod quadratic_residue;\nmod random;\nmod relu;\nmod sieve_of_eratosthenes;\nmod sigmoid;\nmod signum;\nmod simpsons_integration;\nmod softmax;\nmod sprague_grundy_theorem;\nmod square_pyramidal_numbers;\nmod square_root;\nmod sum_of_digits;\nmod sum_of_geometric_progression;\nmod sum_of_harmonic_series;\nmod sylvester_sequence;\nmod tanh;\nmod trapezoidal_integration;\nmod trial_division;\nmod trig_functions;\nmod vector_cross_product;\nmod zellers_congruence_algorithm;\n\npub use self::abs::abs;\npub use self::aliquot_sum::aliquot_sum;\npub use self::amicable_numbers::amicable_pairs_under_n;\npub use self::area_of_polygon::area_of_polygon;\npub use self::area_under_curve::area_under_curve;\npub use self::armstrong_number::is_armstrong_number;\npub use self::average::{mean, median, mode};\npub use self::baby_step_giant_step::baby_step_giant_step;\npub use self::bell_numbers::bell_number;\npub use self::binary_exponentiation::binary_exponentiation;\npub use self::binomial_coefficient::binom;\npub use self::catalan_numbers::init_catalan;\npub use self::ceil::ceil;\npub use self::chinese_remainder_theorem::chinese_remainder_theorem;\npub use self::collatz_sequence::sequence;\npub use self::combinations::combinations;\npub use self::cross_entropy_loss::cross_entropy_loss;\npub use self::decimal_to_fraction::decimal_to_fraction;\npub use self::doomsday::get_week_day;\npub use self::elliptic_curve::EllipticCurve;\npub use self::euclidean_distance::euclidean_distance;\npub use self::exponential_linear_unit::exponential_linear_unit;\npub use self::extended_euclidean_algorithm::extended_euclidean_algorithm;\npub use self::factorial::{factorial, factorial_bigmath, factorial_recursive};\npub use self::factors::factors;\npub use self::fast_fourier_transform::{\n    fast_fourier_transform, fast_fourier_transform_input_permutation,\n    inverse_fast_fourier_transform,\n};\npub use self::fast_power::fast_power;\npub use self::faster_perfect_numbers::generate_perfect_numbers;\npub use self::field::{Field, PrimeField};\npub use self::frizzy_number::get_nth_frizzy;\npub use self::gaussian_elimination::gaussian_elimination;\npub use self::gaussian_error_linear_unit::gaussian_error_linear_unit;\npub use self::gcd_of_n_numbers::gcd;\npub use self::geometric_series::geometric_series;\npub use self::greatest_common_divisor::{\n    greatest_common_divisor_iterative, greatest_common_divisor_recursive,\n    greatest_common_divisor_stein,\n};\npub use self::huber_loss::huber_loss;\npub use self::infix_to_postfix::infix_to_postfix;\npub use self::interest::{compound_interest, simple_interest};\npub use self::interpolation::{lagrange_polynomial_interpolation, linear_interpolation};\npub use self::interquartile_range::interquartile_range;\npub use self::karatsuba_multiplication::multiply;\npub use self::lcm_of_n_numbers::lcm;\npub use self::leaky_relu::leaky_relu;\npub use self::least_square_approx::least_square_approx;\npub use self::linear_sieve::LinearSieve;\npub use self::logarithm::log;\npub use self::lucas_series::dynamic_lucas_number;\npub use self::lucas_series::recursive_lucas_number;\npub use self::matrix_ops::Matrix;\npub use self::mersenne_primes::{get_mersenne_primes, is_mersenne_prime};\npub use self::miller_rabin::{big_miller_rabin, miller_rabin};\npub use self::modular_exponential::{mod_inverse, modular_exponential};\npub use self::newton_raphson::find_root;\npub use self::nthprime::nthprime;\npub use self::pascal_triangle::pascal_triangle;\npub use self::perfect_cube::perfect_cube_binary_search;\npub use self::perfect_numbers::perfect_numbers;\npub use self::perfect_square::perfect_square;\npub use self::perfect_square::perfect_square_binary_search;\npub use self::pollard_rho::{pollard_rho_factorize, pollard_rho_get_one_factor};\npub use self::postfix_evaluation::evaluate_postfix;\npub use self::prime_check::prime_check;\npub use self::prime_factors::prime_factors;\npub use self::prime_numbers::prime_numbers;\npub use self::quadratic_residue::{cipolla, tonelli_shanks};\npub use self::random::PCG32;\npub use self::relu::relu;\npub use self::sieve_of_eratosthenes::sieve_of_eratosthenes;\npub use self::sigmoid::sigmoid;\npub use self::signum::signum;\npub use self::simpsons_integration::simpsons_integration;\npub use self::softmax::softmax;\npub use self::sprague_grundy_theorem::calculate_grundy_number;\npub use self::square_pyramidal_numbers::square_pyramidal_number;\npub use self::square_root::{fast_inv_sqrt, square_root};\npub use self::sum_of_digits::{sum_digits_iterative, sum_digits_recursive};\npub use self::sum_of_geometric_progression::sum_of_geometric_progression;\npub use self::sum_of_harmonic_series::sum_of_harmonic_progression;\npub use self::sylvester_sequence::sylvester;\npub use self::tanh::tanh;\npub use self::trapezoidal_integration::trapezoidal_integral;\npub use self::trial_division::trial_division;\npub use self::trig_functions::cosine;\npub use self::trig_functions::cosine_no_radian_arg;\npub use self::trig_functions::cotan;\npub use self::trig_functions::cotan_no_radian_arg;\npub use self::trig_functions::sine;\npub use self::trig_functions::sine_no_radian_arg;\npub use self::trig_functions::tan;\npub use self::trig_functions::tan_no_radian_arg;\npub use self::vector_cross_product::cross_product;\npub use self::vector_cross_product::vector_magnitude;\npub use self::zellers_congruence_algorithm::zellers_congruence_algorithm;\n"
  },
  {
    "path": "src/math/modular_exponential.rs",
    "content": "/// Calculate the greatest common divisor (GCD) of two numbers and the\n/// coefficients of Bézout's identity using the Extended Euclidean Algorithm.\n///\n/// # Arguments\n///\n/// * `a` - One of the numbers to find the GCD of\n/// * `m` - The other number to find the GCD of\n///\n/// # Returns\n///\n/// A tuple (gcd, x1, x2) such that:\n/// gcd - the greatest common divisor of a and m.\n/// x1, x2 - the coefficients such that `a * x1 + m * x2` is equivalent to `gcd` modulo `m`.\npub fn gcd_extended(a: i64, m: i64) -> (i64, i64, i64) {\n    if a == 0 {\n        (m, 0, 1)\n    } else {\n        let (gcd, x1, x2) = gcd_extended(m % a, a);\n        let x = x2 - (m / a) * x1;\n        (gcd, x, x1)\n    }\n}\n\n/// Find the modular multiplicative inverse of a number modulo `m`.\n///\n/// # Arguments\n///\n/// * `b` - The number to find the modular inverse of\n/// * `m` - The modulus\n///\n/// # Returns\n///\n/// The modular inverse of `b` modulo `m`.\n///\n/// # Panics\n///\n/// Panics if the inverse does not exist (i.e., `b` and `m` are not coprime).\npub fn mod_inverse(b: i64, m: i64) -> i64 {\n    let (gcd, x, _) = gcd_extended(b, m);\n    if gcd == 1 {\n        // Ensure the modular inverse is positive\n        (x % m + m) % m\n    } else {\n        panic!(\"Inverse does not exist\");\n    }\n}\n\n/// Perform modular exponentiation of a number raised to a power modulo `m`.\n/// This function handles both positive and negative exponents.\n///\n/// # Arguments\n///\n/// * `base` - The base number to be raised to the `power`\n/// * `power` - The exponent to raise the `base` to\n/// * `modulus` - The modulus to perform the operation under\n///\n/// # Returns\n///\n/// The result of `base` raised to `power` modulo `modulus`.\npub fn modular_exponential(base: i64, mut power: i64, modulus: i64) -> i64 {\n    if modulus == 1 {\n        return 0; // Base case: any number modulo 1 is 0\n    }\n\n    // Adjust if the exponent is negative by finding the modular inverse\n    let mut base = if power < 0 {\n        mod_inverse(base, modulus)\n    } else {\n        base % modulus\n    };\n\n    let mut result = 1; // Initialize result\n    power = power.abs(); // Work with the absolute value of the exponent\n\n    // Perform the exponentiation\n    while power > 0 {\n        if power & 1 == 1 {\n            result = (result * base) % modulus;\n        }\n        power >>= 1; // Divide the power by 2\n        base = (base * base) % modulus; // Square the base\n    }\n    result\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_modular_exponential_positive() {\n        assert_eq!(modular_exponential(2, 3, 5), 3); // 2^3 % 5 = 8 % 5 = 3\n        assert_eq!(modular_exponential(7, 2, 13), 10); // 7^2 % 13 = 49 % 13 = 10\n        assert_eq!(modular_exponential(5, 5, 31), 25); // 5^5 % 31 = 3125 % 31 = 25\n        assert_eq!(modular_exponential(10, 8, 11), 1); // 10^8 % 11 = 100000000 % 11 = 1\n        assert_eq!(modular_exponential(123, 45, 67), 62); // 123^45 % 67\n    }\n\n    #[test]\n    fn test_modular_inverse() {\n        assert_eq!(mod_inverse(7, 13), 2); // Inverse of 7 mod 13 is 2\n        assert_eq!(mod_inverse(5, 31), 25); // Inverse of 5 mod 31 is 25\n        assert_eq!(mod_inverse(10, 11), 10); // Inverse of 10 mod 1 is 10\n        assert_eq!(mod_inverse(123, 67), 6); // Inverse of 123 mod 67 is 6\n        assert_eq!(mod_inverse(9, 17), 2); // Inverse of 9 mod 17 is 2\n    }\n\n    #[test]\n    fn test_modular_exponential_negative() {\n        assert_eq!(\n            modular_exponential(7, -2, 13),\n            mod_inverse(7, 13).pow(2) % 13\n        ); // Inverse of 7 mod 13 is 2, 2^2 % 13 = 4 % 13 = 4\n        assert_eq!(\n            modular_exponential(5, -5, 31),\n            mod_inverse(5, 31).pow(5) % 31\n        ); // Inverse of 5 mod 31 is 25, 25^5 % 31 = 25\n        assert_eq!(\n            modular_exponential(10, -8, 11),\n            mod_inverse(10, 11).pow(8) % 11\n        ); // Inverse of 10 mod 11 is 10, 10^8 % 11 = 10\n        assert_eq!(\n            modular_exponential(123, -5, 67),\n            mod_inverse(123, 67).pow(5) % 67\n        ); // Inverse of 123 mod 67 is calculated via the function\n    }\n\n    #[test]\n    fn test_modular_exponential_edge_cases() {\n        assert_eq!(modular_exponential(0, 0, 1), 0); // 0^0 % 1 should be 0 as the modulus is 1\n        assert_eq!(modular_exponential(0, 10, 1), 0); // 0^n % 1 should be 0 for any n\n        assert_eq!(modular_exponential(10, 0, 1), 0); // n^0 % 1 should be 0 for any n\n        assert_eq!(modular_exponential(1, 1, 1), 0); // 1^1 % 1 should be 0\n        assert_eq!(modular_exponential(-1, 2, 1), 0); // (-1)^2 % 1 should be 0\n    }\n}\n"
  },
  {
    "path": "src/math/newton_raphson.rs",
    "content": "pub fn find_root(f: fn(f64) -> f64, fd: fn(f64) -> f64, guess: f64, iterations: i32) -> f64 {\n    let mut result = guess;\n    for _ in 0..iterations {\n        result = iteration(f, fd, result);\n    }\n    result\n}\n\npub fn iteration(f: fn(f64) -> f64, fd: fn(f64) -> f64, guess: f64) -> f64 {\n    guess - f(guess) / fd(guess)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn math_fn(x: f64) -> f64 {\n        x.cos() - (x * x * x)\n    }\n    fn math_fnd(x: f64) -> f64 {\n        -x.sin() - 3.0 * (x * x)\n    }\n    #[test]\n    fn basic() {\n        assert_eq!(find_root(math_fn, math_fnd, 0.5, 6), 0.8654740331016144);\n    }\n}\n"
  },
  {
    "path": "src/math/nthprime.rs",
    "content": "// Generate the nth prime number.\n// Algorithm is inspired by the optimized version of the Sieve of Eratosthenes.\npub fn nthprime(nth: u64) -> u64 {\n    let mut total_prime: u64 = 0;\n    let mut size_factor: u64 = 2;\n\n    let mut s: u64 = nth * size_factor;\n    let mut primes: Vec<u64> = Vec::new();\n\n    let n: u64 = nth;\n\n    while total_prime < n {\n        primes = get_primes(s).to_vec();\n\n        total_prime = primes[2..].iter().sum();\n        size_factor += 1;\n        s = n * size_factor;\n    }\n\n    count_prime(primes, n).unwrap()\n}\n\nfn get_primes(s: u64) -> Vec<u64> {\n    let mut v: Vec<u64> = vec![1; s as usize];\n\n    for index in 2..s {\n        if v[index as usize] == 1 {\n            for j in index..s {\n                if index * j < s {\n                    v[(index * j) as usize] = 0;\n                } else {\n                    break;\n                }\n            }\n        }\n    }\n    v\n}\n\nfn count_prime(primes: Vec<u64>, n: u64) -> Option<u64> {\n    let mut counter: u64 = 0;\n    for (i, prime) in primes.iter().enumerate().skip(2) {\n        counter += prime;\n        if counter == n {\n            return Some(i as u64);\n        }\n    }\n    None\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn my_test() {\n        assert_eq!(nthprime(100), 541u64);\n    }\n}\n"
  },
  {
    "path": "src/math/pascal_triangle.rs",
    "content": "/// ## Pascal's triangle problem\n///\n/// pascal_triangle(num_rows) returns the first num_rows of Pascal's triangle.\\\n/// About Pascal's triangle: <https://en.wikipedia.org/wiki/Pascal%27s_triangle>\n///\n/// # Arguments:\n///   * `num_rows`: number of rows of triangle\n///\n/// # Complexity\n///   - time complexity: O(n^2),\n///   - space complexity: O(n^2),\npub fn pascal_triangle(num_rows: i32) -> Vec<Vec<i32>> {\n    let mut ans: Vec<Vec<i32>> = vec![];\n\n    for i in 1..=num_rows {\n        let mut vec: Vec<i32> = vec![1];\n\n        let mut res: i32 = 1;\n        for k in 1..i {\n            res *= i - k;\n            res /= k;\n            vec.push(res);\n        }\n        ans.push(vec);\n    }\n\n    ans\n}\n\n#[cfg(test)]\nmod tests {\n    use super::pascal_triangle;\n\n    #[test]\n    fn test() {\n        assert_eq!(pascal_triangle(3), vec![vec![1], vec![1, 1], vec![1, 2, 1]]);\n        assert_eq!(\n            pascal_triangle(4),\n            vec![vec![1], vec![1, 1], vec![1, 2, 1], vec![1, 3, 3, 1]]\n        );\n        assert_eq!(\n            pascal_triangle(5),\n            vec![\n                vec![1],\n                vec![1, 1],\n                vec![1, 2, 1],\n                vec![1, 3, 3, 1],\n                vec![1, 4, 6, 4, 1]\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/perfect_cube.rs",
    "content": "// Check if a number is a perfect cube using binary search.\npub fn perfect_cube_binary_search(n: i64) -> bool {\n    if n < 0 {\n        return perfect_cube_binary_search(-n);\n    }\n\n    // Initialize left and right boundaries for binary search.\n    let mut left = 0;\n    let mut right = n.abs(); // Use the absolute value to handle negative numbers\n\n    // Binary search loop to find the cube root.\n    while left <= right {\n        // Calculate the mid-point.\n        let mid = left + (right - left) / 2;\n        // Calculate the cube of the mid-point.\n        let cube = mid * mid * mid;\n\n        // Check if the cube equals the original number.\n        match cube.cmp(&n) {\n            std::cmp::Ordering::Equal => return true,\n            std::cmp::Ordering::Less => left = mid + 1,\n            std::cmp::Ordering::Greater => right = mid - 1,\n        }\n    }\n\n    // If no cube root is found, return false.\n    false\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_perfect_cube {\n        ($($name:ident: $inputs:expr,)*) => {\n        $(\n            #[test]\n            fn $name() {\n                let (n, expected) = $inputs;\n                assert_eq!(perfect_cube_binary_search(n), expected);\n                assert_eq!(perfect_cube_binary_search(-n), expected);\n            }\n        )*\n        }\n    }\n\n    test_perfect_cube! {\n        num_0_a_perfect_cube: (0, true),\n        num_1_is_a_perfect_cube: (1, true),\n        num_27_is_a_perfect_cube: (27, true),\n        num_64_is_a_perfect_cube: (64, true),\n        num_8_is_a_perfect_cube: (8, true),\n        num_2_is_not_a_perfect_cube: (2, false),\n        num_3_is_not_a_perfect_cube: (3, false),\n        num_4_is_not_a_perfect_cube: (4, false),\n        num_5_is_not_a_perfect_cube: (5, false),\n        num_999_is_not_a_perfect_cube: (999, false),\n        num_1000_is_a_perfect_cube: (1000, true),\n        num_1001_is_not_a_perfect_cube: (1001, false),\n    }\n}\n"
  },
  {
    "path": "src/math/perfect_numbers.rs",
    "content": "pub fn is_perfect_number(num: usize) -> bool {\n    let mut sum = 0;\n\n    for i in 1..num - 1 {\n        if num.is_multiple_of(i) {\n            sum += i;\n        }\n    }\n\n    num == sum\n}\n\npub fn perfect_numbers(max: usize) -> Vec<usize> {\n    let mut result: Vec<usize> = Vec::new();\n\n    // It is not known if there are any odd perfect numbers, so we go around all the numbers.\n    for i in 1..=max {\n        if is_perfect_number(i) {\n            result.push(i);\n        }\n    }\n\n    result\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn basic() {\n        assert!(is_perfect_number(6));\n        assert!(is_perfect_number(28));\n        assert!(is_perfect_number(496));\n        assert!(is_perfect_number(8128));\n\n        assert!(!is_perfect_number(5));\n        assert!(!is_perfect_number(86));\n        assert!(!is_perfect_number(497));\n        assert!(!is_perfect_number(8120));\n\n        assert_eq!(perfect_numbers(10), vec![6]);\n        assert_eq!(perfect_numbers(100), vec![6, 28]);\n        assert_eq!(perfect_numbers(496), vec![6, 28, 496]);\n        assert_eq!(perfect_numbers(1000), vec![6, 28, 496]);\n    }\n}\n"
  },
  {
    "path": "src/math/perfect_square.rs",
    "content": "// Author : cyrixninja\n// Perfect Square : Checks if a number is perfect square number or not\n// https://en.wikipedia.org/wiki/Perfect_square\npub fn perfect_square(num: i32) -> bool {\n    if num < 0 {\n        return false;\n    }\n    let sqrt_num = (num as f64).sqrt() as i32;\n    sqrt_num * sqrt_num == num\n}\n\npub fn perfect_square_binary_search(n: i32) -> bool {\n    if n < 0 {\n        return false;\n    }\n\n    let mut left = 0;\n    let mut right = n;\n\n    while left <= right {\n        let mid = i32::midpoint(left, right);\n        let mid_squared = mid * mid;\n\n        match mid_squared.cmp(&n) {\n            std::cmp::Ordering::Equal => return true,\n            std::cmp::Ordering::Greater => right = mid - 1,\n            std::cmp::Ordering::Less => left = mid + 1,\n        }\n    }\n\n    false\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_perfect_square() {\n        assert!(perfect_square(9));\n        assert!(perfect_square(81));\n        assert!(perfect_square(4));\n        assert!(perfect_square(0));\n        assert!(!perfect_square(3));\n        assert!(!perfect_square(-19));\n    }\n\n    #[test]\n    fn test_perfect_square_binary_search() {\n        assert!(perfect_square_binary_search(9));\n        assert!(perfect_square_binary_search(81));\n        assert!(perfect_square_binary_search(4));\n        assert!(perfect_square_binary_search(0));\n        assert!(!perfect_square_binary_search(3));\n        assert!(!perfect_square_binary_search(-19));\n    }\n}\n"
  },
  {
    "path": "src/math/pollard_rho.rs",
    "content": "use super::miller_rabin;\n\nstruct LinearCongruenceGenerator {\n    // modulus as 2 ^ 32\n    multiplier: u32,\n    increment: u32,\n    state: u32,\n}\n\nimpl LinearCongruenceGenerator {\n    fn new(multiplier: u32, increment: u32, state: u32) -> Self {\n        Self {\n            multiplier,\n            increment,\n            state,\n        }\n    }\n    fn next(&mut self) -> u32 {\n        self.state = (self.multiplier as u64 * self.state as u64 + self.increment as u64) as u32;\n        self.state\n    }\n    fn get_64bits(&mut self) -> u64 {\n        ((self.next() as u64) << 32) | (self.next() as u64)\n    }\n}\n\nfn gcd(mut a: u64, mut b: u64) -> u64 {\n    while a != 0 {\n        let tmp = b % a;\n        b = a;\n        a = tmp;\n    }\n    b\n}\n\n#[inline]\nfn advance(x: u128, c: u64, number: u64) -> u128 {\n    ((x * x) + c as u128) % number as u128\n}\n\nfn pollard_rho_customizable(\n    number: u64,\n    x0: u64,\n    c: u64,\n    iterations_before_check: u32,\n    iterations_cutoff: u32,\n) -> u64 {\n    /*\n    Here we are using Brent's method for finding cycle.\n    It is generally faster because we will not use `advance` function as often\n    as Floyd's method.\n    We also wait to do a few iterations before calculating the GCD, because\n    it is an expensive function. We will correct for overshooting later.\n    This function may return either 1, `number` or a proper divisor of `number`\n     */\n    let mut x = x0 as u128; // tortoise\n    let mut x_start = 0_u128; // to save the starting tortoise if we overshoot\n    let mut y = 0_u128; // hare\n    let mut remainder = 1_u128;\n    let mut current_gcd = 1_u64;\n    let mut max_iterations = 1_u32;\n    while current_gcd == 1 {\n        y = x;\n        for _ in 1..max_iterations {\n            x = advance(x, c, number);\n        }\n        let mut big_iteration = 0_u32;\n        while big_iteration < max_iterations && current_gcd == 1 {\n            x_start = x;\n            let mut small_iteration = 0_u32;\n            while small_iteration < iterations_before_check\n                && small_iteration < (max_iterations - big_iteration)\n            {\n                small_iteration += 1;\n                x = advance(x, c, number);\n                let diff = x.abs_diff(y);\n                remainder = (remainder * diff) % number as u128;\n            }\n            current_gcd = gcd(remainder as u64, number);\n            big_iteration += iterations_before_check;\n        }\n        max_iterations *= 2;\n        if max_iterations > iterations_cutoff {\n            break;\n        }\n    }\n    if current_gcd == number {\n        while current_gcd == 1 {\n            x_start = advance(x_start, c, number);\n            current_gcd = gcd(x_start.abs_diff(y) as u64, number);\n        }\n    }\n    current_gcd\n}\n\n/*\nNote: using this function with `check_is_prime` = false\nand a prime number will result in an infinite loop.\n\nRNG's internal state is represented as `seed`. It is\nadvisable (but not mandatory) to reuse the saved seed value\nIn subsequent calls to this function.\n */\npub fn pollard_rho_get_one_factor(number: u64, seed: &mut u32, check_is_prime: bool) -> u64 {\n    // LCG parameters from wikipedia\n    let mut rng = LinearCongruenceGenerator::new(1103515245, 12345, *seed);\n    if number <= 1 {\n        return number;\n    }\n    if check_is_prime {\n        let mut bases = vec![2u64, 3, 5, 7];\n        if number > 3_215_031_000 {\n            bases.append(&mut vec![11, 13, 17, 19, 23, 29, 31, 37]);\n        }\n        if miller_rabin(number, &bases) == 0 {\n            return number;\n        }\n    }\n    let mut factor = 1u64;\n    while factor == 1 || factor == number {\n        let x = rng.get_64bits();\n        let c = rng.get_64bits();\n        factor = pollard_rho_customizable(\n            number,\n            (x % (number - 3)) + 2,\n            (c % (number - 2)) + 1,\n            32,\n            1 << 18, // This shouldn't take much longer than number ^ 0.25\n        );\n        // These numbers were selected based on local testing.\n        // For specific applications there maybe better choices.\n    }\n    *seed = rng.state;\n    factor\n}\n\nfn get_small_factors(mut number: u64, primes: &[usize]) -> (u64, Vec<u64>) {\n    let mut result: Vec<u64> = Vec::new();\n    for p in primes {\n        while number.is_multiple_of(*p as u64) {\n            number /= *p as u64;\n            result.push(*p as u64);\n        }\n    }\n    (number, result)\n}\n\nfn factor_using_mpf(mut number: usize, mpf: &[usize]) -> Vec<u64> {\n    let mut result = Vec::new();\n    while number > 1 {\n        result.push(mpf[number] as u64);\n        number /= mpf[number];\n    }\n    result\n}\n\n/*\n`primes` and `minimum_prime_factors` use usize because so does\nLinearSieve implementation in this repository\n */\npub fn pollard_rho_factorize(\n    mut number: u64,\n    seed: &mut u32,\n    primes: &[usize],\n    minimum_prime_factors: &[usize],\n) -> Vec<u64> {\n    if number <= 1 {\n        return vec![];\n    }\n    let mut result: Vec<u64> = Vec::new();\n    {\n        // Create a new scope to keep the outer scope clean\n        let (rem, mut res) = get_small_factors(number, primes);\n        number = rem;\n        result.append(&mut res);\n    }\n    if number == 1 {\n        return result;\n    }\n    let mut to_be_factored = vec![number];\n    while let Some(last) = to_be_factored.pop() {\n        if last < minimum_prime_factors.len() as u64 {\n            result.append(&mut factor_using_mpf(last as usize, minimum_prime_factors));\n            continue;\n        }\n        let fact = pollard_rho_get_one_factor(last, seed, true);\n        if fact == last {\n            result.push(last);\n            continue;\n        }\n        to_be_factored.push(fact);\n        to_be_factored.push(last / fact);\n    }\n    result.sort_unstable();\n    result\n}\n\n#[cfg(test)]\nmod test {\n    use super::super::LinearSieve;\n    use super::*;\n\n    fn check_is_proper_factor(number: u64, factor: u64) -> bool {\n        factor > 1 && factor < number && number.is_multiple_of(factor)\n    }\n\n    fn check_factorization(number: u64, factors: &[u64]) -> bool {\n        let bases = vec![2u64, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37];\n        let mut prod = 1_u64;\n        let mut prime_check = 0_u64;\n        for p in factors {\n            prod *= *p;\n            prime_check |= miller_rabin(*p, &bases);\n        }\n        prime_check == 0 && prod == number\n    }\n\n    #[test]\n    fn one_factor() {\n        // a few small cases\n        let mut sieve = LinearSieve::new();\n        sieve.prepare(1e5 as usize).unwrap();\n        let numbers = vec![1235, 239874233, 4353234, 456456, 120983];\n        let mut seed = 314159_u32; // first digits of pi; nothing up my sleeve\n        for num in numbers {\n            let factor = pollard_rho_get_one_factor(num, &mut seed, true);\n            assert!(check_is_proper_factor(num, factor));\n            let factor = pollard_rho_get_one_factor(num, &mut seed, false);\n            assert!(check_is_proper_factor(num, factor));\n            assert!(check_factorization(\n                num,\n                &pollard_rho_factorize(num, &mut seed, &sieve.primes, &sieve.minimum_prime_factor)\n            ));\n        }\n        // check if it goes into infinite loop if `number` is prime\n        let numbers = vec![\n            2, 3, 5, 7, 11, 13, 101, 998244353, 1000000007, 1000000009, 1671398671, 1652465729,\n            1894404511, 1683402997, 1661963047, 1946039987, 2071566551, 1867816303, 1952199377,\n            1622379469, 1739317499, 1775433631, 1994828917, 1818930719, 1672996277,\n        ];\n        for num in numbers {\n            assert_eq!(pollard_rho_get_one_factor(num, &mut seed, true), num);\n            assert!(check_factorization(\n                num,\n                &pollard_rho_factorize(num, &mut seed, &sieve.primes, &sieve.minimum_prime_factor)\n            ));\n        }\n    }\n    #[test]\n    fn big_numbers() {\n        // Bigger cases:\n        // Each of these numbers is a product of two 31 bit primes\n        // This shouldn't take more than a 10ms per number on a modern PC\n        let mut seed = 314159_u32; // first digits of pi; nothing up my sleeve\n        let numbers: Vec<u64> = vec![\n            2761929023323646159,\n            3189046231347719467,\n            3234246546378360389,\n            3869305776707280953,\n            3167208188639390813,\n            3088042782711408869,\n            3628455596280801323,\n            2953787574901819241,\n            3909561575378030219,\n            4357328471891213977,\n            2824368080144930999,\n            3348680054093203003,\n            2704267100962222513,\n            2916169237307181179,\n            3669851121098875703,\n        ];\n        for num in numbers {\n            assert!(check_factorization(\n                num,\n                &pollard_rho_factorize(num, &mut seed, &[], &[])\n            ));\n        }\n    }\n}\n"
  },
  {
    "path": "src/math/postfix_evaluation.rs",
    "content": "//! This module provides a function to evaluate postfix (Reverse Polish Notation) expressions.\n//! Postfix notation is a mathematical notation in which every operator follows all of its operands.\n//!\n//! The evaluator supports the four basic arithmetic operations: addition, subtraction, multiplication, and division.\n//! It handles errors such as division by zero, invalid operators, insufficient operands, and invalid postfix expressions.\n\n/// Enumeration of errors that can occur when evaluating a postfix expression.\n#[derive(Debug, PartialEq)]\npub enum PostfixError {\n    DivisionByZero,\n    InvalidOperator,\n    InsufficientOperands,\n    InvalidExpression,\n}\n\n/// Evaluates a postfix expression and returns the result or an error.\n///\n/// # Arguments\n///\n/// * `expression` - A string slice that contains the postfix expression to be evaluated.\n///                  The tokens (numbers and operators) should be separated by whitespace.\n///\n/// # Returns\n///\n/// * `Ok(isize)` if the expression is valid and evaluates to an integer.\n/// * `Err(PostfixError)` if the expression is invalid or encounters errors during evaluation.\n///\n/// # Errors\n///\n/// * `PostfixError::DivisionByZero` - If a division by zero is attempted.\n/// * `PostfixError::InvalidOperator` - If an unknown operator is encountered.\n/// * `PostfixError::InsufficientOperands` - If there are not enough operands for an operator.\n/// * `PostfixError::InvalidExpression` - If the expression is malformed (e.g., multiple values are left on the stack).\npub fn evaluate_postfix(expression: &str) -> Result<isize, PostfixError> {\n    let mut stack: Vec<isize> = Vec::new();\n\n    for token in expression.split_whitespace() {\n        if let Ok(number) = token.parse::<isize>() {\n            // If the token is a number, push it onto the stack.\n            stack.push(number);\n        } else {\n            // If the token is an operator, pop the top two values from the stack,\n            // apply the operator, and push the result back onto the stack.\n            if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {\n                match token {\n                    \"+\" => stack.push(a + b),\n                    \"-\" => stack.push(a - b),\n                    \"*\" => stack.push(a * b),\n                    \"/\" => {\n                        if b == 0 {\n                            return Err(PostfixError::DivisionByZero);\n                        }\n                        stack.push(a / b);\n                    }\n                    _ => return Err(PostfixError::InvalidOperator),\n                }\n            } else {\n                return Err(PostfixError::InsufficientOperands);\n            }\n        }\n    }\n    // The final result should be the only element on the stack.\n    if stack.len() == 1 {\n        Ok(stack[0])\n    } else {\n        Err(PostfixError::InvalidExpression)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! postfix_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $test_case;\n                    assert_eq!(evaluate_postfix(input), expected);\n                }\n            )*\n        }\n    }\n\n    postfix_tests! {\n        test_addition_of_two_numbers: (\"2 3 +\", Ok(5)),\n        test_multiplication_and_addition: (\"5 2 * 4 +\", Ok(14)),\n        test_simple_division: (\"10 2 /\", Ok(5)),\n        test_operator_without_operands: (\"+\", Err(PostfixError::InsufficientOperands)),\n        test_division_by_zero_error: (\"5 0 /\", Err(PostfixError::DivisionByZero)),\n        test_invalid_operator_in_expression: (\"2 3 #\", Err(PostfixError::InvalidOperator)),\n        test_missing_operator_for_expression: (\"2 3\", Err(PostfixError::InvalidExpression)),\n        test_extra_operands_in_expression: (\"2 3 4 +\", Err(PostfixError::InvalidExpression)),\n        test_empty_expression_error: (\"\", Err(PostfixError::InvalidExpression)),\n        test_single_number_expression: (\"42\", Ok(42)),\n        test_addition_of_negative_numbers: (\"-3 -2 +\", Ok(-5)),\n        test_complex_expression_with_multiplication_and_addition: (\"3 5 8 * 7 + *\", Ok(141)),\n        test_expression_with_extra_whitespace: (\"  3  4   +   \", Ok(7)),\n        test_valid_then_invalid_operator: (\"5 2 + 1 #\", Err(PostfixError::InvalidOperator)),\n        test_first_division_by_zero: (\"5 0 / 6 0 /\", Err(PostfixError::DivisionByZero)),\n        test_complex_expression_with_multiple_operators: (\"5 1 2 + 4 * + 3 -\", Ok(14)),\n        test_expression_with_only_whitespace: (\" \", Err(PostfixError::InvalidExpression)),\n    }\n}\n"
  },
  {
    "path": "src/math/prime_check.rs",
    "content": "pub fn prime_check(num: usize) -> bool {\n    if (num > 1) & (num < 4) {\n        return true;\n    } else if (num < 2) || (num.is_multiple_of(2)) {\n        return false;\n    }\n\n    let stop: usize = (num as f64).sqrt() as usize + 1;\n    for i in (3..stop).step_by(2) {\n        if num.is_multiple_of(i) {\n            return false;\n        }\n    }\n    true\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn basic() {\n        assert!(prime_check(3));\n        assert!(prime_check(7));\n        assert!(prime_check(11));\n        assert!(prime_check(2003));\n\n        assert!(!prime_check(4));\n        assert!(!prime_check(6));\n        assert!(!prime_check(21));\n        assert!(!prime_check(2004));\n    }\n}\n"
  },
  {
    "path": "src/math/prime_factors.rs",
    "content": "// Finds the prime factors of a number in increasing order, with repetition.\n\npub fn prime_factors(n: u64) -> Vec<u64> {\n    let mut i = 2;\n    let mut n = n;\n    let mut factors = Vec::new();\n    while i * i <= n {\n        if n.is_multiple_of(i) {\n            n /= i;\n            factors.push(i);\n        } else {\n            if i != 2 {\n                i += 1;\n            }\n            i += 1;\n        }\n    }\n    if n > 1 {\n        factors.push(n);\n    }\n    factors\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn it_works() {\n        assert_eq!(prime_factors(0), vec![]);\n        assert_eq!(prime_factors(1), vec![]);\n        assert_eq!(prime_factors(11), vec![11]);\n        assert_eq!(prime_factors(25), vec![5, 5]);\n        assert_eq!(prime_factors(33), vec![3, 11]);\n        assert_eq!(prime_factors(2560), vec![2, 2, 2, 2, 2, 2, 2, 2, 2, 5]);\n    }\n}\n"
  },
  {
    "path": "src/math/prime_numbers.rs",
    "content": "pub fn prime_numbers(max: usize) -> Vec<usize> {\n    let mut result: Vec<usize> = Vec::new();\n\n    if max >= 2 {\n        result.push(2)\n    }\n    for i in (3..=max).step_by(2) {\n        let stop: usize = (i as f64).sqrt() as usize + 1;\n        let mut status = true;\n\n        for j in (3..stop).step_by(2) {\n            if i % j == 0 {\n                status = false;\n                break;\n            }\n        }\n        if status {\n            result.push(i)\n        }\n    }\n\n    result\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn basic() {\n        assert_eq!(prime_numbers(0), vec![]);\n        assert_eq!(prime_numbers(11), vec![2, 3, 5, 7, 11]);\n        assert_eq!(prime_numbers(25), vec![2, 3, 5, 7, 11, 13, 17, 19, 23]);\n        assert_eq!(\n            prime_numbers(33),\n            vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/quadratic_residue.rs",
    "content": "/// Cipolla algorithm\n///\n/// Solving quadratic residue problem:\n///     x^2 = a (mod p) , p is an odd prime\n/// with O(M*log(n)) time complexity, M depends on the complexity of complex numbers multiplication.\n///\n/// Wikipedia reference: https://en.wikipedia.org/wiki/Cipolla%27s_algorithm\n/// When a is the primitive root modulo n, the answer is unique.\n/// Otherwise it will return the smallest positive solution\nuse std::rc::Rc;\nuse std::time::{SystemTime, UNIX_EPOCH};\n\nuse rand::RngExt;\n\nuse super::{fast_power, PCG32};\n\n#[derive(Debug)]\nstruct CustomFiniteField {\n    modulus: u64,\n    i_square: u64,\n}\n\nimpl CustomFiniteField {\n    pub fn new(modulus: u64, i_square: u64) -> Self {\n        Self { modulus, i_square }\n    }\n}\n\n#[derive(Clone, Debug)]\nstruct CustomComplexNumber {\n    real: u64,\n    imag: u64,\n    f: Rc<CustomFiniteField>,\n}\n\nimpl CustomComplexNumber {\n    pub fn new(real: u64, imag: u64, f: Rc<CustomFiniteField>) -> Self {\n        Self { real, imag, f }\n    }\n\n    pub fn mult_other(&mut self, rhs: &Self) {\n        let tmp = (self.imag * rhs.real + self.real * rhs.imag) % self.f.modulus;\n        self.real = (self.real * rhs.real\n            + ((self.imag * rhs.imag) % self.f.modulus) * self.f.i_square)\n            % self.f.modulus;\n        self.imag = tmp;\n    }\n\n    pub fn mult_self(&mut self) {\n        let tmp = (self.imag * self.real + self.real * self.imag) % self.f.modulus;\n        self.real = (self.real * self.real\n            + ((self.imag * self.imag) % self.f.modulus) * self.f.i_square)\n            % self.f.modulus;\n        self.imag = tmp;\n    }\n\n    pub fn fast_power(mut base: Self, mut power: u64) -> Self {\n        let mut result = CustomComplexNumber::new(1, 0, base.f.clone());\n        while power != 0 {\n            if (power & 1) != 0 {\n                result.mult_other(&base); // result *= base;\n            }\n            base.mult_self(); // base *= base;\n            power >>= 1;\n        }\n        result\n    }\n}\n\nfn is_residue(x: u64, modulus: u64) -> bool {\n    let power = (modulus - 1) >> 1;\n    x != 0 && fast_power(x as usize, power as usize, modulus as usize) == 1\n}\n\n/// The Legendre symbol `(a | p)`\n///\n/// Returns 0 if a = 0 mod p, 1 if a is a square mod p, -1 if it not a square mod p.\n///\n/// <https://en.wikipedia.org/wiki/Legendre_symbol>\npub fn legendre_symbol(a: u64, odd_prime: u64) -> i64 {\n    debug_assert!(!odd_prime.is_multiple_of(2), \"odd_prime must be odd\");\n    if a == 0 {\n        0\n    } else if is_residue(a, odd_prime) {\n        1\n    } else {\n        -1\n    }\n}\n\n// return two solutions (x1, x2) for Quadratic Residue problem x^2 = a (mod p), where p is an odd prime\n// if a is Quadratic Nonresidues, return None\npub fn cipolla(a: u32, p: u32, seed: Option<u64>) -> Option<(u32, u32)> {\n    // The params should be kept in u32 range for multiplication overflow issue\n    // But inside we use u64 for convenience\n    let a = a as u64;\n    let p = p as u64;\n    if a == 0 {\n        return Some((0, 0));\n    }\n    if !is_residue(a, p) {\n        return None;\n    }\n    let seed = match seed {\n        Some(seed) => seed,\n        None => SystemTime::now()\n            .duration_since(UNIX_EPOCH)\n            .unwrap()\n            .as_secs(),\n    };\n    let mut rng = PCG32::new_default(seed);\n    let r = loop {\n        let r = rng.get_u64() % p;\n        if r == 0 || !is_residue((p + r * r - a) % p, p) {\n            break r;\n        }\n    };\n    let filed = Rc::new(CustomFiniteField::new(p, (p + r * r - a) % p));\n    let comp = CustomComplexNumber::new(r, 1, filed);\n    let power = (p + 1) >> 1;\n    let x0 = CustomComplexNumber::fast_power(comp, power).real as u32;\n    let x1 = p as u32 - x0;\n    if x0 < x1 {\n        Some((x0, x1))\n    } else {\n        Some((x1, x0))\n    }\n}\n\n/// Returns one of the two possible solutions of _x² = a mod p_, if any.\n///\n/// The other solution is _-x mod p_. If there is no solution, returns `None`.\n///\n/// Reference: H. Cohen, _A course in computational algebraic number theory_, Algorithm 1.4.3\n///\n/// ## Implementation details\n///\n/// To avoid multiplication overflows, internally the algorithm uses the `128`-bit arithmetic.\n///\n/// Also see [`cipolla`].\npub fn tonelli_shanks(a: i64, odd_prime: u64) -> Option<u64> {\n    let p: u128 = odd_prime as u128;\n    let e = (p - 1).trailing_zeros();\n    let q = (p - 1) >> e; // p = 2^e * q, with q odd\n\n    let a = if a < 0 {\n        a.rem_euclid(p as i64) as u128\n    } else {\n        a as u128\n    };\n\n    let power_mod_p = |b, e| fast_power(b as usize, e as usize, p as usize) as u128;\n\n    // find generator: choose a random non-residue n mod p\n    let mut rng = rand::rng();\n    let n = loop {\n        let n = rng.random_range(0..p);\n        if legendre_symbol(n as u64, p as u64) == -1 {\n            break n;\n        }\n    };\n    let z = power_mod_p(n, q);\n\n    // init\n    let mut y = z;\n    let mut r = e;\n    let mut x = power_mod_p(a, (q - 1) / 2) % p;\n    let mut b = (a * x * x) % p;\n    x = (a * x) % p;\n\n    while b % p != 1 {\n        // find exponent\n        let m = (1..r)\n            .scan(b, |prev, m| {\n                *prev = (*prev * *prev) % p;\n                Some((m, *prev == 1))\n            })\n            .find_map(|(m, cond)| cond.then_some(m));\n        let Some(m) = m else {\n            return None; // non-residue\n        };\n\n        // reduce exponent\n        let t = power_mod_p(y as u128, 2_u128.pow(r - m - 1));\n        y = (t * t) % p;\n        r = m;\n        x = (x * t) % p;\n        b = (b * y) % p;\n    }\n\n    Some(x as u64)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn tonelli_shanks_residues(x: u64, odd_prime: u64) -> Option<(u64, u64)> {\n        let x = tonelli_shanks(x as i64, odd_prime)?;\n        let x2 = (-(x as i64)).rem_euclid(odd_prime as i64) as u64;\n        Some(if x < x2 { (x, x2) } else { (x2, x) })\n    }\n\n    #[test]\n    fn cipolla_small_numbers() {\n        assert_eq!(cipolla(1, 43, None), Some((1, 42)));\n        assert_eq!(cipolla(2, 23, None), Some((5, 18)));\n        assert_eq!(cipolla(17, 83, Some(42)), Some((10, 73)));\n    }\n\n    #[test]\n    fn tonelli_shanks_small_numbers() {\n        assert_eq!(tonelli_shanks_residues(1, 43).unwrap(), (1, 42));\n        assert_eq!(tonelli_shanks_residues(2, 23).unwrap(), (5, 18));\n        assert_eq!(tonelli_shanks_residues(17, 83).unwrap(), (10, 73));\n    }\n\n    #[test]\n    fn cipolla_random_numbers() {\n        assert_eq!(cipolla(392203, 852167, None), Some((413252, 438915)));\n        assert_eq!(\n            cipolla(379606557, 425172197, None),\n            Some((143417827, 281754370))\n        );\n        assert_eq!(\n            cipolla(585251669, 892950901, None),\n            Some((192354555, 700596346))\n        );\n        assert_eq!(\n            cipolla(404690348, 430183399, Some(19260817)),\n            Some((57227138, 372956261))\n        );\n        assert_eq!(\n            cipolla(210205747, 625380647, Some(998244353)),\n            Some((76810367, 548570280))\n        );\n    }\n\n    #[test]\n    fn tonelli_shanks_random_numbers() {\n        assert_eq!(\n            tonelli_shanks_residues(392203, 852167),\n            Some((413252, 438915))\n        );\n        assert_eq!(\n            tonelli_shanks_residues(379606557, 425172197),\n            Some((143417827, 281754370))\n        );\n        assert_eq!(\n            tonelli_shanks_residues(585251669, 892950901),\n            Some((192354555, 700596346))\n        );\n        assert_eq!(\n            tonelli_shanks_residues(404690348, 430183399),\n            Some((57227138, 372956261))\n        );\n        assert_eq!(\n            tonelli_shanks_residues(210205747, 625380647),\n            Some((76810367, 548570280))\n        );\n    }\n\n    #[test]\n    fn no_answer() {\n        assert_eq!(cipolla(650927, 852167, None), None);\n        assert_eq!(tonelli_shanks(650927, 852167), None);\n    }\n}\n"
  },
  {
    "path": "src/math/random.rs",
    "content": "/*\nPermuted Congruential Generator\nhttps://en.wikipedia.org/wiki/Permuted_congruential_generator\n\nNote that this is _NOT_ intended for serious applications. Use this generator\nat your own risk and only use your own values instead of the default ones if\nyou really know what you are doing.\n */\npub struct PCG32 {\n    state: u64,\n    multiplier: u64,\n    increment: u64,\n}\n\npub const PCG32_MULTIPLIER: u64 = 6364136223846793005_u64;\npub const PCG32_INCREMENT: u64 = 1442695040888963407_u64;\n\npub struct IterMut<'a> {\n    pcg: &'a mut PCG32,\n}\n\nimpl PCG32 {\n    /// `stream` should be less than 1 << 63\n    pub fn new(seed: u64, multiplier: u64, stream: u64) -> Self {\n        // We should make sure that increment is odd\n        let increment = (stream << 1) | 1;\n        let mut pcg = PCG32 {\n            state: seed.wrapping_add(increment),\n            multiplier,\n            increment,\n        };\n        pcg.next();\n        pcg\n    }\n    pub fn new_default(seed: u64) -> Self {\n        let multiplier = PCG32_MULTIPLIER;\n        let increment = PCG32_INCREMENT;\n        let mut pcg = PCG32 {\n            state: seed.wrapping_add(increment),\n            multiplier,\n            increment,\n        };\n        pcg.next();\n        pcg\n    }\n    #[inline]\n    pub fn next(&mut self) {\n        self.state = self\n            .state\n            .wrapping_mul(self.multiplier)\n            .wrapping_add(self.increment);\n    }\n    #[inline]\n    /// Advance the PCG by `delta` steps in O(lg(`delta`)) time. By passing\n    /// a negative i64 as u64, it can go back too.\n    pub fn advance(&mut self, mut delta: u64) {\n        let mut acc_mult = 1u64;\n        let mut acc_incr = 0u64;\n        let mut curr_mlt = self.multiplier;\n        let mut curr_inc = self.increment;\n        while delta > 0 {\n            if delta & 1 != 0 {\n                acc_mult = acc_mult.wrapping_mul(curr_mlt);\n                acc_incr = acc_incr.wrapping_mul(curr_mlt).wrapping_add(curr_inc);\n            }\n            curr_inc = curr_mlt.wrapping_add(1).wrapping_mul(curr_inc);\n            curr_mlt = curr_mlt.wrapping_mul(curr_mlt);\n            delta >>= 1;\n        }\n        self.state = acc_mult.wrapping_mul(self.state).wrapping_add(acc_incr);\n    }\n    #[inline]\n    pub fn get_u32(&mut self) -> u32 {\n        let mut x = self.state;\n        let count = (x >> 59) as u32;\n\n        self.next();\n\n        x ^= x >> 18;\n        ((x >> 27) as u32).rotate_right(count)\n    }\n    #[inline]\n    pub fn get_u64(&mut self) -> u64 {\n        self.get_u32() as u64 ^ ((self.get_u32() as u64) << 32)\n    }\n    #[inline]\n    pub fn get_u16(&mut self) -> (u16, u16) {\n        let res = self.get_u32();\n        (res as u16, (res >> 16) as u16)\n    }\n    #[inline]\n    pub fn get_u8(&mut self) -> (u8, u8, u8, u8) {\n        let res = self.get_u32();\n        (\n            res as u8,\n            (res >> 8) as u8,\n            (res >> 16) as u8,\n            (res >> 24) as u8,\n        )\n    }\n    #[inline]\n    pub fn get_state(&self) -> u64 {\n        self.state\n    }\n    pub fn iter_mut(&mut self) -> IterMut<'_> {\n        IterMut { pcg: self }\n    }\n}\n\nimpl Iterator for IterMut<'_> {\n    type Item = u32;\n    fn next(&mut self) -> Option<Self::Item> {\n        Some(self.pcg.get_u32())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn no_birthday() {\n        // If the distribution is not almost uniform, the probability of\n        // birthday paradox increases. For n=2^32 and k=1e5, the probability\n        // of not having a collision is about (1 - (k+1)/n) ^ (k/2) which is\n        // 0.3121 for this (n, k).\n        // So this test is a (dumb) test for distribution, and for speed. This\n        // is only basic sanity checking, as the actual algorithm was\n        // rigorously tested by others before.\n        let numbers = 1e5 as usize;\n        let mut pcg = PCG32::new_default(314159);\n        let mut pcg2 = PCG32::new_default(314159);\n        assert_eq!(pcg.get_u32(), pcg2.get_u32());\n        let mut randoms: Vec<u32> = pcg.iter_mut().take(numbers).collect::<Vec<u32>>();\n        pcg2.advance(1000);\n        assert_eq!(pcg2.get_u32(), randoms[1000]);\n        pcg2.advance((-1001_i64) as u64);\n        assert_eq!(pcg2.get_u32(), randoms[0]);\n        randoms.sort_unstable();\n        randoms.dedup();\n        assert_eq!(randoms.len(), numbers);\n    }\n}\n"
  },
  {
    "path": "src/math/relu.rs",
    "content": "//Rust implementation of the ReLU (rectified linear unit) activation function.\n//The formula for ReLU is quite simple really: (if x>0 -> x, else -> 0)\n//More information on the concepts of ReLU can be found here:\n//https://en.wikipedia.org/wiki/Rectifier_(neural_networks)\n\n//The function below takes a reference to a mutable <f32> Vector as an argument\n//and returns the vector with 'ReLU' applied to all values.\n//Of course, these functions can be changed by the developer so that the input vector isn't manipulated.\n//This is simply an implemenation of the formula.\n\npub fn relu(array: &mut Vec<f32>) -> &mut Vec<f32> {\n    //note that these calculations are assuming the Vector values consists of real numbers in radians\n    for value in &mut *array {\n        if value <= &mut 0. {\n            *value = 0.;\n        }\n    }\n\n    array\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_relu() {\n        let mut test: Vec<f32> = Vec::from([1.0, 0.5, -1.0, 0.0, 0.3]);\n        assert_eq!(\n            relu(&mut test),\n            &mut Vec::<f32>::from([1.0, 0.5, 0.0, 0.0, 0.3])\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/sieve_of_eratosthenes.rs",
    "content": "/// Implements the Sieve of Eratosthenes algorithm to find all prime numbers up to a given limit.\n///\n/// # Arguments\n///\n/// * `num` - The upper limit up to which to find prime numbers (inclusive).\n///\n/// # Returns\n///\n/// A vector containing all prime numbers up to the specified limit.\npub fn sieve_of_eratosthenes(num: usize) -> Vec<usize> {\n    let mut result: Vec<usize> = Vec::new();\n    if num >= 2 {\n        let mut sieve: Vec<bool> = vec![true; num + 1];\n\n        // 0 and 1 are not prime numbers\n        sieve[0] = false;\n        sieve[1] = false;\n\n        let end: usize = (num as f64).sqrt() as usize;\n\n        // Mark non-prime numbers in the sieve and collect primes up to `end`\n        update_sieve(&mut sieve, end, num, &mut result);\n\n        // Collect remaining primes beyond `end`\n        result.extend(extract_remaining_primes(&sieve, end + 1));\n    }\n    result\n}\n\n/// Marks non-prime numbers in the sieve and collects prime numbers up to `end`.\n///\n/// # Arguments\n///\n/// * `sieve` - A mutable slice of booleans representing the sieve.\n/// * `end` - The square root of the upper limit, used to optimize the algorithm.\n/// * `num` - The upper limit up to which to mark non-prime numbers.\n/// * `result` - A mutable vector to store the prime numbers.\nfn update_sieve(sieve: &mut [bool], end: usize, num: usize, result: &mut Vec<usize>) {\n    for start in 2..=end {\n        if sieve[start] {\n            result.push(start); // Collect prime numbers up to `end`\n            for i in (start * start..=num).step_by(start) {\n                sieve[i] = false;\n            }\n        }\n    }\n}\n\n/// Extracts remaining prime numbers from the sieve beyond the given start index.\n///\n/// # Arguments\n///\n/// * `sieve` - A slice of booleans representing the sieve with non-prime numbers marked as false.\n/// * `start` - The index to start checking for primes (inclusive).\n///\n/// # Returns\n///\n/// A vector containing all remaining prime numbers extracted from the sieve.\nfn extract_remaining_primes(sieve: &[bool], start: usize) -> Vec<usize> {\n    sieve[start..]\n        .iter()\n        .enumerate()\n        .filter_map(|(i, &is_prime)| if is_prime { Some(start + i) } else { None })\n        .collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    const PRIMES_UP_TO_997: [usize; 168] = [\n        2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89,\n        97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181,\n        191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,\n        283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397,\n        401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,\n        509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619,\n        631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743,\n        751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863,\n        877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,\n    ];\n\n    macro_rules! sieve_tests {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let input: usize = $test_case;\n                    let expected: Vec<usize> = PRIMES_UP_TO_997.iter().cloned().filter(|&x| x <= input).collect();\n                    assert_eq!(sieve_of_eratosthenes(input), expected);\n                }\n            )*\n        }\n    }\n\n    sieve_tests! {\n        test_0: 0,\n        test_1: 1,\n        test_2: 2,\n        test_3: 3,\n        test_4: 4,\n        test_5: 5,\n        test_6: 6,\n        test_7: 7,\n        test_11: 11,\n        test_23: 23,\n        test_24: 24,\n        test_25: 25,\n        test_26: 26,\n        test_27: 27,\n        test_28: 28,\n        test_29: 29,\n        test_33: 33,\n        test_100: 100,\n        test_997: 997,\n        test_998: 998,\n        test_999: 999,\n        test_1000: 1000,\n    }\n}\n"
  },
  {
    "path": "src/math/sigmoid.rs",
    "content": "//Rust implementation of the Sigmoid activation function.\n//The formula for Sigmoid: 1 / (1 + e^(-x))\n//More information on the concepts of Sigmoid can be found here:\n//https://en.wikipedia.org/wiki/Sigmoid_function\n\n//The function below takes a reference to a mutable <f32> Vector as an argument\n//and returns the vector with 'Sigmoid' applied to all values.\n//Of course, these functions can be changed by the developer so that the input vector isn't manipulated.\n//This is simply an implemenation of the formula.\n\nuse std::f32::consts::E;\n\npub fn sigmoid(array: &mut Vec<f32>) -> &mut Vec<f32> {\n    //note that these calculations are assuming the Vector values consists of real numbers in radians\n    for value in &mut *array {\n        *value = 1. / (1. + E.powf(-1. * *value));\n    }\n\n    array\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_sigmoid() {\n        let mut test = Vec::from([1.0, 0.5, -1.0, 0.0, 0.3]);\n        assert_eq!(\n            sigmoid(&mut test),\n            &mut Vec::<f32>::from([0.7310586, 0.62245935, 0.26894143, 0.5, 0.5744425,])\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/signum.rs",
    "content": "/// Signum function is a mathematical function that extracts\n/// the sign of a real number. It is also known as the sign function,\n/// and it is an odd piecewise function.\n/// If a number is negative, i.e. it is less than zero, then sgn(x) = -1\n/// If a number is zero, then sgn(0) = 0\n/// If a number is positive, i.e. it is greater than zero, then sgn(x) = 1\n\npub fn signum(number: f64) -> i8 {\n    if number == 0.0 {\n        return 0;\n    } else if number > 0.0 {\n        return 1;\n    }\n\n    -1\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn positive_integer() {\n        assert_eq!(signum(15.0), 1);\n    }\n\n    #[test]\n    fn negative_integer() {\n        assert_eq!(signum(-30.0), -1);\n    }\n\n    #[test]\n    fn zero() {\n        assert_eq!(signum(0.0), 0);\n    }\n}\n"
  },
  {
    "path": "src/math/simpsons_integration.rs",
    "content": "pub fn simpsons_integration<F>(f: F, a: f64, b: f64, n: usize) -> f64\nwhere\n    F: Fn(f64) -> f64,\n{\n    let h = (b - a) / n as f64;\n    (0..n)\n        .map(|i| {\n            let x0 = a + i as f64 * h;\n            let x1 = x0 + h / 2.0;\n            let x2 = x0 + h;\n            (h / 6.0) * (f(x0) + 4.0 * f(x1) + f(x2))\n        })\n        .sum()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_simpsons_integration() {\n        let f = |x: f64| x.powi(2);\n        let a = 0.0;\n        let b = 1.0;\n        let n = 100;\n        let result = simpsons_integration(f, a, b, n);\n        assert!((result - 1.0 / 3.0).abs() < 1e-6);\n    }\n\n    #[test]\n    fn test_error() {\n        let f = |x: f64| x.powi(2);\n        let a = 0.0;\n        let b = 1.0;\n        let n = 100;\n        let result = simpsons_integration(f, a, b, n);\n        let error = (1.0 / 3.0 - result).abs();\n        assert!(error < 1e-6);\n    }\n\n    #[test]\n    fn test_convergence() {\n        let f = |x: f64| x.powi(2);\n        let a = 0.0;\n        let b = 1.0;\n        let n = 100;\n        let result1 = simpsons_integration(f, a, b, n);\n        let result2 = simpsons_integration(f, a, b, 2 * n);\n        let result3 = simpsons_integration(f, a, b, 4 * n);\n        let result4 = simpsons_integration(f, a, b, 8 * n);\n        assert!((result1 - result2).abs() < 1e-6);\n        assert!((result2 - result3).abs() < 1e-6);\n        assert!((result3 - result4).abs() < 1e-6);\n    }\n\n    #[test]\n    fn test_negative() {\n        let f = |x: f64| -x.powi(2);\n        let a = 0.0;\n        let b = 1.0;\n        let n = 100;\n        let result = simpsons_integration(f, a, b, n);\n        assert!((result + 1.0 / 3.0).abs() < 1e-6);\n    }\n\n    #[test]\n    fn test_non_zero_lower_bound() {\n        let f = |x: f64| x.powi(2);\n        let a = 1.0;\n        let b = 2.0;\n        let n = 100;\n        let result = simpsons_integration(f, a, b, n);\n        assert!((result - 7.0 / 3.0).abs() < 1e-6);\n    }\n\n    #[test]\n    fn test_non_zero_upper_bound() {\n        let f = |x: f64| x.powi(2);\n        let a = 0.0;\n        let b = 2.0;\n        let n = 100;\n        let result = simpsons_integration(f, a, b, n);\n        assert!((result - 8.0 / 3.0).abs() < 1e-6);\n    }\n\n    #[test]\n    fn test_non_zero_lower_and_upper_bound() {\n        let f = |x: f64| x.powi(2);\n        let a = 1.0;\n        let b = 2.0;\n        let n = 100;\n        let result = simpsons_integration(f, a, b, n);\n        assert!((result - 7.0 / 3.0).abs() < 1e-6);\n    }\n\n    #[test]\n    fn test_non_zero_lower_and_upper_bound_negative() {\n        let f = |x: f64| -x.powi(2);\n        let a = 1.0;\n        let b = 2.0;\n        let n = 100;\n        let result = simpsons_integration(f, a, b, n);\n        assert!((result + 7.0 / 3.0).abs() < 1e-6);\n    }\n\n    #[test]\n    fn parabola_curve_length() {\n        // Calculate the length of the curve f(x) = x^2 for -5 <= x <= 5\n        // We should integrate sqrt(1 + (f'(x))^2)\n        let function = |x: f64| -> f64 { (1.0 + 4.0 * x * x).sqrt() };\n        let result = simpsons_integration(function, -5.0, 5.0, 1_000);\n        let integrated = |x: f64| -> f64 { (x * function(x) / 2.0) + ((2.0 * x).asinh() / 4.0) };\n        let expected = integrated(5.0) - integrated(-5.0);\n        assert!((result - expected).abs() < 1e-9);\n    }\n\n    #[test]\n    fn area_under_cosine() {\n        use std::f64::consts::PI;\n        // Calculate area under f(x) = cos(x) + 5 for -pi <= x <= pi\n        // cosine should cancel out and the answer should be 2pi * 5\n        let function = |x: f64| -> f64 { x.cos() + 5.0 };\n        let result = simpsons_integration(function, -PI, PI, 1_000);\n        let expected = 2.0 * PI * 5.0;\n        assert!((result - expected).abs() < 1e-9);\n    }\n}\n"
  },
  {
    "path": "src/math/softmax.rs",
    "content": "//! # Softmax Function\n//!\n//! The `softmax` function computes the softmax values of a given array of f32 numbers.\n//!\n//! The softmax operation is often used in machine learning for converting a vector of real numbers into a\n//! probability distribution. It exponentiates each element in the input array, and then normalizes the\n//! results so that they sum to 1.\n//!\n//! ## Formula\n//!\n//! For a given input array `x`, the softmax function computes the output `y` as follows:\n//!\n//! `y_i = e^(x_i) / sum(e^(x_j) for all j)`\n//!\n//! ## Softmax Function Implementation\n//!\n//! This implementation uses the `std::f32::consts::E` constant for the base of the exponential function. and\n//! f32 vectors to compute the values. The function creates a new vector and not altering the input vector.\n//!\nuse std::f32::consts::E;\n\npub fn softmax(array: Vec<f32>) -> Vec<f32> {\n    let mut softmax_array = array;\n\n    for value in &mut softmax_array {\n        *value = E.powf(*value);\n    }\n\n    let sum: f32 = softmax_array.iter().sum();\n\n    for value in &mut softmax_array {\n        *value /= sum;\n    }\n\n    softmax_array\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_softmax() {\n        let test = vec![9.0, 0.5, -3.0, 0.0, 3.0];\n        assert_eq!(\n            softmax(test),\n            vec![\n                0.9971961,\n                0.00020289792,\n                6.126987e-6,\n                0.00012306382,\n                0.0024718025\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/sprague_grundy_theorem.rs",
    "content": "/**\n * Sprague Grundy Theorem for combinatorial games like Nim\n *\n * The Sprague Grundy Theorem is a fundamental concept in combinatorial game theory, commonly used to analyze\n * games like Nim. It calculates the Grundy number (also known as the nimber) for a position in a game.\n * The Grundy number represents the game's position, and it helps determine the winning strategy.\n *\n * The Grundy number of a terminal state is 0; otherwise, it is recursively defined as the minimum\n * excludant (mex) of the Grundy values of possible next states.\n *\n * For more details on Sprague Grundy Theorem, you can visit:(https://en.wikipedia.org/wiki/Sprague%E2%80%93Grundy_theorem)\n *\n * Author : [Gyandeep](https://github.com/Gyan172004)\n */\n\npub fn calculate_grundy_number(\n    position: i64,\n    grundy_numbers: &mut [i64],\n    possible_moves: &[i64],\n) -> i64 {\n    // Check if we've already calculated the Grundy number for this position.\n    if grundy_numbers[position as usize] != -1 {\n        return grundy_numbers[position as usize];\n    }\n\n    // Base case: terminal state\n    if position == 0 {\n        grundy_numbers[0] = 0;\n        return 0;\n    }\n\n    // Calculate Grundy values for possible next states.\n    let mut next_state_grundy_values: Vec<i64> = vec![];\n    for move_size in possible_moves.iter() {\n        if position - move_size >= 0 {\n            next_state_grundy_values.push(calculate_grundy_number(\n                position - move_size,\n                grundy_numbers,\n                possible_moves,\n            ));\n        }\n    }\n\n    // Sort the Grundy values and find the minimum excludant.\n    next_state_grundy_values.sort_unstable();\n    let mut mex: i64 = 0;\n    for grundy_value in next_state_grundy_values.iter() {\n        if *grundy_value != mex {\n            break;\n        }\n        mex += 1;\n    }\n\n    // Store the calculated Grundy number and return it.\n    grundy_numbers[position as usize] = mex;\n    mex\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn calculate_grundy_number_test() {\n        let mut grundy_numbers: Vec<i64> = vec![-1; 7];\n        let possible_moves: Vec<i64> = vec![1, 4];\n        calculate_grundy_number(6, &mut grundy_numbers, &possible_moves);\n        assert_eq!(grundy_numbers, [0, 1, 0, 1, 2, 0, 1]);\n    }\n}\n"
  },
  {
    "path": "src/math/square_pyramidal_numbers.rs",
    "content": "// https://en.wikipedia.org/wiki/Square_pyramidal_number\n// 1² + 2² + ... = ... (total)\n\npub fn square_pyramidal_number(n: u64) -> u64 {\n    n * (n + 1) * (2 * n + 1) / 6\n}\n\n#[cfg(test)]\nmod tests {\n\n    use super::*;\n\n    #[test]\n    fn test0() {\n        assert_eq!(0, square_pyramidal_number(0));\n        assert_eq!(1, square_pyramidal_number(1));\n        assert_eq!(5, square_pyramidal_number(2));\n        assert_eq!(14, square_pyramidal_number(3));\n    }\n}\n"
  },
  {
    "path": "src/math/square_root.rs",
    "content": "/// squre_root returns the square root\n/// of a f64 number using Newton's method\npub fn square_root(num: f64) -> f64 {\n    if num < 0.0_f64 {\n        return f64::NAN;\n    }\n\n    let mut root = 1.0_f64;\n\n    while (root * root - num).abs() > 1e-10_f64 {\n        root -= (root * root - num) / (2.0_f64 * root);\n    }\n\n    root\n}\n\n// fast_inv_sqrt returns an approximation of the inverse square root\n// This algorithm was first used in Quake and has been reimplemented in a few other languages\n// This crate implements it more thoroughly: https://docs.rs/quake-inverse-sqrt/latest/quake_inverse_sqrt/\npub fn fast_inv_sqrt(num: f32) -> f32 {\n    // If you are confident in your input this can be removed for speed\n    if num < 0.0f32 {\n        return f32::NAN;\n    }\n\n    let i = num.to_bits();\n    let i = 0x5f3759df - (i >> 1);\n    let y = f32::from_bits(i);\n\n    println!(\"num: {:?}, out: {:?}\", num, y * (1.5 - 0.5 * num * y * y));\n    // First iteration of Newton's approximation\n    y * (1.5 - 0.5 * num * y * y)\n    // The above can be repeated for more precision\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_fast_inv_sqrt() {\n        // Negatives don't have square roots:\n        assert!(fast_inv_sqrt(-1.0f32).is_nan());\n\n        // Test a few cases, expect less than 1% error:\n        let test_pairs = [(4.0, 0.5), (16.0, 0.25), (25.0, 0.2)];\n        for pair in test_pairs {\n            assert!((fast_inv_sqrt(pair.0) - pair.1).abs() <= (0.01 * pair.0));\n        }\n    }\n\n    #[test]\n    fn test_sqare_root() {\n        assert!((square_root(4.0_f64) - 2.0_f64).abs() <= 1e-10_f64);\n        assert!(square_root(-4.0_f64).is_nan());\n    }\n}\n"
  },
  {
    "path": "src/math/sum_of_digits.rs",
    "content": "/// Iteratively sums the digits of a signed integer\n///\n/// ## Arguments\n///\n/// * `num` - The number to sum the digits of\n///\n/// ## Examples\n///\n/// ```\n/// use the_algorithms_rust::math::sum_digits_iterative;\n///\n/// assert_eq!(10, sum_digits_iterative(1234));\n/// assert_eq!(12, sum_digits_iterative(-246));\n/// ```\npub fn sum_digits_iterative(num: i32) -> u32 {\n    // convert to unsigned integer\n    let mut num = num.unsigned_abs();\n    // initialize sum\n    let mut result: u32 = 0;\n\n    // iterate through digits\n    while num > 0 {\n        // extract next digit and add to sum\n        result += num % 10;\n        num /= 10; // chop off last digit\n    }\n    result\n}\n\n/// Recursively sums the digits of a signed integer\n///\n/// ## Arguments\n///\n/// * `num` - The number to sum the digits of\n///\n/// ## Examples\n///\n/// ```\n/// use the_algorithms_rust::math::sum_digits_recursive;\n///\n/// assert_eq!(10, sum_digits_recursive(1234));\n/// assert_eq!(12, sum_digits_recursive(-246));\n/// ```\npub fn sum_digits_recursive(num: i32) -> u32 {\n    // convert to unsigned integer\n    let num = num.unsigned_abs();\n    // base case\n    if num < 10 {\n        return num;\n    }\n    // recursive case: add last digit to sum of remaining digits\n    num % 10 + sum_digits_recursive((num / 10) as i32)\n}\n\n#[cfg(test)]\nmod tests {\n    mod iterative {\n        // import relevant sum_digits function\n        use super::super::sum_digits_iterative as sum_digits;\n\n        #[test]\n        fn zero() {\n            assert_eq!(0, sum_digits(0));\n        }\n        #[test]\n        fn positive_number() {\n            assert_eq!(1, sum_digits(1));\n            assert_eq!(10, sum_digits(1234));\n            assert_eq!(14, sum_digits(42161));\n            assert_eq!(6, sum_digits(500010));\n        }\n        #[test]\n        fn negative_number() {\n            assert_eq!(1, sum_digits(-1));\n            assert_eq!(12, sum_digits(-246));\n            assert_eq!(2, sum_digits(-11));\n            assert_eq!(14, sum_digits(-42161));\n            assert_eq!(6, sum_digits(-500010));\n        }\n        #[test]\n        fn trailing_zeros() {\n            assert_eq!(1, sum_digits(1000000000));\n            assert_eq!(3, sum_digits(300));\n        }\n    }\n\n    mod recursive {\n        // import relevant sum_digits function\n        use super::super::sum_digits_recursive as sum_digits;\n\n        #[test]\n        fn zero() {\n            assert_eq!(0, sum_digits(0));\n        }\n        #[test]\n        fn positive_number() {\n            assert_eq!(1, sum_digits(1));\n            assert_eq!(10, sum_digits(1234));\n            assert_eq!(14, sum_digits(42161));\n            assert_eq!(6, sum_digits(500010));\n        }\n        #[test]\n        fn negative_number() {\n            assert_eq!(1, sum_digits(-1));\n            assert_eq!(12, sum_digits(-246));\n            assert_eq!(2, sum_digits(-11));\n            assert_eq!(14, sum_digits(-42161));\n            assert_eq!(6, sum_digits(-500010));\n        }\n        #[test]\n        fn trailing_zeros() {\n            assert_eq!(1, sum_digits(1000000000));\n            assert_eq!(3, sum_digits(300));\n        }\n    }\n}\n"
  },
  {
    "path": "src/math/sum_of_geometric_progression.rs",
    "content": "// Author : cyrixninja\n// Find the Sum of Geometric Progression\n// Wikipedia: https://en.wikipedia.org/wiki/Geometric_progression\n\npub fn sum_of_geometric_progression(first_term: f64, common_ratio: f64, num_of_terms: i32) -> f64 {\n    if common_ratio == 1.0 {\n        // Formula for sum if the common ratio is 1\n        return (num_of_terms as f64) * first_term;\n    }\n\n    // Formula for finding the sum of n terms of a Geometric Progression\n    (first_term / (1.0 - common_ratio)) * (1.0 - common_ratio.powi(num_of_terms))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_sum_of_geometric_progression {\n        ($($name:ident: $inputs:expr,)*) => {\n        $(\n            #[test]\n            fn $name() {\n                let (first_term, common_ratio, num_of_terms, expected) = $inputs;\n                assert_eq!(sum_of_geometric_progression(first_term, common_ratio, num_of_terms), expected);\n            }\n        )*\n        }\n    }\n\n    test_sum_of_geometric_progression! {\n        regular_input_0: (1.0, 2.0, 10, 1023.0),\n        regular_input_1: (1.0, 10.0, 5, 11111.0),\n        regular_input_2: (9.0, 2.5, 5, 579.9375),\n        common_ratio_one: (10.0, 1.0, 3, 30.0),\n    }\n}\n"
  },
  {
    "path": "src/math/sum_of_harmonic_series.rs",
    "content": "// Author : cyrixninja\n// Sum of Harmonic Series :    Find the sum of n terms in an harmonic progression.  The calculation starts with the\n//                             first_term and loops adding the common difference of Arithmetic Progression by which\n//                             the given Harmonic Progression is linked.\n// Wikipedia Reference  :  https://en.wikipedia.org/wiki/Interquartile_range\n// Other References     :  https://the-algorithms.com/algorithm/sum-of-harmonic-series?lang=python\n\npub fn sum_of_harmonic_progression(\n    first_term: f64,\n    common_difference: f64,\n    number_of_terms: i32,\n) -> f64 {\n    let mut arithmetic_progression = vec![1.0 / first_term];\n    let mut current_term = 1.0 / first_term;\n\n    for _ in 0..(number_of_terms - 1) {\n        current_term += common_difference;\n        arithmetic_progression.push(current_term);\n    }\n\n    let harmonic_series: Vec<f64> = arithmetic_progression\n        .into_iter()\n        .map(|step| 1.0 / step)\n        .collect();\n    harmonic_series.iter().sum()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_sum_of_harmonic_progression() {\n        assert_eq!(sum_of_harmonic_progression(1.0 / 2.0, 2.0, 2), 0.75);\n        assert_eq!(\n            sum_of_harmonic_progression(1.0 / 5.0, 5.0, 5),\n            0.45666666666666667\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/sylvester_sequence.rs",
    "content": "// Author : cyrixninja\n// Sylvester Series     :  Calculates the nth number in Sylvester's sequence.\n// Wikipedia Reference  :  https://en.wikipedia.org/wiki/Sylvester%27s_sequence\n// Other References     :  https://the-algorithms.com/algorithm/sylvester-sequence?lang=python\n\npub fn sylvester(number: i32) -> i128 {\n    assert!(number > 0, \"The input value of [n={number}] has to be > 0\");\n\n    if number == 1 {\n        2\n    } else {\n        let num = sylvester(number - 1);\n        let lower = num - 1;\n        let upper = num;\n        lower * upper + 1\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_sylvester() {\n        assert_eq!(sylvester(8), 113423713055421844361000443_i128);\n    }\n\n    #[test]\n    #[should_panic(expected = \"The input value of [n=-1] has to be > 0\")]\n    fn test_sylvester_negative() {\n        sylvester(-1);\n    }\n}\n"
  },
  {
    "path": "src/math/tanh.rs",
    "content": "//Rust implementation of the Tanh (hyperbolic tangent) activation function.\n//The formula for Tanh: (e^x - e^(-x))/(e^x + e^(-x)) OR (2/(1+e^(-2x))-1\n//More information on the concepts of Sigmoid can be found here:\n//https://en.wikipedia.org/wiki/Hyperbolic_functions\n\n//The function below takes a reference to a mutable <f32> Vector as an argument\n//and returns the vector with 'Tanh' applied to all values.\n//Of course, these functions can be changed by the developer so that the input vector isn't manipulated.\n//This is simply an implemenation of the formula.\n\nuse std::f32::consts::E;\n\npub fn tanh(array: &mut Vec<f32>) -> &mut Vec<f32> {\n    //note that these calculations are assuming the Vector values consists of real numbers in radians\n    for value in &mut *array {\n        *value = (2. / (1. + E.powf(-2. * *value))) - 1.;\n    }\n\n    array\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_tanh() {\n        let mut test = Vec::from([1.0, 0.5, -1.0, 0.0, 0.3]);\n        assert_eq!(\n            tanh(&mut test),\n            &mut Vec::<f32>::from([0.76159406, 0.4621172, -0.7615941, 0.0, 0.29131258,])\n        );\n    }\n}\n"
  },
  {
    "path": "src/math/trapezoidal_integration.rs",
    "content": "pub fn trapezoidal_integral<F>(a: f64, b: f64, f: F, precision: u32) -> f64\nwhere\n    F: Fn(f64) -> f64,\n{\n    let delta = (b - a) / precision as f64;\n\n    (0..precision)\n        .map(|trapezoid| {\n            let left_side = a + (delta * trapezoid as f64);\n            let right_side = left_side + delta;\n\n            0.5 * (f(left_side) + f(right_side)) * delta\n        })\n        .sum()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_trapezoidal_integral {\n        ($($name:ident: $inputs:expr,)*) => {\n        $(\n            #[test]\n            fn $name() {\n                let (a, b, f, prec, expected, eps) = $inputs;\n                let actual = trapezoidal_integral(a, b, f, prec);\n                assert!((actual - expected).abs() < eps);\n            }\n        )*\n        }\n    }\n\n    test_trapezoidal_integral! {\n        basic_0: (0.0, 1.0, |x: f64| x.powi(2), 1000, 1.0/3.0, 0.0001),\n        basic_0_higher_prec: (0.0, 1.0, |x: f64| x.powi(2), 10000, 1.0/3.0, 0.00001),\n        basic_1: (-1.0, 1.0, |x: f64| x.powi(2), 10000, 2.0/3.0, 0.00001),\n        basic_1_higher_prec: (-1.0, 1.0, |x: f64| x.powi(2), 100000, 2.0/3.0, 0.000001),\n        flipped_limits: (1.0, 0.0, |x: f64| x.powi(2), 10000, -1.0/3.0, 0.00001),\n        empty_range: (0.5, 0.5, |x: f64| x.powi(2), 100, 0.0, 0.0000001),\n    }\n}\n"
  },
  {
    "path": "src/math/trial_division.rs",
    "content": "fn floor(value: f64, scale: u8) -> f64 {\n    let multiplier = 10i64.pow(scale as u32) as f64;\n    (value * multiplier).floor()\n}\n\nfn double_to_int(amount: f64) -> i128 {\n    amount.round() as i128\n}\n\npub fn trial_division(mut num: i128) -> Vec<i128> {\n    if num < 0 {\n        return trial_division(-num);\n    }\n    let mut result: Vec<i128> = vec![];\n\n    if num == 0 {\n        return result;\n    }\n\n    while num % 2 == 0 {\n        result.push(2);\n        num /= 2;\n        num = double_to_int(floor(num as f64, 0))\n    }\n    let mut f: i128 = 3;\n\n    while f.pow(2) <= num {\n        if num % f == 0 {\n            result.push(f);\n            num /= f;\n            num = double_to_int(floor(num as f64, 0))\n        } else {\n            f += 2\n        }\n    }\n\n    if num != 1 {\n        result.push(num)\n    }\n    result\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn basic() {\n        assert_eq!(trial_division(0), vec![]);\n        assert_eq!(trial_division(1), vec![]);\n        assert_eq!(trial_division(9), vec!(3, 3));\n        assert_eq!(trial_division(-9), vec!(3, 3));\n        assert_eq!(trial_division(10), vec!(2, 5));\n        assert_eq!(trial_division(11), vec!(11));\n        assert_eq!(trial_division(33), vec!(3, 11));\n        assert_eq!(trial_division(2003), vec!(2003));\n        assert_eq!(trial_division(100001), vec!(11, 9091));\n    }\n}\n"
  },
  {
    "path": "src/math/trig_functions.rs",
    "content": "/// Function that contains the similarities of the sine and cosine implementations\n///\n/// Both of them are calculated using their MacLaurin Series\n///\n/// Because there is just a '+1' that differs in their formula, this function has been\n/// created for not repeating\nfn template<T: Into<f64>>(x: T, tol: f64, kind: i32) -> f64 {\n    use std::f64::consts::PI;\n    const PERIOD: f64 = 2.0 * PI;\n    /* Sometimes, this function is called for a big 'n'(when tol is very small) */\n    fn factorial(n: i128) -> i128 {\n        (1..=n).product()\n    }\n\n    /* Function to round up to the 'decimal'th decimal of the number 'x' */\n    fn round_up_to_decimal(x: f64, decimal: i32) -> f64 {\n        let multiplier = 10f64.powi(decimal);\n        (x * multiplier).round() / multiplier\n    }\n\n    let mut value: f64 = x.into(); //<-- This is the line for which the trait 'Into' is required\n\n    /* Check for invalid arguments */\n    if !value.is_finite() || value.is_nan() {\n        eprintln!(\"This function does not accept invalid arguments.\");\n        return f64::NAN;\n    }\n\n    /*\n        The argument to sine could be bigger than the sine's PERIOD\n        To prevent overflowing, strip the value off relative to the PERIOD\n    */\n    while value >= PERIOD {\n        value -= PERIOD;\n    }\n    /* For cases when the value is smaller than the -PERIOD (e.g. sin(-3π) <=> sin(-π)) */\n    while value <= -PERIOD {\n        value += PERIOD;\n    }\n\n    let mut rez = 0f64;\n    let mut prev_rez = 1f64;\n    let mut step: i32 = 0;\n    /*\n        This while instruction is the MacLaurin Series for sine / cosine\n        sin(x) = Σ (-1)^n * x^2n+1 / (2n+1)!, for n >= 0 and x a Real number\n        cos(x) = Σ (-1)^n * x^2n / (2n)!, for n >= 0 and x a Real number\n\n        '+1' in sine's formula is replaced with 'kind', which values are:\n            -> kind = 0, for cosine\n            -> kind = 1, for sine\n    */\n    while (prev_rez - rez).abs() > tol {\n        prev_rez = rez;\n        rez += (-1f64).powi(step) * value.powi(2 * step + kind)\n            / factorial((2 * step + kind) as i128) as f64;\n        step += 1;\n    }\n\n    /* Round up to the 6th decimal */\n    round_up_to_decimal(rez, 6)\n}\n\n/// Returns the value of sin(x), approximated with the given tolerance\n///\n/// This function supposes the argument is in radians\n///\n/// ### Example\n///\n/// sin(1) == sin(1 rad) == sin(π/180)\npub fn sine<T: Into<f64>>(x: T, tol: f64) -> f64 {\n    template(x, tol, 1)\n}\n\n/// Returns the value of cos, approximated with the given tolerance, for\n/// an angle 'x' in radians\npub fn cosine<T: Into<f64>>(x: T, tol: f64) -> f64 {\n    template(x, tol, 0)\n}\n\n/// Cosine of 'x' in degrees, with the given tolerance\npub fn cosine_no_radian_arg<T: Into<f64>>(x: T, tol: f64) -> f64 {\n    use std::f64::consts::PI;\n    let val: f64 = x.into();\n    cosine(val * PI / 180., tol)\n}\n\n/// Sine function for non radian angle\n///\n/// Interprets the argument in degrees, not in radians\n///\n/// ### Example\n///\n/// sin(1<sup>o</sup>) != \\[ sin(1 rad) == sin(π/180) \\]\npub fn sine_no_radian_arg<T: Into<f64>>(x: T, tol: f64) -> f64 {\n    use std::f64::consts::PI;\n    let val: f64 = x.into();\n    sine(val * PI / 180f64, tol)\n}\n\n/// Tangent of angle 'x' in radians, calculated with the given tolerance\npub fn tan<T: Into<f64> + Copy>(x: T, tol: f64) -> f64 {\n    let cos_val = cosine(x, tol);\n\n    /* Cover special cases for division */\n    if cos_val == 0f64 {\n        f64::NAN\n    } else {\n        let sin_val = sine(x, tol);\n        sin_val / cos_val\n    }\n}\n\n/// Cotangent of angle 'x' in radians, calculated with the given tolerance\npub fn cotan<T: Into<f64> + Copy>(x: T, tol: f64) -> f64 {\n    let sin_val = sine(x, tol);\n\n    /* Cover special cases for division */\n    if sin_val == 0f64 {\n        f64::NAN\n    } else {\n        let cos_val = cosine(x, tol);\n        cos_val / sin_val\n    }\n}\n\n/// Tangent of 'x' in degrees, approximated with the given tolerance\npub fn tan_no_radian_arg<T: Into<f64> + Copy>(x: T, tol: f64) -> f64 {\n    let angle: f64 = x.into();\n\n    use std::f64::consts::PI;\n    tan(angle * PI / 180., tol)\n}\n\n/// Cotangent of 'x' in degrees, approximated with the given tolerance\npub fn cotan_no_radian_arg<T: Into<f64> + Copy>(x: T, tol: f64) -> f64 {\n    let angle: f64 = x.into();\n\n    use std::f64::consts::PI;\n    cotan(angle * PI / 180., tol)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::f64::consts::PI;\n\n    enum TrigFuncType {\n        Sine,\n        Cosine,\n        Tan,\n        Cotan,\n    }\n\n    const TOL: f64 = 1e-10;\n\n    impl TrigFuncType {\n        fn verify<T: Into<f64> + Copy>(&self, angle: T, expected_result: f64, is_radian: bool) {\n            let value = match self {\n                TrigFuncType::Sine => {\n                    if is_radian {\n                        sine(angle, TOL)\n                    } else {\n                        sine_no_radian_arg(angle, TOL)\n                    }\n                }\n                TrigFuncType::Cosine => {\n                    if is_radian {\n                        cosine(angle, TOL)\n                    } else {\n                        cosine_no_radian_arg(angle, TOL)\n                    }\n                }\n                TrigFuncType::Tan => {\n                    if is_radian {\n                        tan(angle, TOL)\n                    } else {\n                        tan_no_radian_arg(angle, TOL)\n                    }\n                }\n                TrigFuncType::Cotan => {\n                    if is_radian {\n                        cotan(angle, TOL)\n                    } else {\n                        cotan_no_radian_arg(angle, TOL)\n                    }\n                }\n            };\n\n            assert_eq!(format!(\"{value:.5}\"), format!(\"{:.5}\", expected_result));\n        }\n    }\n\n    #[test]\n    fn test_sine() {\n        let sine_id = TrigFuncType::Sine;\n        sine_id.verify(0.0, 0.0, true);\n        sine_id.verify(-PI, 0.0, true);\n        sine_id.verify(-PI / 2.0, -1.0, true);\n        sine_id.verify(0.5, 0.4794255386, true);\n        /* Same tests, but angle is now in degrees */\n        sine_id.verify(0, 0.0, false);\n        sine_id.verify(-180, 0.0, false);\n        sine_id.verify(-180 / 2, -1.0, false);\n        sine_id.verify(0.5, 0.00872654, false);\n    }\n\n    #[test]\n    fn test_sine_bad_arg() {\n        assert!(sine(f64::NEG_INFINITY, 1e-1).is_nan());\n        assert!(sine_no_radian_arg(f64::NAN, 1e-1).is_nan());\n    }\n\n    #[test]\n    fn test_cosine_bad_arg() {\n        assert!(cosine(f64::INFINITY, 1e-1).is_nan());\n        assert!(cosine_no_radian_arg(f64::NAN, 1e-1).is_nan());\n    }\n\n    #[test]\n    fn test_cosine() {\n        let cosine_id = TrigFuncType::Cosine;\n        cosine_id.verify(0, 1., true);\n        cosine_id.verify(0, 1., false);\n        cosine_id.verify(45, 1. / f64::sqrt(2.), false);\n        cosine_id.verify(PI / 4., 1. / f64::sqrt(2.), true);\n        cosine_id.verify(360, 1., false);\n        cosine_id.verify(2. * PI, 1., true);\n        cosine_id.verify(15. * PI / 2., 0.0, true);\n        cosine_id.verify(-855, -1. / f64::sqrt(2.), false);\n    }\n\n    #[test]\n    fn test_tan_bad_arg() {\n        assert!(tan(PI / 2., TOL).is_nan());\n        assert!(tan(3. * PI / 2., TOL).is_nan());\n    }\n\n    #[test]\n    fn test_tan() {\n        let tan_id = TrigFuncType::Tan;\n        tan_id.verify(PI / 4., 1f64, true);\n        tan_id.verify(45, 1f64, false);\n        tan_id.verify(PI, 0f64, true);\n        tan_id.verify(180 + 45, 1f64, false);\n        tan_id.verify(60 - 2 * 180, 1.7320508075, false);\n        tan_id.verify(30 + 180 - 180, 0.57735026919, false);\n    }\n\n    #[test]\n    fn test_cotan_bad_arg() {\n        assert!(cotan(tan(PI / 2., TOL), TOL).is_nan());\n        assert!(!cotan(0, TOL).is_finite());\n    }\n\n    #[test]\n    fn test_cotan() {\n        let cotan_id = TrigFuncType::Cotan;\n        cotan_id.verify(PI / 4., 1f64, true);\n        cotan_id.verify(90 + 10 * 180, 0f64, false);\n        cotan_id.verify(30 - 5 * 180, f64::sqrt(3.), false);\n    }\n}\n"
  },
  {
    "path": "src/math/vector_cross_product.rs",
    "content": "/// Cross Product and Magnitude Calculation\n///\n/// This program defines functions to calculate the cross product of two 3D vectors\n/// and the magnitude of a vector from its direction ratios. The main purpose is\n/// to demonstrate the mathematical concepts and provide test cases for the functions.\n///\n/// Time Complexity:\n/// - Calculating the cross product and magnitude of a vector each takes O(1) time\n///   since we are working with fixed-size arrays and performing a fixed number of\n///   mathematical operations.\n\n/// Function to calculate the cross product of two vectors\npub fn cross_product(vec1: [f64; 3], vec2: [f64; 3]) -> [f64; 3] {\n    let x = vec1[1] * vec2[2] - vec1[2] * vec2[1];\n    let y = -(vec1[0] * vec2[2] - vec1[2] * vec2[0]);\n    let z = vec1[0] * vec2[1] - vec1[1] * vec2[0];\n    [x, y, z]\n}\n\n/// Function to calculate the magnitude of a vector\npub fn vector_magnitude(vec: [f64; 3]) -> f64 {\n    (vec[0].powi(2) + vec[1].powi(2) + vec[2].powi(2)).sqrt()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_cross_product_and_magnitude_1() {\n        // Test case with non-trivial vectors\n        let vec1 = [1.0, 2.0, 3.0];\n        let vec2 = [4.0, 5.0, 6.0];\n\n        let cross_product = cross_product(vec1, vec2);\n        let magnitude = vector_magnitude(cross_product);\n\n        // Check the expected results with a tolerance for floating-point comparisons\n        assert_eq!(cross_product, [-3.0, 6.0, -3.0]);\n        assert!((magnitude - 7.34847).abs() < 1e-5);\n    }\n\n    #[test]\n    fn test_cross_product_and_magnitude_2() {\n        // Test case with orthogonal vectors\n        let vec1 = [1.0, 0.0, 0.0];\n        let vec2 = [0.0, 1.0, 0.0];\n\n        let cross_product = cross_product(vec1, vec2);\n        let magnitude = vector_magnitude(cross_product);\n\n        // Check the expected results\n        assert_eq!(cross_product, [0.0, 0.0, 1.0]);\n        assert_eq!(magnitude, 1.0);\n    }\n\n    #[test]\n    fn test_cross_product_and_magnitude_3() {\n        // Test case with vectors along the axes\n        let vec1 = [2.0, 0.0, 0.0];\n        let vec2 = [0.0, 3.0, 0.0];\n\n        let cross_product = cross_product(vec1, vec2);\n        let magnitude = vector_magnitude(cross_product);\n\n        // Check the expected results\n        assert_eq!(cross_product, [0.0, 0.0, 6.0]);\n        assert_eq!(magnitude, 6.0);\n    }\n\n    #[test]\n    fn test_cross_product_and_magnitude_4() {\n        // Test case with parallel vectors\n        let vec1 = [1.0, 2.0, 3.0];\n        let vec2 = [2.0, 4.0, 6.0];\n\n        let cross_product = cross_product(vec1, vec2);\n        let magnitude = vector_magnitude(cross_product);\n\n        // Check the expected results\n        assert_eq!(cross_product, [0.0, 0.0, 0.0]);\n        assert_eq!(magnitude, 0.0);\n    }\n\n    #[test]\n    fn test_cross_product_and_magnitude_5() {\n        // Test case with zero vectors\n        let vec1 = [0.0, 0.0, 0.0];\n        let vec2 = [0.0, 0.0, 0.0];\n\n        let cross_product = cross_product(vec1, vec2);\n        let magnitude = vector_magnitude(cross_product);\n\n        // Check the expected results\n        assert_eq!(cross_product, [0.0, 0.0, 0.0]);\n        assert_eq!(magnitude, 0.0);\n    }\n}\n"
  },
  {
    "path": "src/math/zellers_congruence_algorithm.rs",
    "content": "// returns the day of the week from the Gregorian Date\n\npub fn zellers_congruence_algorithm(date: i32, month: i32, year: i32, as_string: bool) -> String {\n    let q = date;\n    let (m, y) = if month < 3 {\n        (month + 12, year - 1)\n    } else {\n        (month, year)\n    };\n    let day: i32 =\n        (q + (26 * (m + 1) / 10) + (y % 100) + ((y % 100) / 4) + ((y / 100) / 4) + (5 * (y / 100)))\n            % 7;\n    if as_string {\n        number_to_day(day)\n    } else {\n        day.to_string()\n    }\n    /* Note that the day follows the following guidelines:\n    0 = Saturday\n    1 = Sunday\n    2 = Monday\n    3 = Tuesday\n    4 = Wednesday\n    5 = Thursday\n    6 = Friday\n    */\n}\n\nfn number_to_day(number: i32) -> String {\n    let days = [\n        \"Saturday\",\n        \"Sunday\",\n        \"Monday\",\n        \"Tuesday\",\n        \"Wednesday\",\n        \"Thursday\",\n        \"Friday\",\n    ];\n    String::from(days[number as usize])\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn it_works() {\n        assert_eq!(zellers_congruence_algorithm(25, 1, 2013, false), \"6\");\n        assert_eq!(zellers_congruence_algorithm(25, 1, 2013, true), \"Friday\");\n        assert_eq!(zellers_congruence_algorithm(16, 4, 2022, false), \"0\");\n        assert_eq!(zellers_congruence_algorithm(16, 4, 2022, true), \"Saturday\");\n        assert_eq!(zellers_congruence_algorithm(14, 12, 1978, false), \"5\");\n        assert_eq!(zellers_congruence_algorithm(15, 6, 2021, false), \"3\");\n    }\n}\n"
  },
  {
    "path": "src/navigation/bearing.rs",
    "content": "use std::f64::consts::PI;\n\npub fn bearing(lat1: f64, lng1: f64, lat2: f64, lng2: f64) -> f64 {\n    let lat1 = lat1 * PI / 180.0;\n    let lng1 = lng1 * PI / 180.0;\n\n    let lat2 = lat2 * PI / 180.0;\n    let lng2 = lng2 * PI / 180.0;\n\n    let delta_longitude = lng2 - lng1;\n\n    let y = delta_longitude.sin() * lat2.cos();\n    let x = lat1.cos() * lat2.sin() - lat1.sin() * lat2.cos() * delta_longitude.cos();\n\n    let mut brng = y.atan2(x);\n    brng = brng.to_degrees();\n\n    (brng + 360.0) % 360.0\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn testing() {\n        assert_eq!(\n            format!(\n                \"{:.0}º\",\n                bearing(\n                    -27.2020447088982,\n                    -49.631891179172555,\n                    -3.106362,\n                    -60.025826,\n                )\n            ),\n            \"336º\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/navigation/haversine.rs",
    "content": "use std::f64::consts::PI;\n\nconst EARTH_RADIUS: f64 = 6371000.00;\n\npub fn haversine(lat1: f64, lng1: f64, lat2: f64, lng2: f64) -> f64 {\n    let delta_dist_lat = (lat2 - lat1) * PI / 180.0;\n    let delta_dist_lng = (lng2 - lng1) * PI / 180.0;\n\n    let cos1 = lat1 * PI / 180.0;\n    let cos2 = lat2 * PI / 180.0;\n\n    let delta_lat = (delta_dist_lat / 2.0).sin().powf(2.0);\n    let delta_lng = (delta_dist_lng / 2.0).sin().powf(2.0);\n\n    let a = delta_lat + delta_lng * cos1.cos() * cos2.cos();\n    let result = 2.0 * a.asin().sqrt();\n\n    result * EARTH_RADIUS\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn testing() {\n        assert_eq!(\n            format!(\n                \"{:.2}km\",\n                haversine(52.375603, 4.903206, 52.366059, 4.926692) / 1000.0\n            ),\n            \"1.92km\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/navigation/mod.rs",
    "content": "mod bearing;\nmod haversine;\nmod rhumbline;\npub use self::bearing::bearing;\npub use self::haversine::haversine;\npub use self::rhumbline::rhumb_bearing;\npub use self::rhumbline::rhumb_destination;\npub use self::rhumbline::rhumb_dist;\n"
  },
  {
    "path": "src/navigation/rhumbline.rs",
    "content": "use std::f64::consts::PI;\n\nconst EARTH_RADIUS: f64 = 6371000.0;\n\npub fn rhumb_dist(lat1: f64, long1: f64, lat2: f64, long2: f64) -> f64 {\n    let phi1 = lat1 * PI / 180.00;\n    let phi2 = lat2 * PI / 180.00;\n    let del_phi = phi2 - phi1;\n    let mut del_lambda = (long2 - long1) * PI / 180.00;\n\n    if del_lambda > PI {\n        del_lambda -= 2.00 * PI;\n    } else if del_lambda < -PI {\n        del_lambda += 2.00 * PI;\n    }\n\n    let del_psi = ((phi2 / 2.00 + PI / 4.00).tan() / (phi1 / 2.00 + PI / 4.00).tan()).ln();\n    let q = if del_psi.abs() > 1e-12 {\n        del_phi / del_psi\n    } else {\n        phi1.cos()\n    };\n\n    (del_phi.powf(2.00) + (q * del_lambda).powf(2.00)).sqrt() * EARTH_RADIUS\n}\n\npub fn rhumb_bearing(lat1: f64, long1: f64, lat2: f64, long2: f64) -> f64 {\n    let phi1 = lat1 * PI / 180.00;\n    let phi2 = lat2 * PI / 180.00;\n    let mut del_lambda = (long2 - long1) * PI / 180.00;\n\n    if del_lambda > PI {\n        del_lambda -= 2.0 * PI;\n    } else if del_lambda < -PI {\n        del_lambda += 2.0 * PI;\n    }\n\n    let del_psi = ((phi2 / 2.00 + PI / 4.00).tan() / (phi1 / 2.00 + PI / 4.00).tan()).ln();\n    let bearing = del_lambda.atan2(del_psi) * 180.0 / PI;\n    (bearing + 360.00) % 360.00\n}\npub fn rhumb_destination(lat: f64, long: f64, distance: f64, bearing: f64) -> (f64, f64) {\n    let del = distance / EARTH_RADIUS;\n    let phi1 = lat * PI / 180.00;\n    let lambda1 = long * PI / 180.00;\n    let theta = bearing * PI / 180.00;\n\n    let del_phi = del * theta.cos();\n    let phi2 = (phi1 + del_phi).clamp(-PI / 2.0, PI / 2.0);\n\n    let del_psi = ((phi2 / 2.00 + PI / 4.00).tan() / (phi1 / 2.0 + PI / 4.0).tan()).ln();\n    let q = if del_psi.abs() > 1e-12 {\n        del_phi / del_psi\n    } else {\n        phi1.cos()\n    };\n\n    let del_lambda = del * theta.sin() / q;\n    let lambda2 = lambda1 + del_lambda;\n\n    (phi2 * 180.00 / PI, lambda2 * 180.00 / PI)\n}\n\n// TESTS\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_rhumb_distance() {\n        let distance = rhumb_dist(28.5416, 77.2006, 28.5457, 77.1928);\n        assert!(distance > 700.00 && distance < 1000.0);\n    }\n\n    #[test]\n    fn test_rhumb_bearing() {\n        let bearing = rhumb_bearing(28.5416, 77.2006, 28.5457, 77.1928);\n        assert!((bearing - 300.0).abs() < 5.0);\n    }\n\n    #[test]\n    fn test_rhumb_destination_point() {\n        let (lat, lng) = rhumb_destination(28.5457, 77.1928, 1000.00, 305.0);\n        assert!((lat - 28.550).abs() < 0.010);\n        assert!((lng - 77.1851).abs() < 0.010);\n    }\n    // edge cases\n\n    #[test]\n    fn test_rhumb_distance_cross_antimeridian() {\n        // Test when del_lambda > PI (line 12)\n        let distance = rhumb_dist(0.0, 170.0, 0.0, -170.0);\n        assert!(distance > 0.0);\n    }\n\n    #[test]\n    fn test_rhumb_distance_cross_antimeridian_negative() {\n        // Test when del_lambda < -PI (line 14)\n        let distance = rhumb_dist(0.0, -170.0, 0.0, 170.0);\n        assert!(distance > 0.0);\n    }\n\n    #[test]\n    fn test_rhumb_distance_to_equator() {\n        // Test when del_psi is near zero (line 21 - the else branch)\n        let distance = rhumb_dist(0.0, 0.0, 0.0, 1.0);\n        assert!(distance > 0.0);\n    }\n}\n"
  },
  {
    "path": "src/number_theory/compute_totient.rs",
    "content": "// Totient function for\n// all numbers smaller than\n// or equal to n.\n\n// Computes and prints\n// totient of all numbers\n// smaller than or equal to n\n\nuse std::vec;\n\npub fn compute_totient(n: i32) -> vec::Vec<i32> {\n    let mut phi: Vec<i32> = Vec::new();\n\n    // initialize phi[i] = i\n    for i in 0..=n {\n        phi.push(i);\n    }\n\n    // Compute other Phi values\n    for p in 2..=n {\n        // If phi[p] is not computed already,\n        // then number p is prime\n        if phi[(p) as usize] == p {\n            // Phi of a prime number p is\n            // always equal to p-1.\n            phi[(p) as usize] = p - 1;\n\n            // Update phi values of all\n            // multiples of p\n            for i in ((2 * p)..=n).step_by(p as usize) {\n                phi[(i) as usize] = (phi[i as usize] / p) * (p - 1);\n            }\n        }\n    }\n\n    phi[1..].to_vec()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_1() {\n        assert_eq!(\n            compute_totient(12),\n            vec![1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4]\n        );\n    }\n\n    #[test]\n    fn test_2() {\n        assert_eq!(compute_totient(7), vec![1, 1, 2, 2, 4, 2, 6]);\n    }\n\n    #[test]\n    fn test_3() {\n        assert_eq!(compute_totient(4), vec![1, 1, 2, 2]);\n    }\n}\n"
  },
  {
    "path": "src/number_theory/euler_totient.rs",
    "content": "pub fn euler_totient(n: u64) -> u64 {\n    let mut result = n;\n    let mut num = n;\n    let mut p = 2;\n\n    // Find  all prime factors and apply formula\n    while p * p <= num {\n        // Check if p is a divisor of n\n        if num.is_multiple_of(p) {\n            // If yes, then it is a prime factor\n            // Apply the formula: result = result * (1 - 1/p)\n            while num.is_multiple_of(p) {\n                num /= p;\n            }\n            result -= result / p;\n        }\n        p += 1;\n    }\n\n    // If num > 1, then it is a prime factor\n    if num > 1 {\n        result -= result / num;\n    }\n\n    result\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    macro_rules! test_euler_totient {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $test_case;\n                    assert_eq!(euler_totient(input), expected)\n                }\n            )*\n        };\n    }\n\n    test_euler_totient! {\n        prime_2: (2, 1),\n        prime_3: (3, 2),\n        prime_5: (5, 4),\n        prime_7: (7, 6),\n        prime_11: (11, 10),\n        prime_13: (13, 12),\n        prime_17: (17, 16),\n        prime_19: (19, 18),\n\n        composite_6: (6, 2),     // 2 * 3\n        composite_10: (10, 4),   // 2 * 5\n        composite_15: (15, 8),   // 3 * 5\n        composite_12: (12, 4),   // 2^2 * 3\n        composite_18: (18, 6),   // 2 * 3^2\n        composite_20: (20, 8),   // 2^2 * 5\n        composite_30: (30, 8),   // 2 * 3 * 5\n\n        prime_power_2_to_2: (4, 2),\n        prime_power_2_to_3: (8, 4),\n        prime_power_3_to_2: (9, 6),\n        prime_power_2_to_4: (16, 8),\n        prime_power_5_to_2: (25, 20),\n        prime_power_3_to_3: (27, 18),\n        prime_power_2_to_5: (32, 16),\n\n        // Large numbers\n        large_50: (50, 20),      // 2 * 5^2\n        large_100: (100, 40),    // 2^2 * 5^2\n        large_1000: (1000, 400), // 2^3 * 5^3\n    }\n}\n"
  },
  {
    "path": "src/number_theory/kth_factor.rs",
    "content": "// Kth Factor of N\n// The idea is to check for each number in the range [N, 1], and print the Kth number that divides N completely.\n\npub fn kth_factor(n: i32, k: i32) -> i32 {\n    let mut factors: Vec<i32> = Vec::new();\n    let k = (k as usize) - 1;\n    for i in 1..=n {\n        if n % i == 0 {\n            factors.push(i);\n        }\n        if let Some(number) = factors.get(k) {\n            return *number;\n        }\n    }\n    -1\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_1() {\n        assert_eq!(kth_factor(12, 3), 3);\n    }\n\n    #[test]\n    fn test_2() {\n        assert_eq!(kth_factor(7, 2), 7);\n    }\n\n    #[test]\n    fn test_3() {\n        assert_eq!(kth_factor(4, 4), -1);\n    }\n\n    #[test]\n    fn test_4() {\n        assert_eq!(kth_factor(950, 5), 19);\n    }\n}\n"
  },
  {
    "path": "src/number_theory/mod.rs",
    "content": "mod compute_totient;\nmod euler_totient;\nmod kth_factor;\n\npub use self::compute_totient::compute_totient;\npub use self::euler_totient::euler_totient;\npub use self::kth_factor::kth_factor;\n"
  },
  {
    "path": "src/searching/README.md",
    "content": "## Search Algorithms\n\n### [Linear](./linear_search.rs)\n![alt text][linear-image]\n\nFrom [Wikipedia][linear-wiki]: linear search or sequential search is a method for finding a target value within a list. It sequentially checks each element of the list for the target value until a match is found or until all the elements have been searched.\n  Linear search runs in at worst linear time and makes at most n comparisons, where n is the length of the list.\n\n__Properties__\n* Worst case performance\tO(n)\n* Best case performance\tO(1)\n* Average case performance\tO(n)\n* Worst case space complexity\tO(1) iterative\n\n### [Binary](./binary_search.rs)\n![alt text][binary-image]\n\nFrom [Wikipedia][binary-wiki]: Binary search, also known as half-interval search or logarithmic search, is a search algorithm that finds the position of a target value within a sorted array. It compares the target value to the middle element of the array; if they are unequal, the half in which the target cannot lie is eliminated and the search continues on the remaining half until it is successful.\n\n__Properties__\n* Worst case performance\tO(log n)\n* Best case performance\tO(1)\n* Average case performance\tO(log n)\n* Worst case space complexity\tO(1) \n\n### [Exponential](./exponential_search.rs)\n![alt text][exponential-image]\n\nFrom [Wikipedia][exponential-wiki]: Exponential search allows for searching through a sorted, unbounded list for a specified input value (the search \"key\"). The algorithm consists of two stages. The first stage determines a range in which the search key would reside if it were in the list. In the second stage, a binary search is performed on this range. In the first stage, assuming that the list is sorted in ascending order, the algorithm looks for the first exponent, j, where the value 2^j is greater than the search key. This value, 2^j becomes the upper bound for the binary search with the previous power of 2, 2^(j - 1), being the lower bound for the binary search.\n\n__Properties__\n* Worst case performance O(log i)\n* Best case performance O(1)\n* Average case performance O(log i)\n* Worst case space complexity O(1)\n\n### [Jump](./jump_search.rs)\n![alt text][jump-image]\n\nFrom [Wikipedia][jump-wiki]: In computer science, a jump search or block search refers to a search algorithm for ordered lists. It works by first checking all items L(km), where k ∈ N and m is the block size, until an item is found that is larger than the search key. To find the exact position of the search key in the list a linear search is performed on the sublist L[(k-1)m, km].\n\n__Properties__\n* Worst case performance O(√n)\n* Best case performance O(1)\n* Average case performance O(√n)\n* Worst case space complexity O(1)\n\n### [Fibonacci](./fibonacci_search.rs)\n\nFrom [Wikipedia][fibonacci-wiki]: In computer science, the Fibonacci search technique is a method of searching a sorted array using a divide and conquer algorithm that narrows down possible locations with the aid of Fibonacci numbers. Compared to binary search where the sorted array is divided into two equal-sized parts, one of which is examined further, Fibonacci search divides the array into two parts that have sizes that are consecutive Fibonacci numbers.\n\n__Properties__\n* Worst case performance O(log n)\n* Best case performance O(1)\n* Average case performance O(log n)\n* Worst case space complexity O(1)\n\n[linear-wiki]: https://en.wikipedia.org/wiki/Linear_search\n[linear-image]: http://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif\n\n[binary-wiki]: https://en.wikipedia.org/wiki/Binary_search_algorithm\n[binary-image]: https://upload.wikimedia.org/wikipedia/commons/f/f7/Binary_search_into_array.png\n\n[exponential-wiki]: https://en.wikipedia.org/wiki/Exponential_search\n[exponential-image]: https://upload.wikimedia.org/wikipedia/commons/4/45/Exponential_search.svg\n\n[jump-wiki]: https://en.wikipedia.org/wiki/Jump_search\n[jump-image]: https://static.studytonight.com/data-structures/images/Jump%20Search%20technique.PNG\n\n[fibonacci-wiki]: https://en.wikipedia.org/wiki/Fibonacci_search_technique\n"
  },
  {
    "path": "src/searching/binary_search.rs",
    "content": "//! This module provides an implementation of a binary search algorithm that\n//! works for both ascending and descending ordered arrays. The binary search\n//! function returns the index of the target element if it is found, or `None`\n//! if the target is not present in the array.\n\nuse std::cmp::Ordering;\n\n/// Performs a binary search for a specified item within a sorted array.\n///\n/// This function can handle both ascending and descending ordered arrays. It\n/// takes a reference to the item to search for and a slice of the array. If\n/// the item is found, it returns the index of the item within the array. If\n/// the item is not found, it returns `None`.\n///\n/// # Parameters\n///\n/// - `item`: A reference to the item to search for.\n/// - `arr`: A slice of the sorted array in which to search.\n///\n/// # Returns\n///\n/// An `Option<usize>` which is:\n/// - `Some(index)` if the item is found at the given index.\n/// - `None` if the item is not found in the array.\npub fn binary_search<T: Ord>(item: &T, arr: &[T]) -> Option<usize> {\n    let is_asc = is_asc_arr(arr);\n\n    let mut left = 0;\n    let mut right = arr.len();\n\n    while left < right {\n        if match_compare(item, arr, &mut left, &mut right, is_asc) {\n            return Some(left);\n        }\n    }\n\n    None\n}\n\n/// Compares the item with the middle element of the current search range and\n/// updates the search bounds accordingly. This function handles both ascending\n/// and descending ordered arrays. It calculates the middle index of the\n/// current search range and compares the item with the element at\n/// this index. It then updates the search bounds (`left` and `right`) based on\n/// the result of this comparison. If the item is found, it updates `left` to\n/// the index of the found item and returns `true`.\n///\n/// # Parameters\n///\n/// - `item`: A reference to the item to search for.\n/// - `arr`: A slice of the array in which to search.\n/// - `left`: A mutable reference to the left bound of the search range.\n/// - `right`: A mutable reference to the right bound of the search range.\n/// - `is_asc`: A boolean indicating whether the array is sorted in ascending order.\n///\n/// # Returns\n///\n/// A `bool` indicating whether the item was found.\nfn match_compare<T: Ord>(\n    item: &T,\n    arr: &[T],\n    left: &mut usize,\n    right: &mut usize,\n    is_asc: bool,\n) -> bool {\n    let mid = *left + (*right - *left) / 2;\n    let cmp_result = item.cmp(&arr[mid]);\n\n    match (is_asc, cmp_result) {\n        (true, Ordering::Less) | (false, Ordering::Greater) => {\n            *right = mid;\n        }\n        (true, Ordering::Greater) | (false, Ordering::Less) => {\n            *left = mid + 1;\n        }\n        (_, Ordering::Equal) => {\n            *left = mid;\n            return true;\n        }\n    }\n\n    false\n}\n\n/// Determines if the given array is sorted in ascending order.\n///\n/// This helper function checks if the first element of the array is less than the\n/// last element, indicating an ascending order. It returns `false` if the array\n/// has fewer than two elements.\n///\n/// # Parameters\n///\n/// - `arr`: A slice of the array to check.\n///\n/// # Returns\n///\n/// A `bool` indicating whether the array is sorted in ascending order.\nfn is_asc_arr<T: Ord>(arr: &[T]) -> bool {\n    arr.len() > 1 && arr[0] < arr[arr.len() - 1]\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_cases {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (item, arr, expected) = $test_case;\n                    assert_eq!(binary_search(&item, arr), expected);\n                }\n            )*\n        };\n    }\n\n    test_cases! {\n        empty: (\"a\", &[] as &[&str], None),\n        one_item_found: (\"a\", &[\"a\"], Some(0)),\n        one_item_not_found: (\"b\", &[\"a\"], None),\n        search_strings_asc_start: (\"a\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], Some(0)),\n        search_strings_asc_middle: (\"google\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], Some(4)),\n        search_strings_asc_last: (\"zoo\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], Some(5)),\n        search_strings_asc_not_found: (\"x\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], None),\n        search_strings_desc_start: (\"zoo\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], Some(0)),\n        search_strings_desc_middle: (\"google\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], Some(1)),\n        search_strings_desc_last: (\"a\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], Some(5)),\n        search_strings_desc_not_found: (\"x\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], None),\n        search_ints_asc_start: (1, &[1, 2, 3, 4], Some(0)),\n        search_ints_asc_middle: (3, &[1, 2, 3, 4], Some(2)),\n        search_ints_asc_end: (4, &[1, 2, 3, 4], Some(3)),\n        search_ints_asc_not_found: (5, &[1, 2, 3, 4], None),\n        search_ints_desc_start: (4, &[4, 3, 2, 1], Some(0)),\n        search_ints_desc_middle: (3, &[4, 3, 2, 1], Some(1)),\n        search_ints_desc_end: (1, &[4, 3, 2, 1], Some(3)),\n        search_ints_desc_not_found: (5, &[4, 3, 2, 1], None),\n        with_gaps_0: (0, &[1, 3, 8, 11], None),\n        with_gaps_1: (1, &[1, 3, 8, 11], Some(0)),\n        with_gaps_2: (2, &[1, 3, 8, 11], None),\n        with_gaps_3: (3, &[1, 3, 8, 11], Some(1)),\n        with_gaps_4: (4, &[1, 3, 8, 10], None),\n        with_gaps_5: (5, &[1, 3, 8, 10], None),\n        with_gaps_6: (6, &[1, 3, 8, 10], None),\n        with_gaps_7: (7, &[1, 3, 8, 11], None),\n        with_gaps_8: (8, &[1, 3, 8, 11], Some(2)),\n        with_gaps_9: (9, &[1, 3, 8, 11], None),\n        with_gaps_10: (10, &[1, 3, 8, 11], None),\n        with_gaps_11: (11, &[1, 3, 8, 11], Some(3)),\n        with_gaps_12: (12, &[1, 3, 8, 11], None),\n        with_gaps_13: (13, &[1, 3, 8, 11], None),\n    }\n}\n"
  },
  {
    "path": "src/searching/binary_search_recursive.rs",
    "content": "use std::cmp::Ordering;\n\n/// Recursively performs a binary search for a specified item within a sorted array.\n///\n/// This function can handle both ascending and descending ordered arrays. It\n/// takes a reference to the item to search for and a slice of the array. If\n/// the item is found, it returns the index of the item within the array. If\n/// the item is not found, it returns `None`.\n///\n/// # Parameters\n///\n/// - `item`: A reference to the item to search for.\n/// - `arr`: A slice of the sorted array in which to search.\n/// - `left`: The left bound of the current search range.\n/// - `right`: The right bound of the current search range.\n/// - `is_asc`: A boolean indicating whether the array is sorted in ascending order.\n///\n/// # Returns\n///\n/// An `Option<usize>` which is:\n/// - `Some(index)` if the item is found at the given index.\n/// - `None` if the item is not found in the array.\npub fn binary_search_rec<T: Ord>(item: &T, arr: &[T], left: usize, right: usize) -> Option<usize> {\n    if left >= right {\n        return None;\n    }\n\n    let is_asc = arr.len() > 1 && arr[0] < arr[arr.len() - 1];\n    let mid = left + (right - left) / 2;\n    let cmp_result = item.cmp(&arr[mid]);\n\n    match (is_asc, cmp_result) {\n        (true, Ordering::Less) | (false, Ordering::Greater) => {\n            binary_search_rec(item, arr, left, mid)\n        }\n        (true, Ordering::Greater) | (false, Ordering::Less) => {\n            binary_search_rec(item, arr, mid + 1, right)\n        }\n        (_, Ordering::Equal) => Some(mid),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_cases {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (item, arr, expected) = $test_case;\n                    assert_eq!(binary_search_rec(&item, arr, 0, arr.len()), expected);\n                }\n            )*\n        };\n    }\n\n    test_cases! {\n        empty: (\"a\", &[] as &[&str], None),\n        one_item_found: (\"a\", &[\"a\"], Some(0)),\n        one_item_not_found: (\"b\", &[\"a\"], None),\n        search_strings_asc_start: (\"a\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], Some(0)),\n        search_strings_asc_middle: (\"google\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], Some(4)),\n        search_strings_asc_last: (\"zoo\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], Some(5)),\n        search_strings_asc_not_found: (\"x\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], None),\n        search_strings_desc_start: (\"zoo\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], Some(0)),\n        search_strings_desc_middle: (\"google\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], Some(1)),\n        search_strings_desc_last: (\"a\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], Some(5)),\n        search_strings_desc_not_found: (\"x\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], None),\n        search_ints_asc_start: (1, &[1, 2, 3, 4], Some(0)),\n        search_ints_asc_middle: (3, &[1, 2, 3, 4], Some(2)),\n        search_ints_asc_end: (4, &[1, 2, 3, 4], Some(3)),\n        search_ints_asc_not_found: (5, &[1, 2, 3, 4], None),\n        search_ints_desc_start: (4, &[4, 3, 2, 1], Some(0)),\n        search_ints_desc_middle: (3, &[4, 3, 2, 1], Some(1)),\n        search_ints_desc_end: (1, &[4, 3, 2, 1], Some(3)),\n        search_ints_desc_not_found: (5, &[4, 3, 2, 1], None),\n        with_gaps_0: (0, &[1, 3, 8, 11], None),\n        with_gaps_1: (1, &[1, 3, 8, 11], Some(0)),\n        with_gaps_2: (2, &[1, 3, 8, 11], None),\n        with_gaps_3: (3, &[1, 3, 8, 11], Some(1)),\n        with_gaps_4: (4, &[1, 3, 8, 10], None),\n        with_gaps_5: (5, &[1, 3, 8, 10], None),\n        with_gaps_6: (6, &[1, 3, 8, 10], None),\n        with_gaps_7: (7, &[1, 3, 8, 11], None),\n        with_gaps_8: (8, &[1, 3, 8, 11], Some(2)),\n        with_gaps_9: (9, &[1, 3, 8, 11], None),\n        with_gaps_10: (10, &[1, 3, 8, 11], None),\n        with_gaps_11: (11, &[1, 3, 8, 11], Some(3)),\n        with_gaps_12: (12, &[1, 3, 8, 11], None),\n        with_gaps_13: (13, &[1, 3, 8, 11], None),\n    }\n}\n"
  },
  {
    "path": "src/searching/exponential_search.rs",
    "content": "use std::cmp::Ordering;\n\npub fn exponential_search<T: Ord>(item: &T, arr: &[T]) -> Option<usize> {\n    let len = arr.len();\n    if len == 0 {\n        return None;\n    }\n    let mut upper = 1;\n    while (upper < len) && (&arr[upper] <= item) {\n        upper *= 2;\n    }\n    if upper > len {\n        upper = len\n    }\n\n    // binary search\n    let mut lower = upper / 2;\n    while lower < upper {\n        let mid = lower + (upper - lower) / 2;\n\n        match item.cmp(&arr[mid]) {\n            Ordering::Less => upper = mid,\n            Ordering::Equal => return Some(mid),\n            Ordering::Greater => lower = mid + 1,\n        }\n    }\n    None\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn empty() {\n        let index = exponential_search(&\"a\", &[]);\n        assert_eq!(index, None);\n    }\n\n    #[test]\n    fn one_item() {\n        let index = exponential_search(&\"a\", &[\"a\"]);\n        assert_eq!(index, Some(0));\n    }\n\n    #[test]\n    fn search_strings() {\n        let index = exponential_search(&\"a\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"]);\n        assert_eq!(index, Some(0));\n    }\n\n    #[test]\n    fn search_ints() {\n        let index = exponential_search(&4, &[1, 2, 3, 4]);\n        assert_eq!(index, Some(3));\n\n        let index = exponential_search(&3, &[1, 2, 3, 4]);\n        assert_eq!(index, Some(2));\n\n        let index = exponential_search(&2, &[1, 2, 3, 4]);\n        assert_eq!(index, Some(1));\n\n        let index = exponential_search(&1, &[1, 2, 3, 4]);\n        assert_eq!(index, Some(0));\n    }\n\n    #[test]\n    fn not_found() {\n        let index = exponential_search(&5, &[1, 2, 3, 4]);\n        assert_eq!(index, None);\n    }\n}\n"
  },
  {
    "path": "src/searching/fibonacci_search.rs",
    "content": "use std::cmp::min;\nuse std::cmp::Ordering;\n\npub fn fibonacci_search<T: Ord>(item: &T, arr: &[T]) -> Option<usize> {\n    let len = arr.len();\n    if len == 0 {\n        return None;\n    }\n    let mut start = -1;\n\n    let mut f0 = 0;\n    let mut f1 = 1;\n    let mut f2 = 1;\n    while f2 < len {\n        f0 = f1;\n        f1 = f2;\n        f2 = f0 + f1;\n    }\n    while f2 > 1 {\n        let index = min((f0 as isize + start) as usize, len - 1);\n        match item.cmp(&arr[index]) {\n            Ordering::Less => {\n                f2 = f0;\n                f1 -= f0;\n                f0 = f2 - f1;\n            }\n            Ordering::Equal => return Some(index),\n            Ordering::Greater => {\n                f2 = f1;\n                f1 = f0;\n                f0 = f2 - f1;\n                start = index as isize;\n            }\n        }\n    }\n    if (f1 != 0) && (&arr[len - 1] == item) {\n        return Some(len - 1);\n    }\n    None\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn empty() {\n        let index = fibonacci_search(&\"a\", &[]);\n        assert_eq!(index, None);\n    }\n\n    #[test]\n    fn one_item() {\n        let index = fibonacci_search(&\"a\", &[\"a\"]);\n        assert_eq!(index, Some(0));\n    }\n\n    #[test]\n    fn search_strings() {\n        let index = fibonacci_search(&\"a\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"]);\n        assert_eq!(index, Some(0));\n    }\n\n    #[test]\n    fn search_ints() {\n        let index = fibonacci_search(&4, &[1, 2, 3, 4]);\n        assert_eq!(index, Some(3));\n\n        let index = fibonacci_search(&3, &[1, 2, 3, 4]);\n        assert_eq!(index, Some(2));\n\n        let index = fibonacci_search(&2, &[1, 2, 3, 4]);\n        assert_eq!(index, Some(1));\n\n        let index = fibonacci_search(&1, &[1, 2, 3, 4]);\n        assert_eq!(index, Some(0));\n    }\n\n    #[test]\n    fn not_found() {\n        let index = fibonacci_search(&5, &[1, 2, 3, 4]);\n        assert_eq!(index, None);\n    }\n}\n"
  },
  {
    "path": "src/searching/interpolation_search.rs",
    "content": "pub fn interpolation_search<Ordering>(nums: &[i32], item: &i32) -> Result<usize, usize> {\n    // early check\n    if nums.is_empty() {\n        return Err(0);\n    }\n    let mut low: usize = 0;\n    let mut high: usize = nums.len() - 1;\n    while low <= high {\n        if *item < nums[low] || *item > nums[high] {\n            break;\n        }\n        let offset: usize = low\n            + (((high - low) / (nums[high] - nums[low]) as usize) * (*item - nums[low]) as usize);\n        match nums[offset].cmp(item) {\n            std::cmp::Ordering::Equal => return Ok(offset),\n            std::cmp::Ordering::Less => low = offset + 1,\n            std::cmp::Ordering::Greater => high = offset - 1,\n        }\n    }\n    Err(0)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::cmp::Ordering;\n\n    #[test]\n    fn returns_err_if_empty_slice() {\n        let nums = [];\n        assert_eq!(interpolation_search::<Ordering>(&nums, &3), Err(0));\n    }\n\n    #[test]\n    fn returns_err_if_target_not_found() {\n        let nums = [1, 2, 3, 4, 5, 6];\n        assert_eq!(interpolation_search::<Ordering>(&nums, &10), Err(0));\n    }\n\n    #[test]\n    fn returns_first_index() {\n        let index: Result<usize, usize> = interpolation_search::<Ordering>(&[1, 2, 3, 4, 5], &1);\n        assert_eq!(index, Ok(0));\n    }\n\n    #[test]\n    fn returns_last_index() {\n        let index: Result<usize, usize> = interpolation_search::<Ordering>(&[1, 2, 3, 4, 5], &5);\n        assert_eq!(index, Ok(4));\n    }\n\n    #[test]\n    fn returns_middle_index() {\n        let index: Result<usize, usize> = interpolation_search::<Ordering>(&[1, 2, 3, 4, 5], &3);\n        assert_eq!(index, Ok(2));\n    }\n}\n"
  },
  {
    "path": "src/searching/jump_search.rs",
    "content": "use std::cmp::min;\n\npub fn jump_search<T: Ord>(item: &T, arr: &[T]) -> Option<usize> {\n    let len = arr.len();\n    if len == 0 {\n        return None;\n    }\n    let mut step = (len as f64).sqrt() as usize;\n    let mut prev = 0;\n\n    while &arr[min(len, step) - 1] < item {\n        prev = step;\n        step += (len as f64).sqrt() as usize;\n        if prev >= len {\n            return None;\n        }\n    }\n    while &arr[prev] < item {\n        prev += 1;\n    }\n    if &arr[prev] == item {\n        return Some(prev);\n    }\n    None\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn empty() {\n        assert!(jump_search(&\"a\", &[]).is_none());\n    }\n\n    #[test]\n    fn one_item() {\n        assert_eq!(jump_search(&\"a\", &[\"a\"]).unwrap(), 0);\n    }\n\n    #[test]\n    fn search_strings() {\n        assert_eq!(\n            jump_search(&\"a\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"]).unwrap(),\n            0\n        );\n    }\n\n    #[test]\n    fn search_ints() {\n        let arr = [1, 2, 3, 4];\n        assert_eq!(jump_search(&4, &arr).unwrap(), 3);\n        assert_eq!(jump_search(&3, &arr).unwrap(), 2);\n        assert_eq!(jump_search(&2, &arr).unwrap(), 1);\n        assert_eq!(jump_search(&1, &arr).unwrap(), 0);\n    }\n\n    #[test]\n    fn not_found() {\n        let arr = [1, 2, 3, 4];\n\n        assert!(jump_search(&5, &arr).is_none());\n        assert!(jump_search(&0, &arr).is_none());\n    }\n}\n"
  },
  {
    "path": "src/searching/kth_smallest.rs",
    "content": "use crate::sorting::partition;\nuse std::cmp::{Ordering, PartialOrd};\n\n/// Returns k-th smallest element of an array, i.e. its order statistics.\n/// Time complexity is O(n^2) in the worst case, but only O(n) on average.\n/// It mutates the input, and therefore does not require additional space.\npub fn kth_smallest<T>(input: &mut [T], k: usize) -> Option<T>\nwhere\n    T: PartialOrd + Copy,\n{\n    if input.is_empty() {\n        return None;\n    }\n\n    let kth = _kth_smallest(input, k, 0, input.len() - 1);\n    Some(kth)\n}\n\nfn _kth_smallest<T>(input: &mut [T], k: usize, lo: usize, hi: usize) -> T\nwhere\n    T: PartialOrd + Copy,\n{\n    if lo == hi {\n        return input[lo];\n    }\n\n    let pivot = partition(input, lo, hi);\n    let i = pivot - lo + 1;\n\n    match k.cmp(&i) {\n        Ordering::Equal => input[pivot],\n        Ordering::Less => _kth_smallest(input, k, lo, pivot - 1),\n        Ordering::Greater => _kth_smallest(input, k - i, pivot + 1, hi),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn empty() {\n        let mut zero: [u8; 0] = [];\n        let first = kth_smallest(&mut zero, 1);\n\n        assert_eq!(None, first);\n    }\n\n    #[test]\n    fn one_element() {\n        let mut one = [1];\n        let first = kth_smallest(&mut one, 1);\n\n        assert_eq!(1, first.unwrap());\n    }\n\n    #[test]\n    fn many_elements() {\n        // 0 1 3 4 5 7 8 9 9 10 12 13 16 17\n        let mut many = [9, 17, 3, 16, 13, 10, 1, 5, 7, 12, 4, 8, 9, 0];\n\n        let first = kth_smallest(&mut many, 1);\n        let third = kth_smallest(&mut many, 3);\n        let sixth = kth_smallest(&mut many, 6);\n        let fourteenth = kth_smallest(&mut many, 14);\n\n        assert_eq!(0, first.unwrap());\n        assert_eq!(3, third.unwrap());\n        assert_eq!(7, sixth.unwrap());\n        assert_eq!(17, fourteenth.unwrap());\n    }\n}\n"
  },
  {
    "path": "src/searching/kth_smallest_heap.rs",
    "content": "use crate::data_structures::Heap;\nuse std::cmp::{Ord, Ordering};\n\n/// Returns k-th smallest element of an array.\n/// Time complexity is stably O(nlog(k)) in all cases\n/// Extra space is required to maintain the heap, and it doesn't\n/// mutate the input list.\n///\n/// It is preferrable to the partition-based algorithm in cases when\n/// we want to maintain the kth smallest element dynamically against\n/// a stream of elements. In that case, once the heap is built, further\n/// operation's complexity is O(log(k)).\npub fn kth_smallest_heap<T>(input: &[T], k: usize) -> Option<T>\nwhere\n    T: Ord + Copy,\n{\n    if input.len() < k {\n        return None;\n    }\n\n    // heap will maintain the kth smallest elements\n    // seen so far, when new elements, E_new arrives,\n    // it is compared with the largest element of the\n    // current Heap E_large, which is the current kth\n    // smallest elements.\n    // if E_new > E_large, then E_new cannot be the kth\n    // smallest because there are already k elements smaller\n    // than it\n    // otherwise, E_large cannot be the kth smallest, and should\n    // be removed from the heap and E_new should be added\n    let mut heap = Heap::new_max();\n\n    // first k elements goes to the heap as the baseline\n    for &val in input.iter().take(k) {\n        heap.add(val);\n    }\n\n    for &val in input.iter().skip(k) {\n        // compare new value to the current kth smallest value\n        let cur_big = heap.pop().unwrap(); // heap.pop() can't be None\n        match val.cmp(&cur_big) {\n            Ordering::Greater => {\n                heap.add(cur_big);\n            }\n            _ => {\n                heap.add(val);\n            }\n        }\n    }\n\n    heap.pop()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn empty() {\n        let zero: [u8; 0] = [];\n        let first = kth_smallest_heap(&zero, 1);\n\n        assert_eq!(None, first);\n    }\n\n    #[test]\n    fn one_element() {\n        let one = [1];\n        let first = kth_smallest_heap(&one, 1);\n\n        assert_eq!(1, first.unwrap());\n    }\n\n    #[test]\n    fn many_elements() {\n        // 0 1 3 4 5 7 8 9 9 10 12 13 16 17\n        let many = [9, 17, 3, 16, 13, 10, 1, 5, 7, 12, 4, 8, 9, 0];\n\n        let first = kth_smallest_heap(&many, 1);\n        let third = kth_smallest_heap(&many, 3);\n        let sixth = kth_smallest_heap(&many, 6);\n        let fourteenth = kth_smallest_heap(&many, 14);\n\n        assert_eq!(0, first.unwrap());\n        assert_eq!(3, third.unwrap());\n        assert_eq!(7, sixth.unwrap());\n        assert_eq!(17, fourteenth.unwrap());\n    }\n}\n"
  },
  {
    "path": "src/searching/linear_search.rs",
    "content": "/// Performs a linear search on the given array, returning the index of the first occurrence of the item.\n///\n/// # Arguments\n///\n/// * `item` - A reference to the item to search for in the array.\n/// * `arr` - A slice of items to search within.\n///\n/// # Returns\n///\n/// * `Some(usize)` - The index of the first occurrence of the item, if found.\n/// * `None` - If the item is not found in the array.\npub fn linear_search<T: Ord>(item: &T, arr: &[T]) -> Option<usize> {\n    for (i, data) in arr.iter().enumerate() {\n        if item == data {\n            return Some(i);\n        }\n    }\n\n    None\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_cases {\n        ($($name:ident: $tc:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (item, arr, expected) = $tc;\n                    if let Some(expected_index) = expected {\n                        assert_eq!(arr[expected_index], item);\n                    }\n                    assert_eq!(linear_search(&item, arr), expected);\n                }\n            )*\n        }\n    }\n\n    test_cases! {\n        empty: (\"a\", &[] as &[&str], None),\n        one_item_found: (\"a\", &[\"a\"], Some(0)),\n        one_item_not_found: (\"b\", &[\"a\"], None),\n        search_strings_asc_start: (\"a\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], Some(0)),\n        search_strings_asc_middle: (\"google\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], Some(4)),\n        search_strings_asc_last: (\"zoo\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], Some(5)),\n        search_strings_asc_not_found: (\"x\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], None),\n        search_strings_desc_start: (\"zoo\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], Some(0)),\n        search_strings_desc_middle: (\"google\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], Some(1)),\n        search_strings_desc_last: (\"a\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], Some(5)),\n        search_strings_desc_not_found: (\"x\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], None),\n        search_ints_asc_start: (1, &[1, 2, 3, 4], Some(0)),\n        search_ints_asc_middle: (3, &[1, 2, 3, 4], Some(2)),\n        search_ints_asc_end: (4, &[1, 2, 3, 4], Some(3)),\n        search_ints_asc_not_found: (5, &[1, 2, 3, 4], None),\n        search_ints_desc_start: (4, &[4, 3, 2, 1], Some(0)),\n        search_ints_desc_middle: (3, &[4, 3, 2, 1], Some(1)),\n        search_ints_desc_end: (1, &[4, 3, 2, 1], Some(3)),\n        search_ints_desc_not_found: (5, &[4, 3, 2, 1], None),\n        with_gaps_0: (0, &[1, 3, 8, 11], None),\n        with_gaps_1: (1, &[1, 3, 8, 11], Some(0)),\n        with_gaps_2: (2, &[1, 3, 8, 11], None),\n        with_gaps_3: (3, &[1, 3, 8, 11], Some(1)),\n        with_gaps_4: (4, &[1, 3, 8, 10], None),\n        with_gaps_5: (5, &[1, 3, 8, 10], None),\n        with_gaps_6: (6, &[1, 3, 8, 10], None),\n        with_gaps_7: (7, &[1, 3, 8, 11], None),\n        with_gaps_8: (8, &[1, 3, 8, 11], Some(2)),\n        with_gaps_9: (9, &[1, 3, 8, 11], None),\n        with_gaps_10: (10, &[1, 3, 8, 11], None),\n        with_gaps_11: (11, &[1, 3, 8, 11], Some(3)),\n        with_gaps_12: (12, &[1, 3, 8, 11], None),\n        with_gaps_13: (13, &[1, 3, 8, 11], None),\n    }\n}\n"
  },
  {
    "path": "src/searching/mod.rs",
    "content": "mod binary_search;\nmod binary_search_recursive;\nmod exponential_search;\nmod fibonacci_search;\nmod interpolation_search;\nmod jump_search;\nmod kth_smallest;\nmod kth_smallest_heap;\nmod linear_search;\nmod moore_voting;\nmod quick_select;\nmod saddleback_search;\nmod ternary_search;\nmod ternary_search_min_max;\nmod ternary_search_min_max_recursive;\nmod ternary_search_recursive;\n\npub use self::binary_search::binary_search;\npub use self::binary_search_recursive::binary_search_rec;\npub use self::exponential_search::exponential_search;\npub use self::fibonacci_search::fibonacci_search;\npub use self::interpolation_search::interpolation_search;\npub use self::jump_search::jump_search;\npub use self::kth_smallest::kth_smallest;\npub use self::kth_smallest_heap::kth_smallest_heap;\npub use self::linear_search::linear_search;\npub use self::moore_voting::moore_voting;\npub use self::quick_select::quick_select;\npub use self::saddleback_search::saddleback_search;\npub use self::ternary_search::ternary_search;\npub use self::ternary_search_min_max::ternary_search_max;\npub use self::ternary_search_min_max::ternary_search_min;\npub use self::ternary_search_min_max_recursive::ternary_search_max_rec;\npub use self::ternary_search_min_max_recursive::ternary_search_min_rec;\npub use self::ternary_search_recursive::ternary_search_rec;\n"
  },
  {
    "path": "src/searching/moore_voting.rs",
    "content": "/*\n\n    Moore's voting algorithm finds out the strictly majority-occurring element\n    without using extra space\n    and O(n) + O(n) time complexity\n\n    It is built on the intuition that a strictly major element will always have a net occurrence as 1.\n    Say, array given: 9 1 8 1 1\n    Here, the algorithm will work as:\n\n    (for finding element present >(n/2) times)\n    (assumed: all elements are >0)\n\n    Initialisation: ele=0, cnt=0\n    Loop beings.\n\n    loop 1: arr[0]=9\n    ele = 9\n    cnt=1 (since cnt = 0, cnt increments to 1 and ele = 9)\n\n    loop 2: arr[1]=1\n    ele = 9\n    cnt= 0 (since in this turn of the loop, the array[i] != ele, cnt decrements by 1)\n\n    loop 3: arr[2]=8\n    ele = 8\n    cnt=1 (since cnt = 0, cnt increments to 1 and ele = 8)\n\n    loop 4: arr[3]=1\n    ele = 8\n    cnt= 0 (since in this turn of the loop, the array[i] != ele, cnt decrements by 1)\n\n    loop 5: arr[4]=1\n    ele = 9\n    cnt=1 (since cnt = 0, cnt increments to 1 and ele = 1)\n\n    Now, this ele should be the majority element if there's any\n    To check, a quick O(n) loop is run to check if the count of ele is >(n/2), n being the length of the array\n\n    -1 is returned when no such element is found.\n\n*/\n\npub fn moore_voting(arr: &[i32]) -> i32 {\n    let n = arr.len();\n    let mut cnt = 0; // initializing cnt\n    let mut ele = 0; // initializing ele\n\n    for &item in arr.iter() {\n        if cnt == 0 {\n            cnt = 1;\n            ele = item;\n        } else if item == ele {\n            cnt += 1;\n        } else {\n            cnt -= 1;\n        }\n    }\n\n    let cnt_check = arr.iter().filter(|&&x| x == ele).count();\n\n    if cnt_check > (n / 2) {\n        ele\n    } else {\n        -1\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_moore_voting() {\n        let arr1: Vec<i32> = vec![9, 1, 8, 1, 1];\n        assert!(moore_voting(&arr1) == 1);\n        let arr2: Vec<i32> = vec![1, 2, 3, 4];\n        assert!(moore_voting(&arr2) == -1);\n    }\n}\n"
  },
  {
    "path": "src/searching/quick_select.rs",
    "content": "// https://en.wikipedia.org/wiki/Quickselect\n\nfn partition(list: &mut [i32], left: usize, right: usize, pivot_index: usize) -> usize {\n    let pivot_value = list[pivot_index];\n    list.swap(pivot_index, right); // Move pivot to end\n    let mut store_index = left;\n    for i in left..right {\n        if list[i] < pivot_value {\n            list.swap(store_index, i);\n            store_index += 1;\n        }\n    }\n    list.swap(right, store_index); // Move pivot to its final place\n    store_index\n}\n\npub fn quick_select(list: &mut [i32], left: usize, right: usize, index: usize) -> i32 {\n    if left == right {\n        // If the list contains only one element,\n        return list[left];\n    } // return that element\n    let mut pivot_index = left + (right - left) / 2; // select a pivotIndex between left and right\n    pivot_index = partition(list, left, right, pivot_index);\n    // The pivot is in its final sorted position\n    match index {\n        x if x == pivot_index => list[index],\n        x if x < pivot_index => quick_select(list, left, pivot_index - 1, index),\n        _ => quick_select(list, pivot_index + 1, right, index),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn it_works() {\n        let mut arr1 = [2, 3, 4, 5];\n        assert_eq!(quick_select(&mut arr1, 0, 3, 1), 3);\n        let mut arr2 = [2, 5, 9, 12, 16];\n        assert_eq!(quick_select(&mut arr2, 1, 3, 2), 9);\n        let mut arr2 = [0, 3, 8];\n        assert_eq!(quick_select(&mut arr2, 0, 0, 0), 0);\n    }\n}\n"
  },
  {
    "path": "src/searching/saddleback_search.rs",
    "content": "// Saddleback search is a technique used to find an element in a sorted 2D matrix in O(m + n) time,\n// where m is the number of rows, and n is the number of columns. It works by starting from the\n// top-right corner of the matrix and moving left or down based on the comparison of the current\n// element with the target element.\nuse std::cmp::Ordering;\n\npub fn saddleback_search(matrix: &[Vec<i32>], element: i32) -> (usize, usize) {\n    // Initialize left and right indices\n    let mut left_index = 0;\n    let mut right_index = matrix[0].len() - 1;\n\n    // Start searching\n    while left_index < matrix.len() {\n        match element.cmp(&matrix[left_index][right_index]) {\n            // If the current element matches the target element, return its position (indices are 1-based)\n            Ordering::Equal => return (left_index + 1, right_index + 1),\n            Ordering::Greater => {\n                // If the target element is greater, move to the next row (downwards)\n                left_index += 1;\n            }\n            Ordering::Less => {\n                // If the target element is smaller, move to the previous column (leftwards)\n                if right_index == 0 {\n                    break; // If we reach the left-most column, exit the loop\n                }\n                right_index -= 1;\n            }\n        }\n    }\n\n    // If the element is not found, return (0, 0)\n    (0, 0)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    // Test when the element is not present in the matrix\n    #[test]\n    fn test_element_not_found() {\n        let matrix = vec![vec![1, 10, 100], vec![2, 20, 200], vec![3, 30, 300]];\n        assert_eq!(saddleback_search(&matrix, 123), (0, 0));\n    }\n\n    // Test when the element is at the top-left corner of the matrix\n    #[test]\n    fn test_element_at_top_left() {\n        let matrix = vec![vec![1, 10, 100], vec![2, 20, 200], vec![3, 30, 300]];\n        assert_eq!(saddleback_search(&matrix, 1), (1, 1));\n    }\n\n    // Test when the element is at the bottom-right corner of the matrix\n    #[test]\n    fn test_element_at_bottom_right() {\n        let matrix = vec![vec![1, 10, 100], vec![2, 20, 200], vec![3, 30, 300]];\n        assert_eq!(saddleback_search(&matrix, 300), (3, 3));\n    }\n\n    // Test when the element is at the top-right corner of the matrix\n    #[test]\n    fn test_element_at_top_right() {\n        let matrix = vec![vec![1, 10, 100], vec![2, 20, 200], vec![3, 30, 300]];\n        assert_eq!(saddleback_search(&matrix, 100), (1, 3));\n    }\n\n    // Test when the element is at the bottom-left corner of the matrix\n    #[test]\n    fn test_element_at_bottom_left() {\n        let matrix = vec![vec![1, 10, 100], vec![2, 20, 200], vec![3, 30, 300]];\n        assert_eq!(saddleback_search(&matrix, 3), (3, 1));\n    }\n\n    // Additional test case: Element in the middle of the matrix\n    #[test]\n    fn test_element_in_middle() {\n        let matrix = vec![\n            vec![1, 10, 100, 1000],\n            vec![2, 20, 200, 2000],\n            vec![3, 30, 300, 3000],\n        ];\n        assert_eq!(saddleback_search(&matrix, 200), (2, 3));\n    }\n}\n"
  },
  {
    "path": "src/searching/ternary_search.rs",
    "content": "//! This module provides an implementation of a ternary search algorithm that\n//! works for both ascending and descending ordered arrays. The ternary search\n//! function returns the index of the target element if it is found, or `None`\n//! if the target is not present in the array.\n\nuse std::cmp::Ordering;\n\n/// Performs a ternary search for a specified item within a sorted array.\n///\n/// This function can handle both ascending and descending ordered arrays. It\n/// takes a reference to the item to search for and a slice of the array. If\n/// the item is found, it returns the index of the item within the array. If\n/// the item is not found, it returns `None`.\n///\n/// # Parameters\n///\n/// - `item`: A reference to the item to search for.\n/// - `arr`: A slice of the sorted array in which to search.\n///\n/// # Returns\n///\n/// An `Option<usize>` which is:\n/// - `Some(index)` if the item is found at the given index.\n/// - `None` if the item is not found in the array.\npub fn ternary_search<T: Ord>(item: &T, arr: &[T]) -> Option<usize> {\n    if arr.is_empty() {\n        return None;\n    }\n\n    let is_asc = is_asc_arr(arr);\n    let mut left = 0;\n    let mut right = arr.len() - 1;\n\n    while left <= right {\n        if match_compare(item, arr, &mut left, &mut right, is_asc) {\n            return Some(left);\n        }\n    }\n\n    None\n}\n\n/// Compares the item with two middle elements of the current search range and\n/// updates the search bounds accordingly. This function handles both ascending\n/// and descending ordered arrays. It calculates two middle indices of the\n/// current search range and compares the item with the elements at these\n/// indices. It then updates the search bounds (`left` and `right`) based on\n/// the result of these comparisons. If the item is found, it returns `true`.\n///\n/// # Parameters\n///\n/// - `item`: A reference to the item to search for.\n/// - `arr`: A slice of the array in which to search.\n/// - `left`: A mutable reference to the left bound of the search range.\n/// - `right`: A mutable reference to the right bound of the search range.\n/// - `is_asc`: A boolean indicating whether the array is sorted in ascending order.\n///\n/// # Returns\n///\n/// A `bool` indicating:\n/// - `true` if the item was found in the array.\n/// - `false` if the item was not found in the array.\nfn match_compare<T: Ord>(\n    item: &T,\n    arr: &[T],\n    left: &mut usize,\n    right: &mut usize,\n    is_asc: bool,\n) -> bool {\n    let first_mid = *left + (*right - *left) / 3;\n    let second_mid = *right - (*right - *left) / 3;\n\n    // Handling the edge case where the search narrows down to a single element\n    if first_mid == second_mid && first_mid == *left {\n        return match &arr[*left] {\n            x if x == item => true,\n            _ => {\n                *left += 1;\n                false\n            }\n        };\n    }\n\n    let cmp_first_mid = item.cmp(&arr[first_mid]);\n    let cmp_second_mid = item.cmp(&arr[second_mid]);\n\n    match (is_asc, cmp_first_mid, cmp_second_mid) {\n        // If the item matches either midpoint, it returns the index\n        (_, Ordering::Equal, _) => {\n            *left = first_mid;\n            return true;\n        }\n        (_, _, Ordering::Equal) => {\n            *left = second_mid;\n            return true;\n        }\n        // If the item is smaller than the element at first_mid (in ascending order)\n        // or greater than it (in descending order), it narrows the search to the first third.\n        (true, Ordering::Less, _) | (false, Ordering::Greater, _) => {\n            *right = first_mid.saturating_sub(1)\n        }\n        // If the item is greater than the element at second_mid (in ascending order)\n        // or smaller than it (in descending order), it narrows the search to the last third.\n        (true, _, Ordering::Greater) | (false, _, Ordering::Less) => *left = second_mid + 1,\n        // Otherwise, it searches the middle third.\n        (_, _, _) => {\n            *left = first_mid + 1;\n            *right = second_mid - 1;\n        }\n    }\n\n    false\n}\n\n/// Determines if the given array is sorted in ascending order.\n///\n/// This helper function checks if the first element of the array is less than the\n/// last element, indicating an ascending order. It returns `false` if the array\n/// has fewer than two elements.\n///\n/// # Parameters\n///\n/// - `arr`: A slice of the array to check.\n///\n/// # Returns\n///\n/// A `bool` indicating whether the array is sorted in ascending order.\nfn is_asc_arr<T: Ord>(arr: &[T]) -> bool {\n    arr.len() > 1 && arr[0] < arr[arr.len() - 1]\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_cases {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (item, arr, expected) = $test_case;\n                    if let Some(expected_index) = expected {\n                        assert_eq!(arr[expected_index], item);\n                    }\n                    assert_eq!(ternary_search(&item, arr), expected);\n                }\n            )*\n        };\n    }\n\n    test_cases! {\n        empty: (\"a\", &[] as &[&str], None),\n        one_item_found: (\"a\", &[\"a\"], Some(0)),\n        one_item_not_found: (\"b\", &[\"a\"], None),\n        search_two_elements_found_at_start: (1, &[1, 2], Some(0)),\n        search_two_elements_found_at_end: (2, &[1, 2], Some(1)),\n        search_two_elements_not_found_start: (0, &[1, 2], None),\n        search_two_elements_not_found_end: (3, &[1, 2], None),\n        search_three_elements_found_start: (1, &[1, 2, 3], Some(0)),\n        search_three_elements_found_middle: (2, &[1, 2, 3], Some(1)),\n        search_three_elements_found_end: (3, &[1, 2, 3], Some(2)),\n        search_three_elements_not_found_start: (0, &[1, 2, 3], None),\n        search_three_elements_not_found_end: (4, &[1, 2, 3], None),\n        search_strings_asc_start: (\"a\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], Some(0)),\n        search_strings_asc_middle: (\"google\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], Some(4)),\n        search_strings_asc_last: (\"zoo\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], Some(5)),\n        search_strings_asc_not_found: (\"x\", &[\"a\", \"b\", \"c\", \"d\", \"google\", \"zoo\"], None),\n        search_strings_desc_start: (\"zoo\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], Some(0)),\n        search_strings_desc_middle: (\"google\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], Some(1)),\n        search_strings_desc_last: (\"a\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], Some(5)),\n        search_strings_desc_not_found: (\"x\", &[\"zoo\", \"google\", \"d\", \"c\", \"b\", \"a\"], None),\n        search_ints_asc_start: (1, &[1, 2, 3, 4], Some(0)),\n        search_ints_asc_middle: (3, &[1, 2, 3, 4], Some(2)),\n        search_ints_asc_end: (4, &[1, 2, 3, 4], Some(3)),\n        search_ints_asc_not_found: (5, &[1, 2, 3, 4], None),\n        search_ints_desc_start: (4, &[4, 3, 2, 1], Some(0)),\n        search_ints_desc_middle: (3, &[4, 3, 2, 1], Some(1)),\n        search_ints_desc_end: (1, &[4, 3, 2, 1], Some(3)),\n        search_ints_desc_not_found: (5, &[4, 3, 2, 1], None),\n        with_gaps_0: (0, &[1, 3, 8, 11], None),\n        with_gaps_1: (1, &[1, 3, 8, 11], Some(0)),\n        with_gaps_2: (2, &[1, 3, 8, 11], None),\n        with_gaps_3: (3, &[1, 3, 8, 11], Some(1)),\n        with_gaps_4: (4, &[1, 3, 8, 10], None),\n        with_gaps_5: (5, &[1, 3, 8, 10], None),\n        with_gaps_6: (6, &[1, 3, 8, 10], None),\n        with_gaps_7: (7, &[1, 3, 8, 11], None),\n        with_gaps_8: (8, &[1, 3, 8, 11], Some(2)),\n        with_gaps_9: (9, &[1, 3, 8, 11], None),\n        with_gaps_10: (10, &[1, 3, 8, 11], None),\n        with_gaps_11: (11, &[1, 3, 8, 11], Some(3)),\n        with_gaps_12: (12, &[1, 3, 8, 11], None),\n        with_gaps_13: (13, &[1, 3, 8, 11], None),\n    }\n}\n"
  },
  {
    "path": "src/searching/ternary_search_min_max.rs",
    "content": "/// Ternary search algorithm for finding maximum of unimodal function\npub fn ternary_search_max(\n    f: fn(f32) -> f32,\n    mut start: f32,\n    mut end: f32,\n    absolute_precision: f32,\n) -> f32 {\n    while (start - end).abs() >= absolute_precision {\n        let mid1 = start + (end - start) / 3.0;\n        let mid2 = end - (end - start) / 3.0;\n\n        let r1 = f(mid1);\n        let r2 = f(mid2);\n\n        if r1 < r2 {\n            start = mid1;\n        } else if r1 > r2 {\n            end = mid2;\n        } else {\n            start = mid1;\n            end = mid2;\n        }\n    }\n    f(start)\n}\n\n/// Ternary search algorithm for finding minimum of unimodal function\npub fn ternary_search_min(\n    f: fn(f32) -> f32,\n    mut start: f32,\n    mut end: f32,\n    absolute_precision: f32,\n) -> f32 {\n    while (start - end).abs() >= absolute_precision {\n        let mid1 = start + (end - start) / 3.0;\n        let mid2 = end - (end - start) / 3.0;\n\n        let r1 = f(mid1);\n        let r2 = f(mid2);\n\n        if r1 < r2 {\n            end = mid2;\n        } else if r1 > r2 {\n            start = mid1;\n        } else {\n            start = mid1;\n            end = mid2;\n        }\n    }\n    f(start)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn finds_max_value() {\n        let expected = 4.0;\n        let f = |x: f32| -x * x - 2.0 * x + 3.0;\n\n        let start: f32 = -10000000000.0;\n        let end: f32 = 10000000000.0;\n        let absolute_precision = 0.0000001;\n\n        let result = ternary_search_max(f, start, end, absolute_precision);\n\n        assert_eq!(result, expected);\n    }\n\n    #[test]\n    fn finds_min_value() {\n        let expected = 2.0;\n        let f = |x: f32| x * x - 2.0 * x + 3.0;\n\n        let start: f32 = -10000000000.0;\n        let end: f32 = 10000000000.0;\n        let absolute_precision = 0.0000001;\n\n        let result = ternary_search_min(f, start, end, absolute_precision);\n\n        assert_eq!(result, expected);\n    }\n\n    #[test]\n    fn finds_max_value_2() {\n        let expected = 7.25;\n        let f = |x: f32| -x.powi(2) + 3.0 * x + 5.0;\n\n        let start: f32 = -10000000000.0;\n        let end: f32 = 10000000000.0;\n        let absolute_precision = 0.000001;\n\n        let result = ternary_search_max(f, start, end, absolute_precision);\n\n        assert_eq!(result, expected);\n    }\n\n    #[test]\n    fn finds_min_value_2() {\n        let expected = 2.75;\n        let f = |x: f32| x.powi(2) + 3.0 * x + 5.0;\n\n        let start: f32 = -10000000000.0;\n        let end: f32 = 10000000000.0;\n        let absolute_precision = 0.000001;\n\n        let result = ternary_search_min(f, start, end, absolute_precision);\n\n        assert_eq!(result, expected);\n    }\n}\n"
  },
  {
    "path": "src/searching/ternary_search_min_max_recursive.rs",
    "content": "/// Recursive ternary search algorithm for finding maximum of unimodal function\npub fn ternary_search_max_rec(\n    f: fn(f32) -> f32,\n    start: f32,\n    end: f32,\n    absolute_precision: f32,\n) -> f32 {\n    if (end - start).abs() >= absolute_precision {\n        let mid1 = start + (end - start) / 3.0;\n        let mid2 = end - (end - start) / 3.0;\n\n        let r1 = f(mid1);\n        let r2 = f(mid2);\n\n        if r1 < r2 {\n            return ternary_search_max_rec(f, mid1, end, absolute_precision);\n        } else if r1 > r2 {\n            return ternary_search_max_rec(f, start, mid2, absolute_precision);\n        }\n        return ternary_search_max_rec(f, mid1, mid2, absolute_precision);\n    }\n    f(start)\n}\n\n/// Recursive ternary search algorithm for finding minimum of unimodal function\npub fn ternary_search_min_rec(\n    f: fn(f32) -> f32,\n    start: f32,\n    end: f32,\n    absolute_precision: f32,\n) -> f32 {\n    if (end - start).abs() >= absolute_precision {\n        let mid1 = start + (end - start) / 3.0;\n        let mid2 = end - (end - start) / 3.0;\n\n        let r1 = f(mid1);\n        let r2 = f(mid2);\n\n        if r1 < r2 {\n            return ternary_search_min_rec(f, start, mid2, absolute_precision);\n        } else if r1 > r2 {\n            return ternary_search_min_rec(f, mid1, end, absolute_precision);\n        }\n        return ternary_search_min_rec(f, mid1, mid2, absolute_precision);\n    }\n    f(start)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn finds_max_value() {\n        let expected = 4.0;\n        let f = |x: f32| -x * x - 2.0 * x + 3.0;\n\n        let start: f32 = -10000000000.0;\n        let end: f32 = 10000000000.0;\n        let absolute_precision = 0.0000001;\n\n        let result = ternary_search_max_rec(f, start, end, absolute_precision);\n\n        assert_eq!(result, expected);\n    }\n\n    #[test]\n    fn finds_min_value() {\n        let expected = 2.0;\n        let f = |x: f32| x * x - 2.0 * x + 3.0;\n\n        let start: f32 = -10000000000.0;\n        let end: f32 = 10000000000.0;\n        let absolute_precision = 0.0000001;\n\n        let result = ternary_search_min_rec(f, start, end, absolute_precision);\n\n        assert_eq!(result, expected);\n    }\n\n    #[test]\n    fn finds_max_value_2() {\n        let expected = 7.25;\n        let f = |x: f32| -x.powi(2) + 3.0 * x + 5.0;\n\n        let start: f32 = -10000000000.0;\n        let end: f32 = 10000000000.0;\n        let absolute_precision = 0.000001;\n\n        let result = ternary_search_max_rec(f, start, end, absolute_precision);\n\n        assert_eq!(result, expected);\n    }\n\n    #[test]\n    fn finds_min_value_2() {\n        let expected = 2.75;\n        let f = |x: f32| x.powi(2) + 3.0 * x + 5.0;\n\n        let start: f32 = -10000000000.0;\n        let end: f32 = 10000000000.0;\n        let absolute_precision = 0.000001;\n\n        let result = ternary_search_min_rec(f, start, end, absolute_precision);\n\n        assert_eq!(result, expected);\n    }\n}\n"
  },
  {
    "path": "src/searching/ternary_search_recursive.rs",
    "content": "use std::cmp::Ordering;\n\npub fn ternary_search_rec<T: Ord>(\n    target: &T,\n    list: &[T],\n    start: usize,\n    end: usize,\n) -> Option<usize> {\n    if list.is_empty() {\n        return None;\n    }\n\n    if end >= start {\n        let mid1: usize = start + (end - start) / 3;\n        let mid2: usize = end - (end - start) / 3;\n\n        match target.cmp(&list[mid1]) {\n            Ordering::Less => return ternary_search_rec(target, list, start, mid1 - 1),\n            Ordering::Equal => return Some(mid1),\n            Ordering::Greater => match target.cmp(&list[mid2]) {\n                Ordering::Greater => return ternary_search_rec(target, list, mid2 + 1, end),\n                Ordering::Equal => return Some(mid2),\n                Ordering::Less => return ternary_search_rec(target, list, mid1 + 1, mid2 - 1),\n            },\n        }\n    }\n\n    None\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn returns_none_if_empty_list() {\n        let index = ternary_search_rec(&\"a\", &[], 1, 10);\n        assert_eq!(index, None);\n    }\n\n    #[test]\n    fn returns_none_if_range_is_invalid() {\n        let index = ternary_search_rec(&1, &[1, 2, 3], 2, 1);\n        assert_eq!(index, None);\n    }\n\n    #[test]\n    fn returns_index_if_list_has_one_item() {\n        let index = ternary_search_rec(&1, &[1], 0, 1);\n        assert_eq!(index, Some(0));\n    }\n\n    #[test]\n    fn returns_first_index() {\n        let index = ternary_search_rec(&1, &[1, 2, 3], 0, 2);\n        assert_eq!(index, Some(0));\n    }\n\n    #[test]\n    fn returns_first_index_if_end_out_of_bounds() {\n        let index = ternary_search_rec(&1, &[1, 2, 3], 0, 3);\n        assert_eq!(index, Some(0));\n    }\n\n    #[test]\n    fn returns_last_index() {\n        let index = ternary_search_rec(&3, &[1, 2, 3], 0, 2);\n        assert_eq!(index, Some(2));\n    }\n\n    #[test]\n    fn returns_last_index_if_end_out_of_bounds() {\n        let index = ternary_search_rec(&3, &[1, 2, 3], 0, 3);\n        assert_eq!(index, Some(2));\n    }\n\n    #[test]\n    fn returns_middle_index() {\n        let index = ternary_search_rec(&2, &[1, 2, 3], 0, 2);\n        assert_eq!(index, Some(1));\n    }\n\n    #[test]\n    fn returns_middle_index_if_end_out_of_bounds() {\n        let index = ternary_search_rec(&2, &[1, 2, 3], 0, 3);\n        assert_eq!(index, Some(1));\n    }\n}\n"
  },
  {
    "path": "src/signal_analysis/mod.rs",
    "content": "mod yin;\npub use self::yin::{Yin, YinResult};\n"
  },
  {
    "path": "src/signal_analysis/yin.rs",
    "content": "use std::f64;\n\n#[derive(Clone, Debug)]\npub struct YinResult {\n    sample_rate: f64,\n    best_lag: usize,\n    cmndf: Vec<f64>,\n}\n\nimpl YinResult {\n    pub fn get_frequency(&self) -> f64 {\n        self.sample_rate / self.best_lag as f64\n    }\n\n    pub fn get_frequency_with_interpolation(&self) -> f64 {\n        let best_lag_with_interpolation = parabolic_interpolation(self.best_lag, &self.cmndf);\n        self.sample_rate / best_lag_with_interpolation\n    }\n}\n\nfn parabolic_interpolation(lag: usize, cmndf: &[f64]) -> f64 {\n    let x0 = lag.saturating_sub(1); // max(0, lag-1)\n    let x2 = usize::min(cmndf.len() - 1, lag + 1);\n    let s0 = cmndf[x0];\n    let s1 = cmndf[lag];\n    let s2 = cmndf[x2];\n    let denom = s0 - 2.0 * s1 + s2;\n    if denom == 0.0 {\n        return lag as f64;\n    }\n    let delta = (s0 - s2) / (2.0 * denom);\n    lag as f64 + delta\n}\n\n#[derive(Clone, Debug)]\npub struct Yin {\n    threshold: f64,\n    min_lag: usize,\n    max_lag: usize,\n    sample_rate: f64,\n}\n\nimpl Yin {\n    pub fn init(\n        threshold: f64,\n        min_expected_frequency: f64,\n        max_expected_frequency: f64,\n        sample_rate: f64,\n    ) -> Yin {\n        let min_lag = (sample_rate / max_expected_frequency) as usize;\n        let max_lag = (sample_rate / min_expected_frequency) as usize;\n        Yin {\n            threshold,\n            min_lag,\n            max_lag,\n            sample_rate,\n        }\n    }\n\n    pub fn yin(&self, frequencies: &[f64]) -> Result<YinResult, String> {\n        let df = difference_function_values(frequencies, self.max_lag);\n        let cmndf = cumulative_mean_normalized_difference_function(&df, self.max_lag);\n        let best_lag = find_cmndf_argmin(&cmndf, self.min_lag, self.max_lag, self.threshold);\n        match best_lag {\n            _ if best_lag == 0 => Err(format!(\n                \"Could not find lag value which minimizes CMNDF below the given threshold {}\",\n                self.threshold\n            )),\n            _ => Ok(YinResult {\n                sample_rate: self.sample_rate,\n                best_lag,\n                cmndf,\n            }),\n        }\n    }\n}\n\n#[allow(clippy::needless_range_loop)]\nfn difference_function_values(frequencies: &[f64], max_lag: usize) -> Vec<f64> {\n    let mut df_list = vec![0.0; max_lag + 1];\n    for lag in 1..=max_lag {\n        df_list[lag] = difference_function(frequencies, lag);\n    }\n    df_list\n}\n\nfn difference_function(f: &[f64], lag: usize) -> f64 {\n    let mut sum = 0.0;\n    let n = f.len();\n    for i in 0..(n - lag) {\n        let diff = f[i] - f[i + lag];\n        sum += diff * diff;\n    }\n    sum\n}\n\nconst EPSILON: f64 = 1e-10;\nfn cumulative_mean_normalized_difference_function(df: &[f64], max_lag: usize) -> Vec<f64> {\n    let mut cmndf = vec![0.0; max_lag + 1];\n    cmndf[0] = 1.0;\n    let mut sum = 0.0;\n    for lag in 1..=max_lag {\n        sum += df[lag];\n        cmndf[lag] = lag as f64 * df[lag] / if sum == 0.0 { EPSILON } else { sum };\n    }\n    cmndf\n}\n\nfn find_cmndf_argmin(cmndf: &[f64], min_lag: usize, max_lag: usize, threshold: f64) -> usize {\n    let mut lag = min_lag;\n    while lag <= max_lag {\n        if cmndf[lag] < threshold {\n            while lag < max_lag && cmndf[lag + 1] < cmndf[lag] {\n                lag += 1;\n            }\n            return lag;\n        }\n        lag += 1;\n    }\n    0\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn generate_sine_wave(frequency: f64, sample_rate: f64, duration_secs: f64) -> Vec<f64> {\n        let total_samples = (sample_rate * duration_secs).round() as usize;\n        let two_pi_f = 2.0 * std::f64::consts::PI * frequency;\n\n        (0..total_samples)\n            .map(|n| {\n                let t = n as f64 / sample_rate;\n                (two_pi_f * t).sin()\n            })\n            .collect()\n    }\n\n    fn diff_from_actual_frequency_smaller_than_threshold(\n        result_frequency: f64,\n        actual_frequency: f64,\n        threshold: f64,\n    ) -> bool {\n        let result_diff_from_actual_freq = (result_frequency - actual_frequency).abs();\n        result_diff_from_actual_freq < threshold\n    }\n\n    fn interpolation_better_than_raw_result(result: YinResult, frequency: f64) -> bool {\n        let result_frequency = result.get_frequency();\n        let refined_frequency = result.get_frequency_with_interpolation();\n        let result_diff = (result_frequency - frequency).abs();\n        let refined_diff = (refined_frequency - frequency).abs();\n        refined_diff < result_diff\n    }\n\n    #[test]\n    fn test_simple_sine() {\n        let sample_rate = 1000.0;\n        let frequency = 12.0;\n        let seconds = 10.0;\n        let signal = generate_sine_wave(frequency, sample_rate, seconds);\n\n        let min_expected_frequency = 10.0;\n        let max_expected_frequency = 100.0;\n\n        let yin = Yin::init(\n            0.1,\n            min_expected_frequency,\n            max_expected_frequency,\n            sample_rate,\n        );\n\n        let result = yin.yin(signal.as_slice());\n        assert!(result.is_ok());\n        let yin_result = result.unwrap();\n\n        assert!(diff_from_actual_frequency_smaller_than_threshold(\n            yin_result.get_frequency(),\n            frequency,\n            1.0\n        ));\n        assert!(diff_from_actual_frequency_smaller_than_threshold(\n            yin_result.get_frequency_with_interpolation(),\n            frequency,\n            1.0,\n        ));\n\n        assert!(interpolation_better_than_raw_result(yin_result, frequency));\n    }\n\n    #[test]\n    fn test_sine_frequency_range() {\n        let sample_rate = 5000.0;\n        for freq in 30..50 {\n            let frequency = freq as f64;\n            let seconds = 2.0;\n            let signal = generate_sine_wave(frequency, sample_rate, seconds);\n\n            let min_expected_frequency = 5.0;\n            let max_expected_frequency = 100.0;\n\n            let yin = Yin::init(\n                0.1,\n                min_expected_frequency,\n                max_expected_frequency,\n                sample_rate,\n            );\n            let result = yin.yin(signal.as_slice());\n            assert!(result.is_ok());\n            let yin_result = result.unwrap();\n\n            if (sample_rate as i32 % freq) == 0 {\n                assert_eq!(yin_result.get_frequency(), frequency);\n            } else {\n                assert!(diff_from_actual_frequency_smaller_than_threshold(\n                    yin_result.get_frequency(),\n                    frequency,\n                    1.0\n                ));\n                assert!(diff_from_actual_frequency_smaller_than_threshold(\n                    yin_result.get_frequency_with_interpolation(),\n                    frequency,\n                    1.0,\n                ));\n\n                assert!(interpolation_better_than_raw_result(yin_result, frequency));\n            }\n        }\n    }\n\n    #[test]\n    fn test_harmonic_sines() {\n        let sample_rate = 44100.0;\n        let seconds = 2.0;\n        let frequency_1 = 50.0; // Minimal/Fundamental frequency - this is what YIN should find\n        let signal_1 = generate_sine_wave(frequency_1, sample_rate, seconds);\n        let frequency_2 = 150.0;\n        let signal_2 = generate_sine_wave(frequency_2, sample_rate, seconds);\n        let frequency_3 = 300.0;\n        let signal_3 = generate_sine_wave(frequency_3, sample_rate, seconds);\n\n        let min_expected_frequency = 10.0;\n        let max_expected_frequency = 500.0;\n\n        let yin = Yin::init(\n            0.1,\n            min_expected_frequency,\n            max_expected_frequency,\n            sample_rate,\n        );\n\n        let total_samples = (sample_rate * seconds).round() as usize;\n        let combined_signal: Vec<f64> = (0..total_samples)\n            .map(|n| signal_1[n] + signal_2[n] + signal_3[n])\n            .collect();\n\n        let result = yin.yin(&combined_signal);\n        assert!(result.is_ok());\n        let yin_result = result.unwrap();\n\n        assert!(diff_from_actual_frequency_smaller_than_threshold(\n            yin_result.get_frequency(),\n            frequency_1,\n            1.0\n        ));\n    }\n\n    #[test]\n    fn test_unharmonic_sines() {\n        let sample_rate = 44100.0;\n        let seconds = 2.0;\n        let frequency_1 = 50.0;\n        let signal_1 = generate_sine_wave(frequency_1, sample_rate, seconds);\n        let frequency_2 = 66.0;\n        let signal_2 = generate_sine_wave(frequency_2, sample_rate, seconds);\n        let frequency_3 = 300.0;\n        let signal_3 = generate_sine_wave(frequency_3, sample_rate, seconds);\n\n        let min_expected_frequency = 10.0;\n        let max_expected_frequency = 500.0;\n\n        let yin = Yin::init(\n            0.1,\n            min_expected_frequency,\n            max_expected_frequency,\n            sample_rate,\n        );\n\n        let total_samples = (sample_rate * seconds).round() as usize;\n        let combined_signal: Vec<f64> = (0..total_samples)\n            .map(|n| signal_1[n] + signal_2[n] + signal_3[n])\n            .collect();\n\n        let result = yin.yin(&combined_signal);\n        assert!(result.is_ok());\n        let yin_result = result.unwrap();\n\n        let expected_frequency = (frequency_1 - frequency_2).abs();\n        assert!(diff_from_actual_frequency_smaller_than_threshold(\n            yin_result.get_frequency(),\n            expected_frequency,\n            1.0\n        ));\n        assert!(interpolation_better_than_raw_result(\n            yin_result,\n            expected_frequency\n        ));\n    }\n\n    #[test]\n    fn test_err() {\n        let sample_rate = 2500.0;\n        let seconds = 2.0;\n        let frequency = 440.0;\n\n        // Can't find frequency 440 between 500 and 700\n        let min_expected_frequency = 500.0;\n        let max_expected_frequency = 700.0;\n        let yin = Yin::init(\n            0.1,\n            min_expected_frequency,\n            max_expected_frequency,\n            sample_rate,\n        );\n\n        let signal = generate_sine_wave(frequency, sample_rate, seconds);\n        let result = yin.yin(&signal);\n        assert!(result.is_err());\n\n        let yin_with_suitable_frequency_range = Yin::init(\n            0.1,\n            min_expected_frequency - 100.0,\n            max_expected_frequency,\n            sample_rate,\n        );\n        let result = yin_with_suitable_frequency_range.yin(&signal);\n        assert!(result.is_ok());\n    }\n}\n"
  },
  {
    "path": "src/sorting/README.md",
    "content": "## Sort Algorithms\n\n### [Bogo-sort](./bogo_sort.rs)\n![alt text][bogo-image]\n\nFrom [Wikipedia][bogo-wiki]: In computer science, bogosort is a sorting algorithm based on the generate and test paradigm. The function successively generates permutations of its input until it finds one that is sorted. It is not considered useful for sorting, but may be used for educational purposes, to contrast it with more efficient algorithms.\n\n__Properties__\n* Worst case performance (unbounded in randomized version)\n* Best case performance O(n)\n* Average case performance O((n+1)!)\n\n\n### [Bubble](./bubble_sort.rs)\n![alt text][bubble-image]\n\nFrom [Wikipedia][bubble-wiki]: Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the list to be sorted, compares each pair of adjacent items and swaps them if they are in the wrong order. The pass through the list is repeated until no swaps are needed, which indicates that the list is sorted.\n\n__Properties__\n* Worst case performance\tO(n^2)\n* Best case performance\tO(n)\n* Average case performance\tO(n^2)\n\n###### View the algorithm in [action][bubble-toptal]\n\n\n\n### [Cocktail-Shaker](./cocktail_shaker_sort.rs)\n![alt text][shaker-image]\n\nFrom [Wikipedia][shaker-wiki]: Cocktail shaker sort, also known as bidirectional bubble sort, cocktail sort, shaker sort (which can also refer to a variant of selection sort), ripple sort, shuffle sort, or shuttle sort, is an extension of bubble sort. The algorithm extends bubble sort by operating in two directions. While it improves on bubble sort by more quickly moving items to the beginning of the list, it provides only marginal performance improvements.\n\n__Properties__\n* Worst case performance\tO(n^2)\n* Best case performance\tO(n)\n* Average case performance\tO(n^2)\n\n\n\n### [Comb-sort](./comb_sort.rs)\n![comb sort][comb-sort]\n\nFrom [wikipedia][comb-sort-wiki]: Comb sort is a relatively simple sorting algorithm and improves on bubble sort in the same way that shell sort improves on insertion sort. The basic idea of comb sort is that the gap(distance from two compared elements) can be much more than 1. And the inner loop of bubble sort, which does actual `swap`, is modified such that the gap between swapped elements goes down in steps of a `shrink factor k: [n/k, n/k^2, ..., 1]`. And the gap is divided by the shrink factor in every loop, and the process repeats until the gap is 1. At this point, comb sort continues using a gap of 1 until the list is fully sorted. The final stage of the sort is thus equivalent to a bubble sort, but this time most turtles have been dealt with, so a bubble sort will be efficient. And the shrink factor has a great effect on the efficiency of comb sort and `k=1.3` has been suggested as an ideal value.\n\n__Properties__\n* Worst case performance   O(n^2)\n* Best case performance    O(n log n)\n* Average case performance O(n^2/2^p)\n\nwhere `p` is the number of increments.\n\n\n\n### [Counting](./counting_sort.rs)\n\nFrom [Wikipedia][counting-wiki]: In computer science, counting sort is an algorithm for sorting a collection of objects according to keys that are small integers; that is, it is an integer sorting algorithm. It operates by counting the number of objects that have each distinct key value, and using arithmetic on those counts to determine the positions of each key value in the output sequence. Its running time is linear in the number of items and the difference between the maximum and minimum key values, so it is only suitable for direct use in situations where the variation in keys is not significantly greater than the number of items. However, it is often used as a subroutine in another sorting algorithm, radix sort, that can handle larger keys more efficiently.\n\n__Properties__\n* Worst case performance\tO(n+k)\n* Best case performance\tO(n+k)\n* Average case performance\tO(n+k),\n\nwhere n is the number of integers to sort and k is the difference between the largest and smallest integer in our list.\n\n\n\n### [Insertion](./insertion_sort.rs)\n![alt text][insertion-image]\n\nFrom [Wikipedia][insertion-wiki]: Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort.\n\n__Properties__\n* Worst case performance\tO(n^2)\n* Best case performance\tO(n)\n* Average case performance\tO(n^2)\n\n###### View the algorithm in [action][insertion-toptal]\n\n\n### [Gnome](./gnome_sort.rs)\n![alt text][gnome-image]\n\nFrom [Wikipedia][gnome-wiki]: The gnome sort is a sorting algorithm which is similar to insertion sort in that it works with one item at a time but gets the item to the proper place by a series of swaps, similar to a bubble sort. It is conceptually simple, requiring no nested loops. The average running time is O(n^2) but tends towards O(n) if the list is initially almost sorted\n\n__Properties__\n* Worst case performance\tO(n^2)\n* Best case performance\tO(n)\n* Average case performance\tO(n^2)\n\n\n\n### [Merge](./merge_sort.rs)\n![alt text][merge-image]\n\nFrom [Wikipedia][merge-wiki]: In computer science, merge sort (also commonly spelled mergesort) is an efficient, general-purpose, comparison-based sorting algorithm. Most implementations produce a stable sort, which means that the implementation preserves the input order of equal elements in the sorted output. Mergesort is a divide and conquer algorithm that was invented by John von Neumann in 1945.\n\n__Properties__\n* Worst case performance\tO(n log n)\n* Best case performance\tO(n log n)\n* Average case performance\tO(n log n)\n\n\n###### View the algorithm in [action][merge-toptal]\n\n### [Odd-even](./odd_even_sort.rs)\n![alt text][odd-even-image]\n\nFrom [Wikipedia][odd-even-wiki]: In computing, an odd–even sort or odd–even transposition sort (also known as brick sort or parity sort) is a relatively simple sorting algorithm, developed originally for use on parallel processors with local interconnections. It is a comparison sort related to bubble sort, with which it shares many characteristics. It functions by comparing all odd/even indexed pairs of adjacent elements in the list and, if a pair is in the wrong order (the first is larger than the second) the elements are switched. The next step repeats this for even/odd indexed pairs (of adjacent elements). Then it alternates between odd/even and even/odd steps until the list is sorted. \n\nNOTE: The implementation is an adaptation of the algorithm for a single-processor machine, while the original algorithm was devised to be executed on many processors simultaneously.\n__Properties__\n* Worst case performance\tO(n^2)\n* Best case performance\tO(n)\n* Average case performance\tO(n^2)\n\n\n### [Pancake](./pancake_sort.rs)\n![alt text][pancake-image]\n\nFrom [Wikipedia][pancake-wiki]: All sorting methods require pairs of elements to be compared. For the traditional sorting problem, the usual problem studied is to minimize the number of comparisons required to sort a list. The number of actual operations, such as swapping two elements, is then irrelevant. For pancake sorting problems, in contrast, the aim is to minimize the number of operations, where the only allowed operations are reversals of the elements of some prefix of the sequence. Now, the number of comparisons is irrelevant.\n\n\n### [Quick](./quick_sort.rs)\n![alt text][quick-image]\n\nFrom [Wikipedia][quick-wiki]: Quicksort (sometimes called partition-exchange sort) is an efficient sorting algorithm, serving as a systematic method for placing the elements of an array in order.\n\n__Properties__\n* Worst case performance\tO(n^2)\n* Best case performance\tO(n log n) or O(n) with three-way partition\n* Average case performance\tO(n log n)\n\n###### View the algorithm in [action][quick-toptal]\n\n### [Radix](./radix_sort.rs)\n![alt text][radix-image]\n\nFrom [Wikipedia][radix-wiki]: Radix sort is a non-comparative sorting algorithm. It avoids comparison by creating and distributing elements into buckets according to their radix. For elements with more than one significant digit, this bucketing process is repeated for each digit, while preserving the ordering of the prior step, until all digits have been considered.\n\n__Properties__\n* Worst case performance O(w*n)\n\nwhere w is the number of bits required to store each key.\n\n### [Selection](./selection_sort.rs)\n![alt text][selection-image]\n\nFrom [Wikipedia][selection-wiki]: The algorithm divides the input list into two parts: the sublist of items already sorted, which is built up from left to right at the front (left) of the list, and the sublist of items remaining to be sorted that occupy the rest of the list. Initially, the sorted sublist is empty and the unsorted sublist is the entire input list. The algorithm proceeds by finding the smallest (or largest, depending on sorting order) element in the unsorted sublist, exchanging (swapping) it with the leftmost unsorted element (putting it in sorted order), and moving the sublist boundaries one element to the right.\n\n__Properties__\n* Worst case performance\tO(n^2)\n* Best case performance\tO(n^2)\n* Average case performance\tO(n^2)\n\n###### View the algorithm in [action][selection-toptal]\n\n### [Shell](./shell_sort.rs)\n![alt text][shell-image]\n\nFrom [Wikipedia][shell-wiki]:  Shellsort is a generalization of insertion sort that allows the exchange of items that are far apart.  The idea is to arrange the list of elements so that, starting anywhere, considering every nth element gives a sorted list.  Such a list is said to be h-sorted.  Equivalently, it can be thought of as h interleaved lists, each individually sorted.\n\n__Properties__\n* Worst case performance O(nlog2 2n)\n* Best case performance O(n log n)\n* Average case performance depends on gap sequence\n\n###### View the algorithm in [action][shell-toptal]\n\n### [Stooge](./stooge_sort.rs)\n![alt text][stooge-image]\n\nFrom [Wikipedia][stooge-wiki]:  Stooge sort is a recursive sorting algorithm. It is notable for its exceptionally bad time complexity of O(n^(log 3 / log 1.5)) = O(n^2.7095...). The running time of the algorithm is thus slower compared to reasonable sorting algorithms, and is slower than Bubble sort, a canonical example of a fairly inefficient sort. It is however more efficient than Slowsort. The name comes from The Three Stooges.\n\n__Properties__\n* Worst case performance O(n^(log(3) / log(1.5)))\n\n### [Tim](./tim_sort.rs)\n![alt text][tim-image]\n\nFrom [Wikipedia][tim-wiki]:  Timsort is a hybrid stable sorting algorithm, derived from merge sort and insertion sort, designed to perform well on many kinds of real-world data. It was implemented by Tim Peters in 2002 for use in the Python programming language. The algorithm finds subsequences of the data that are already ordered (runs) and uses them to sort the remainder more efficiently. This is done by merging runs until certain criteria are fulfilled. Timsort has been Python's standard sorting algorithm since version 2.3. It is also used to sort arrays of non-primitive type in Java SE 7, on the Android platform, in GNU Octave, on V8, Swift, and Rust.\n\n__Properties__\n* Worst-case performance O(max element size(ms))\n* Best-case performance\tO(max element size(ms))\n\n### [Sleep](./sleep_sort.rs)\n![alt text][sleep-image]\n\nFrom [Wikipedia][bucket-sort-wiki]: This is an idea that was originally posted on the message board 4chan, replacing the bucket in bucket sort with time instead of memory space.\nIt is actually possible to sort by \"maximum of all elements x unit time to sleep\". The only case where this would be useful would be in examples.\n\n### [Patience](./patience_sort.rs)\n[patience-video]\n\n\nFrom [Wikipedia][patience-sort-wiki]: The algorithm's name derives from a simplified variant of the patience card game. The game begins with a shuffled deck of cards. The cards are dealt one by one into a sequence of piles on the table, according to the following rules.\n\n1. Initially, there are no piles. The first card dealt forms a new pile consisting of the single card.\n2. Each subsequent card is placed on the leftmost existing pile whose top card has a value greater than or equal to the new card's value, or to the right of all of the existing piles, thus forming a new pile.\n3. When there are no more cards remaining to deal, the game ends.\n\nThis card game is turned into a two-phase sorting algorithm, as follows. Given an array of n elements from some totally ordered domain, consider this array as a collection of cards and simulate the patience sorting game. When the game is over, recover the sorted sequence by repeatedly picking off the minimum visible card; in other words, perform a k-way merge of the p piles, each of which is internally sorted.\n\n__Properties__\n* Worst case performance O(n log n)\n* Best case performance\tO(n)\n\n[bogo-wiki]: https://en.wikipedia.org/wiki/Bogosort\n[bogo-image]: https://upload.wikimedia.org/wikipedia/commons/7/7b/Bogo_sort_animation.gif\n\n[bubble-toptal]: https://www.toptal.com/developers/sorting-algorithms/bubble-sort\n[bubble-wiki]: https://en.wikipedia.org/wiki/Bubble_sort\n[bubble-image]: https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Bubblesort-edited-color.svg/220px-Bubblesort-edited-color.svg.png \"Bubble Sort\"\n\n[shaker-wiki]: https://en.wikipedia.org/wiki/Cocktail_shaker_sort\n[shaker-image]: https://upload.wikimedia.org/wikipedia/commons/e/ef/Sorting_shaker_sort_anim.gif\n\n[counting-wiki]: https://en.wikipedia.org/wiki/Counting_sort\n\n[insertion-toptal]: https://www.toptal.com/developers/sorting-algorithms/insertion-sort\n[insertion-wiki]: https://en.wikipedia.org/wiki/Insertion_sort\n[insertion-image]: https://upload.wikimedia.org/wikipedia/commons/7/7e/Insertionsort-edited.png \"Insertion Sort\"\n\n[gnome-wiki]: https://en.wikipedia.org/wiki/Gnome_sort\n[gnome-image]: https://upload.wikimedia.org/wikipedia/commons/3/37/Sorting_gnomesort_anim.gif \"Insertion Sort\"\n\n[pancake-wiki]: https://en.wikipedia.org/wiki/Pancake_sorting\n[pancake-image]: https://upload.wikimedia.org/wikipedia/commons/0/0f/Pancake_sort_operation.png\n\n[quick-toptal]: https://www.toptal.com/developers/sorting-algorithms/quick-sort\n[quick-wiki]: https://en.wikipedia.org/wiki/Quicksort\n[quick-image]: https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif \"Quick Sort\"\n\n[merge-toptal]: https://www.toptal.com/developers/sorting-algorithms/merge-sort\n[merge-wiki]: https://en.wikipedia.org/wiki/Merge_sort\n[merge-image]: https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif \"Merge Sort\"\n\n[odd-even-image]: https://upload.wikimedia.org/wikipedia/commons/1/1b/Odd_even_sort_animation.gif\n[odd-even-wiki]: https://en.wikipedia.org/wiki/Odd%E2%80%93even_sort\n\n[radix-wiki]: https://en.wikipedia.org/wiki/Radix_sort\n[radix-image]: https://ds055uzetaobb.cloudfront.net/brioche/uploads/IEZs8xJML3-radixsort_ed.png?width=400 \"Radix Sort\"\n\n[selection-toptal]: https://www.toptal.com/developers/sorting-algorithms/selection-sort\n[selection-wiki]: https://en.wikipedia.org/wiki/Selection_sort\n[selection-image]: https://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Selection_sort_animation.gif/250px-Selection_sort_animation.gif \"Selection Sort Sort\"\n\n[shell-toptal]: https://www.toptal.com/developers/sorting-algorithms/shell-sort\n[shell-wiki]: https://en.wikipedia.org/wiki/Shellsort\n[shell-image]: https://upload.wikimedia.org/wikipedia/commons/d/d8/Sorting_shellsort_anim.gif \"Shell Sort\"\n\n[stooge-image]: https://upload.wikimedia.org/wikipedia/commons/f/f8/Sorting_stoogesort_anim.gif\n[stooge-wiki]: https://en.wikipedia.org/wiki/Stooge_sort\n\n[tim-image]: https://thumbs.gfycat.com/BruisedFrigidBlackrhino-size_restricted.gif\n[tim-wiki]: https://en.wikipedia.org/wiki/Timsort\n\n[comb-sort]: https://upload.wikimedia.org/wikipedia/commons/4/46/Comb_sort_demo.gif\n[comb-sort-wiki]: https://en.wikipedia.org/wiki/Comb_sort\n\n[sleep-sort]: <no image>\n[sleep-sort-wiki]: https://ja.m.wikipedia.org/wiki/バケットソート#.E3.82.B9.E3.83.AA.E3.83.BC.E3.83.97.E3.82.BD.E3.83.BC.E3.83.88\n\n[patience-sort-wiki]: https://en.wikipedia.org/wiki/Patience_sorting\n[patience-video]: https://user-images.githubusercontent.com/67539676/212542208-d3f7a824-60d8-467c-8097-841945514ae9.mp4\n"
  },
  {
    "path": "src/sorting/bead_sort.rs",
    "content": "//Bead sort only works for sequences of non-negative integers.\n//https://en.wikipedia.org/wiki/Bead_sort\npub fn bead_sort(a: &mut [usize]) {\n    // Find the maximum element\n    let mut max = a[0];\n    (1..a.len()).for_each(|i| {\n        if a[i] > max {\n            max = a[i];\n        }\n    });\n\n    // allocating memory\n    let mut beads = vec![vec![0; max]; a.len()];\n\n    // mark the beads\n    for i in 0..a.len() {\n        for j in (0..a[i]).rev() {\n            beads[i][j] = 1;\n        }\n    }\n\n    // move down the beads\n    for j in 0..max {\n        let mut sum = 0;\n        (0..a.len()).for_each(|i| {\n            sum += beads[i][j];\n            beads[i][j] = 0;\n        });\n\n        for k in ((a.len() - sum)..a.len()).rev() {\n            a[k] = j + 1;\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn descending() {\n        //descending\n        let mut ve1: [usize; 5] = [5, 4, 3, 2, 1];\n        let cloned = ve1;\n        bead_sort(&mut ve1);\n        assert!(is_sorted(&ve1) && have_same_elements(&ve1, &cloned));\n    }\n\n    #[test]\n    fn mix_values() {\n        //pre-sorted\n        let mut ve2: [usize; 5] = [7, 9, 6, 2, 3];\n        let cloned = ve2;\n        bead_sort(&mut ve2);\n        assert!(is_sorted(&ve2) && have_same_elements(&ve2, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/binary_insertion_sort.rs",
    "content": "fn _binary_search<T: Ord>(arr: &[T], target: &T) -> usize {\n    let mut low = 0;\n    let mut high = arr.len();\n\n    while low < high {\n        let mid = low + (high - low) / 2;\n\n        if arr[mid] < *target {\n            low = mid + 1;\n        } else {\n            high = mid;\n        }\n    }\n\n    low\n}\n\npub fn binary_insertion_sort<T: Ord + Clone>(arr: &mut [T]) {\n    let len = arr.len();\n\n    for i in 1..len {\n        let key = arr[i].clone();\n        let index = _binary_search(&arr[..i], &key);\n\n        arr[index..=i].rotate_right(1);\n        arr[index] = key;\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_binary_insertion_sort() {\n        let mut arr1 = vec![64, 25, 12, 22, 11];\n        let mut arr2 = vec![5, 4, 3, 2, 1];\n        let mut arr3 = vec![1, 2, 3, 4, 5];\n        let mut arr4: Vec<i32> = vec![]; // Explicitly specify the type for arr4\n\n        binary_insertion_sort(&mut arr1);\n        binary_insertion_sort(&mut arr2);\n        binary_insertion_sort(&mut arr3);\n        binary_insertion_sort(&mut arr4);\n\n        assert_eq!(arr1, vec![11, 12, 22, 25, 64]);\n        assert_eq!(arr2, vec![1, 2, 3, 4, 5]);\n        assert_eq!(arr3, vec![1, 2, 3, 4, 5]);\n        assert_eq!(arr4, Vec::<i32>::new());\n    }\n}\n"
  },
  {
    "path": "src/sorting/bingo_sort.rs",
    "content": "use std::cmp::{max, min};\n\n// Function for finding the maximum and minimum element of the Array\nfn max_min(vec: &[i32], bingo: &mut i32, next_bingo: &mut i32) {\n    for &element in vec.iter().skip(1) {\n        *bingo = min(*bingo, element);\n        *next_bingo = max(*next_bingo, element);\n    }\n}\n\npub fn bingo_sort(vec: &mut [i32]) {\n    if vec.is_empty() {\n        return;\n    }\n\n    let mut bingo = vec[0];\n    let mut next_bingo = vec[0];\n\n    max_min(vec, &mut bingo, &mut next_bingo);\n\n    let largest_element = next_bingo;\n    let mut next_element_pos = 0;\n\n    for (bingo, _next_bingo) in (bingo..=largest_element).zip(bingo..=largest_element) {\n        let start_pos = next_element_pos;\n\n        for i in start_pos..vec.len() {\n            if vec[i] == bingo {\n                vec.swap(i, next_element_pos);\n                next_element_pos += 1;\n            }\n        }\n    }\n}\n\n#[allow(dead_code)]\nfn print_array(arr: &[i32]) {\n    print!(\"Sorted Array: \");\n    for &element in arr {\n        print!(\"{element} \");\n    }\n    println!();\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_bingo_sort() {\n        let mut arr = vec![5, 4, 8, 5, 4, 8, 5, 4, 4, 4];\n        bingo_sort(&mut arr);\n        assert_eq!(arr, vec![4, 4, 4, 4, 4, 5, 5, 5, 8, 8]);\n\n        let mut arr2 = vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1];\n        bingo_sort(&mut arr2);\n        assert_eq!(arr2, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);\n\n        let mut arr3 = vec![0, 1, 0, 1, 0, 1];\n        bingo_sort(&mut arr3);\n        assert_eq!(arr3, vec![0, 0, 0, 1, 1, 1]);\n    }\n\n    #[test]\n    fn test_empty_array() {\n        let mut arr = Vec::new();\n        bingo_sort(&mut arr);\n        assert_eq!(arr, Vec::new());\n    }\n\n    #[test]\n    fn test_single_element_array() {\n        let mut arr = vec![42];\n        bingo_sort(&mut arr);\n        assert_eq!(arr, vec![42]);\n    }\n\n    #[test]\n    fn test_negative_numbers() {\n        let mut arr = vec![-5, -4, -3, -2, -1];\n        bingo_sort(&mut arr);\n        assert_eq!(arr, vec![-5, -4, -3, -2, -1]);\n    }\n\n    #[test]\n    fn test_already_sorted() {\n        let mut arr = vec![1, 2, 3, 4, 5];\n        bingo_sort(&mut arr);\n        assert_eq!(arr, vec![1, 2, 3, 4, 5]);\n    }\n\n    #[test]\n    fn test_reverse_sorted() {\n        let mut arr = vec![5, 4, 3, 2, 1];\n        bingo_sort(&mut arr);\n        assert_eq!(arr, vec![1, 2, 3, 4, 5]);\n    }\n\n    #[test]\n    fn test_duplicates() {\n        let mut arr = vec![1, 2, 3, 4, 5, 1, 2, 3, 4, 5];\n        bingo_sort(&mut arr);\n        assert_eq!(arr, vec![1, 1, 2, 2, 3, 3, 4, 4, 5, 5]);\n    }\n}\n"
  },
  {
    "path": "src/sorting/bitonic_sort.rs",
    "content": "fn _comp_and_swap<T: Ord>(array: &mut [T], left: usize, right: usize, ascending: bool) {\n    if (ascending && array[left] > array[right]) || (!ascending && array[left] < array[right]) {\n        array.swap(left, right);\n    }\n}\n\nfn _bitonic_merge<T: Ord>(array: &mut [T], low: usize, length: usize, ascending: bool) {\n    if length > 1 {\n        let middle = length / 2;\n        for i in low..(low + middle) {\n            _comp_and_swap(array, i, i + middle, ascending);\n        }\n        _bitonic_merge(array, low, middle, ascending);\n        _bitonic_merge(array, low + middle, middle, ascending);\n    }\n}\n\npub fn bitonic_sort<T: Ord>(array: &mut [T], low: usize, length: usize, ascending: bool) {\n    if length > 1 {\n        let middle = length / 2;\n        bitonic_sort(array, low, middle, true);\n        bitonic_sort(array, low + middle, middle, false);\n        _bitonic_merge(array, low, length, ascending);\n    }\n}\n\n//Note that this program works only when size of input is a power of 2.\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_descending_sorted;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn descending() {\n        //descending\n        let mut ve1 = vec![6, 5, 4, 3];\n        let cloned = ve1.clone();\n        bitonic_sort(&mut ve1, 0, 4, true);\n        assert!(is_sorted(&ve1) && have_same_elements(&ve1, &cloned));\n    }\n\n    #[test]\n    fn ascending() {\n        //pre-sorted\n        let mut ve2 = vec![1, 2, 3, 4];\n        let cloned = ve2.clone();\n        bitonic_sort(&mut ve2, 0, 4, false);\n        assert!(is_descending_sorted(&ve2) && have_same_elements(&ve2, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/bogo_sort.rs",
    "content": "use crate::math::PCG32;\nuse std::time::{SystemTime, UNIX_EPOCH};\n\nconst DEFAULT: u64 = 4294967296;\n\nfn is_sorted<T: Ord>(arr: &[T], len: usize) -> bool {\n    for i in 0..len - 1 {\n        if arr[i] > arr[i + 1] {\n            return false;\n        }\n    }\n\n    true\n}\n\n#[cfg(target_pointer_width = \"64\")]\nfn generate_index(range: usize, generator: &mut PCG32) -> usize {\n    generator.get_u64() as usize % range\n}\n\n#[cfg(not(target_pointer_width = \"64\"))]\nfn generate_index(range: usize, generator: &mut PCG32) -> usize {\n    generator.get_u32() as usize % range\n}\n\n/**\n * Fisher–Yates shuffle for generating random permutation.\n */\nfn permute_randomly<T>(arr: &mut [T], len: usize, generator: &mut PCG32) {\n    for i in (1..len).rev() {\n        let j = generate_index(i + 1, generator);\n        arr.swap(i, j);\n    }\n}\n\npub fn bogo_sort<T: Ord>(arr: &mut [T]) {\n    let seed = match SystemTime::now().duration_since(UNIX_EPOCH) {\n        Ok(duration) => duration.as_millis() as u64,\n        Err(_) => DEFAULT,\n    };\n\n    let mut random_generator = PCG32::new_default(seed);\n\n    let arr_length = arr.len();\n    while !is_sorted(arr, arr_length) {\n        permute_randomly(arr, arr_length, &mut random_generator);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn random_array() {\n        let mut arr = [1, 8, 3, 2, 7, 4, 6, 5];\n        bogo_sort(&mut arr);\n\n        for i in 0..arr.len() - 1 {\n            assert!(arr[i] <= arr[i + 1]);\n        }\n    }\n\n    #[test]\n    fn sorted_array() {\n        let mut arr = [1, 2, 3, 4, 5, 6, 7, 8];\n        bogo_sort(&mut arr);\n\n        for i in 0..arr.len() - 1 {\n            assert!(arr[i] <= arr[i + 1]);\n        }\n    }\n}\n"
  },
  {
    "path": "src/sorting/bubble_sort.rs",
    "content": "pub fn bubble_sort<T: Ord>(arr: &mut [T]) {\n    if arr.is_empty() {\n        return;\n    }\n    let mut sorted = false;\n    let mut n = arr.len();\n    while !sorted {\n        sorted = true;\n        for i in 0..n - 1 {\n            if arr[i] > arr[i + 1] {\n                arr.swap(i, i + 1);\n                sorted = false;\n            }\n        }\n        n -= 1;\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn descending() {\n        //descending\n        let mut ve1 = vec![6, 5, 4, 3, 2, 1];\n        let cloned = ve1.clone();\n        bubble_sort(&mut ve1);\n        assert!(is_sorted(&ve1) && have_same_elements(&ve1, &cloned));\n    }\n\n    #[test]\n    fn ascending() {\n        //pre-sorted\n        let mut ve2 = vec![1, 2, 3, 4, 5, 6];\n        let cloned = ve2.clone();\n        bubble_sort(&mut ve2);\n        assert!(is_sorted(&ve2) && have_same_elements(&ve2, &cloned));\n    }\n    #[test]\n    fn empty() {\n        let mut ve3: Vec<usize> = vec![];\n        let cloned = ve3.clone();\n        bubble_sort(&mut ve3);\n        assert!(is_sorted(&ve3) && have_same_elements(&ve3, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/bucket_sort.rs",
    "content": "/// Sort a slice using bucket sort algorithm.\n///\n/// Time complexity is `O(n + k)` on average, where `n` is the number of elements,\n/// `k` is the number of buckets used in process.\n///\n/// Space complexity is `O(n + k)`, as it sorts not in-place.\npub fn bucket_sort(arr: &[usize]) -> Vec<usize> {\n    if arr.is_empty() {\n        return vec![];\n    }\n\n    let max = *arr.iter().max().unwrap();\n    let len = arr.len();\n    let mut buckets = vec![vec![]; len + 1];\n\n    for x in arr {\n        buckets[len * *x / max].push(*x);\n    }\n\n    for bucket in buckets.iter_mut() {\n        super::insertion_sort(bucket);\n    }\n\n    let mut result = vec![];\n    for bucket in buckets {\n        for x in bucket {\n            result.push(x);\n        }\n    }\n\n    result\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn empty() {\n        let arr: [usize; 0] = [];\n        let cloned = arr;\n        let res = bucket_sort(&arr);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn one_element() {\n        let arr: [usize; 1] = [4];\n        let cloned = arr;\n        let res = bucket_sort(&arr);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn already_sorted() {\n        let arr: [usize; 3] = [10, 19, 105];\n        let cloned = arr;\n        let res = bucket_sort(&arr);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn basic() {\n        let arr: [usize; 4] = [35, 53, 1, 0];\n        let cloned = arr;\n        let res = bucket_sort(&arr);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn odd_number_of_elements() {\n        let arr: [usize; 5] = [1, 21, 5, 11, 58];\n        let cloned = arr;\n        let res = bucket_sort(&arr);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn repeated_elements() {\n        let arr: [usize; 4] = [542, 542, 542, 542];\n        let cloned = arr;\n        let res = bucket_sort(&arr);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/cocktail_shaker_sort.rs",
    "content": "pub fn cocktail_shaker_sort<T: Ord>(arr: &mut [T]) {\n    let len = arr.len();\n\n    if len == 0 {\n        return;\n    }\n\n    loop {\n        let mut swapped = false;\n\n        for i in 0..(len - 1).clamp(0, len) {\n            if arr[i] > arr[i + 1] {\n                arr.swap(i, i + 1);\n                swapped = true;\n            }\n        }\n\n        if !swapped {\n            break;\n        }\n\n        swapped = false;\n\n        for i in (0..(len - 1).clamp(0, len)).rev() {\n            if arr[i] > arr[i + 1] {\n                arr.swap(i, i + 1);\n                swapped = true;\n            }\n        }\n\n        if !swapped {\n            break;\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn basic() {\n        let mut arr = vec![5, 2, 1, 3, 4, 6];\n        let cloned = arr.clone();\n        cocktail_shaker_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n\n    #[test]\n    fn empty() {\n        let mut arr = Vec::<i32>::new();\n        let cloned = arr.clone();\n        cocktail_shaker_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n\n    #[test]\n    fn one_element() {\n        let mut arr = vec![1];\n        let cloned = arr.clone();\n        cocktail_shaker_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n\n    #[test]\n    fn pre_sorted() {\n        let mut arr = vec![1, 2, 3, 4, 5, 6];\n        let cloned = arr.clone();\n        cocktail_shaker_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/comb_sort.rs",
    "content": "pub fn comb_sort<T: Ord>(arr: &mut [T]) {\n    let mut gap = arr.len();\n    let shrink = 1.3;\n    let mut sorted = false;\n\n    while !sorted {\n        gap = (gap as f32 / shrink).floor() as usize;\n        if gap <= 1 {\n            gap = 1;\n            sorted = true;\n        }\n        for i in 0..arr.len() - gap {\n            let j = i + gap;\n            if arr[i] > arr[j] {\n                arr.swap(i, j);\n                sorted = false;\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn descending() {\n        //descending\n        let mut ve1 = vec![6, 5, 4, 3, 2, 1];\n        let cloned = ve1.clone();\n        comb_sort(&mut ve1);\n        assert!(is_sorted(&ve1) && have_same_elements(&ve1, &cloned));\n    }\n\n    #[test]\n    fn ascending() {\n        //pre-sorted\n        let mut ve2 = vec![1, 2, 3, 4, 5, 6];\n        let cloned = ve2.clone();\n        comb_sort(&mut ve2);\n        assert!(is_sorted(&ve2) && have_same_elements(&ve2, &cloned));\n    }\n\n    #[test]\n    fn duplicates() {\n        //pre-sorted\n        let mut ve3 = vec![2, 2, 2, 2, 2, 1];\n        let cloned = ve3.clone();\n        comb_sort(&mut ve3);\n        assert!(is_sorted(&ve3) && have_same_elements(&ve3, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/counting_sort.rs",
    "content": "/// In place counting sort for collections of u32\n/// O(n + maxval) in time, where maxval is the biggest value an input can possibly take\n/// O(maxval) in memory\n/// u32 is chosen arbitrarly, a counting sort probably should'nt be used on data that requires bigger types.\n\npub fn counting_sort(arr: &mut [u32], maxval: usize) {\n    let mut occurences: Vec<usize> = vec![0; maxval + 1];\n\n    for &data in arr.iter() {\n        occurences[data as usize] += 1;\n    }\n\n    let mut i = 0;\n    for (data, &number) in occurences.iter().enumerate() {\n        for _ in 0..number {\n            arr[i] = data as u32;\n            i += 1;\n        }\n    }\n}\n\nuse std::ops::AddAssign;\n/// Generic implementation of a counting sort for all usigned types\npub fn generic_counting_sort<T: Into<u64> + From<u8> + AddAssign + Copy>(\n    arr: &mut [T],\n    maxval: usize,\n) {\n    let mut occurences: Vec<usize> = vec![0; maxval + 1];\n\n    for &data in arr.iter() {\n        occurences[data.into() as usize] += 1;\n    }\n\n    // Current index in output array\n    let mut i = 0;\n\n    // current data point, necessary to be type-safe\n    let mut data = T::from(0);\n\n    // This will iterate from 0 to the largest data point in `arr`\n    // `number` contains the occurances of the data point `data`\n    for &number in occurences.iter() {\n        for _ in 0..number {\n            arr[i] = data;\n            i += 1;\n        }\n\n        data += T::from(1);\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn counting_sort_descending() {\n        let mut ve1 = vec![6, 5, 4, 3, 2, 1];\n        let cloned = ve1.clone();\n        counting_sort(&mut ve1, 6);\n\n        assert!(is_sorted(&ve1) && have_same_elements(&ve1, &cloned));\n    }\n\n    #[test]\n    fn counting_sort_pre_sorted() {\n        let mut ve2 = vec![1, 2, 3, 4, 5, 6];\n        let cloned = ve2.clone();\n        counting_sort(&mut ve2, 6);\n\n        assert!(is_sorted(&ve2) && have_same_elements(&ve2, &cloned));\n    }\n\n    #[test]\n    fn generic_counting_sort() {\n        let mut ve1: Vec<u8> = vec![100, 30, 60, 10, 20, 120, 1];\n        let cloned = ve1.clone();\n        super::generic_counting_sort(&mut ve1, 120);\n\n        assert!(is_sorted(&ve1) && have_same_elements(&ve1, &cloned));\n    }\n\n    #[test]\n    fn presorted_u64_counting_sort() {\n        let mut ve2: Vec<u64> = vec![1, 2, 3, 4, 5, 6];\n        let cloned = ve2.clone();\n        super::generic_counting_sort(&mut ve2, 6);\n\n        assert!(is_sorted(&ve2) && have_same_elements(&ve2, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/cycle_sort.rs",
    "content": "// sorts with the minimum number of rewrites. Runs through all values in the array, placing them in their correct spots. O(n^2).\n\npub fn cycle_sort(arr: &mut [i32]) {\n    for cycle_start in 0..arr.len() {\n        let mut item = arr[cycle_start];\n        let mut pos = cycle_start;\n        for i in arr.iter().skip(cycle_start + 1) {\n            if *i < item {\n                pos += 1;\n            }\n        }\n        if pos == cycle_start {\n            continue;\n        }\n        while item == arr[pos] {\n            pos += 1;\n        }\n        std::mem::swap(&mut arr[pos], &mut item);\n        while pos != cycle_start {\n            pos = cycle_start;\n            for i in arr.iter().skip(cycle_start + 1) {\n                if *i < item {\n                    pos += 1;\n                }\n            }\n            while item == arr[pos] {\n                pos += 1;\n            }\n            std::mem::swap(&mut arr[pos], &mut item);\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn it_works() {\n        let mut arr1 = [6, 5, 4, 3, 2, 1];\n        let cloned = arr1;\n        cycle_sort(&mut arr1);\n        assert!(is_sorted(&arr1) && have_same_elements(&arr1, &cloned));\n        arr1 = [12, 343, 21, 90, 3, 21];\n        let cloned = arr1;\n        cycle_sort(&mut arr1);\n        assert!(is_sorted(&arr1) && have_same_elements(&arr1, &cloned));\n        let mut arr2 = [1];\n        let cloned = arr2;\n        cycle_sort(&mut arr2);\n        assert!(is_sorted(&arr2) && have_same_elements(&arr2, &cloned));\n        let mut arr3 = [213, 542, 90, -23412, -32, 324, -34, 3324, 54];\n        let cloned = arr3;\n        cycle_sort(&mut arr3);\n        assert!(is_sorted(&arr3) && have_same_elements(&arr3, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/dutch_national_flag_sort.rs",
    "content": "/*\nA Rust implementation of the Dutch National Flag sorting algorithm.\n\nReference implementation: https://github.com/TheAlgorithms/Python/blob/master/sorts/dutch_national_flag_sort.py\nMore info: https://en.wikipedia.org/wiki/Dutch_national_flag_problem\n*/\n\n#[derive(PartialOrd, PartialEq, Eq)]\npub enum Colors {\n    Red,   // \\\n    White, //  | Define the three colors of the Dutch Flag: 🇳🇱\n    Blue,  // /\n}\nuse Colors::{Blue, Red, White};\n\n// Algorithm implementation\npub fn dutch_national_flag_sort(mut sequence: Vec<Colors>) -> Vec<Colors> {\n    // We take ownership of `sequence` because the original `sequence` will be modified and then returned\n    let length = sequence.len();\n    if length <= 1 {\n        return sequence; // Arrays of length 0 or 1 are automatically sorted\n    }\n    let mut low = 0;\n    let mut mid = 0;\n    let mut high = length - 1;\n    while mid <= high {\n        match sequence[mid] {\n            Red => {\n                sequence.swap(low, mid);\n                low += 1;\n                mid += 1;\n            }\n            White => {\n                mid += 1;\n            }\n            Blue => {\n                sequence.swap(mid, high);\n                high -= 1;\n            }\n        }\n    }\n    sequence\n}\n\n#[cfg(test)]\nmod tests {\n    use super::super::is_sorted;\n    use super::*;\n\n    #[test]\n    fn random_array() {\n        let arr = vec![\n            Red, Blue, White, White, Blue, Blue, Red, Red, White, Blue, White, Red, White, Blue,\n        ];\n        let arr = dutch_national_flag_sort(arr);\n        assert!(is_sorted(&arr))\n    }\n\n    #[test]\n    fn sorted_array() {\n        let arr = vec![\n            Red, Red, Red, Red, Red, White, White, White, White, White, Blue, Blue, Blue, Blue,\n        ];\n        let arr = dutch_national_flag_sort(arr);\n        assert!(is_sorted(&arr))\n    }\n}\n"
  },
  {
    "path": "src/sorting/exchange_sort.rs",
    "content": "// sorts through swapping the first value until it is at the right position, and repeating for all the following.\n\npub fn exchange_sort(arr: &mut [i32]) {\n    let length = arr.len();\n    for number1 in 0..length {\n        for number2 in (number1 + 1)..length {\n            if arr[number2] < arr[number1] {\n                arr.swap(number1, number2)\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n    #[test]\n    fn it_works() {\n        let mut arr1 = [6, 5, 4, 3, 2, 1];\n        let cloned = arr1;\n        exchange_sort(&mut arr1);\n        assert!(is_sorted(&arr1) && have_same_elements(&arr1, &cloned));\n        arr1 = [12, 343, 21, 90, 3, 21];\n        let cloned = arr1;\n        exchange_sort(&mut arr1);\n        assert!(is_sorted(&arr1) && have_same_elements(&arr1, &cloned));\n        let mut arr2 = [1];\n        let cloned = arr2;\n        exchange_sort(&mut arr2);\n        assert!(is_sorted(&arr2) && have_same_elements(&arr2, &cloned));\n        let mut arr3 = [213, 542, 90, -23412, -32, 324, -34, 3324, 54];\n        let cloned = arr3;\n        exchange_sort(&mut arr3);\n        assert!(is_sorted(&arr3) && have_same_elements(&arr3, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/gnome_sort.rs",
    "content": "use std::cmp;\n\npub fn gnome_sort<T>(arr: &[T]) -> Vec<T>\nwhere\n    T: cmp::PartialEq + cmp::PartialOrd + Clone,\n{\n    let mut arr = arr.to_vec();\n    let mut i: usize = 1;\n    let mut j: usize = 2;\n\n    while i < arr.len() {\n        if arr[i - 1] < arr[i] {\n            i = j;\n            j = i + 1;\n        } else {\n            arr.swap(i - 1, i);\n            i -= 1;\n            if i == 0 {\n                i = j;\n                j += 1;\n            }\n        }\n    }\n    arr\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn basic() {\n        let original = [6, 5, -8, 3, 2, 3];\n        let res = gnome_sort(&original);\n        assert!(is_sorted(&res) && have_same_elements(&res, &original));\n    }\n\n    #[test]\n    fn already_sorted() {\n        let original = gnome_sort(&[\"a\", \"b\", \"c\"]);\n        let res = gnome_sort(&original);\n        assert!(is_sorted(&res) && have_same_elements(&res, &original));\n    }\n\n    #[test]\n    fn odd_number_of_elements() {\n        let original = gnome_sort(&[\"d\", \"a\", \"c\", \"e\", \"b\"]);\n        let res = gnome_sort(&original);\n        assert!(is_sorted(&res) && have_same_elements(&res, &original));\n    }\n\n    #[test]\n    fn one_element() {\n        let original = gnome_sort(&[3]);\n        let res = gnome_sort(&original);\n        assert!(is_sorted(&res) && have_same_elements(&res, &original));\n    }\n\n    #[test]\n    fn empty() {\n        let original = gnome_sort(&Vec::<u8>::new());\n        let res = gnome_sort(&original);\n        assert!(is_sorted(&res) && have_same_elements(&res, &original));\n    }\n}\n"
  },
  {
    "path": "src/sorting/heap_sort.rs",
    "content": "//! This module provides functions for heap sort algorithm.\n\nuse std::cmp::Ordering;\n\n/// Builds a heap from the provided array.\n///\n/// This function builds either a max heap or a min heap based on the `is_max_heap` parameter.\n///\n/// # Arguments\n///\n/// * `arr` - A mutable reference to the array to be sorted.\n/// * `is_max_heap` - A boolean indicating whether to build a max heap (`true`) or a min heap (`false`).\nfn build_heap<T: Ord>(arr: &mut [T], is_max_heap: bool) {\n    let mut i = (arr.len() - 1) / 2;\n    while i > 0 {\n        heapify(arr, i, is_max_heap);\n        i -= 1;\n    }\n    heapify(arr, 0, is_max_heap);\n}\n\n/// Fixes a heap violation starting at the given index.\n///\n/// This function adjusts the heap rooted at index `i` to fix the heap property violation.\n/// It assumes that the subtrees rooted at left and right children of `i` are already heaps.\n///\n/// # Arguments\n///\n/// * `arr` - A mutable reference to the array representing the heap.\n/// * `i` - The index to start fixing the heap violation.\n/// * `is_max_heap` - A boolean indicating whether to maintain a max heap or a min heap.\nfn heapify<T: Ord>(arr: &mut [T], i: usize, is_max_heap: bool) {\n    let comparator: fn(&T, &T) -> Ordering = if is_max_heap {\n        |a, b| a.cmp(b)\n    } else {\n        |a, b| b.cmp(a)\n    };\n\n    let mut idx = i;\n    let l = 2 * i + 1;\n    let r = 2 * i + 2;\n\n    if l < arr.len() && comparator(&arr[l], &arr[idx]) == Ordering::Greater {\n        idx = l;\n    }\n\n    if r < arr.len() && comparator(&arr[r], &arr[idx]) == Ordering::Greater {\n        idx = r;\n    }\n\n    if idx != i {\n        arr.swap(i, idx);\n        heapify(arr, idx, is_max_heap);\n    }\n}\n\n/// Sorts the given array using heap sort algorithm.\n///\n/// This function sorts the array either in ascending or descending order based on the `ascending` parameter.\n///\n/// # Arguments\n///\n/// * `arr` - A mutable reference to the array to be sorted.\n/// * `ascending` - A boolean indicating whether to sort in ascending order (`true`) or descending order (`false`).\npub fn heap_sort<T: Ord>(arr: &mut [T], ascending: bool) {\n    if arr.len() <= 1 {\n        return;\n    }\n\n    // Build heap based on the order\n    build_heap(arr, ascending);\n\n    let mut end = arr.len() - 1;\n    while end > 0 {\n        arr.swap(0, end);\n        heapify(&mut arr[..end], 0, ascending);\n        end -= 1;\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::sorting::{have_same_elements, heap_sort, is_descending_sorted, is_sorted};\n\n    macro_rules! test_heap_sort {\n        ($($name:ident: $input:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let input_array = $input;\n                    let mut arr_asc = input_array.clone();\n                    heap_sort(&mut arr_asc, true);\n                    assert!(is_sorted(&arr_asc) && have_same_elements(&arr_asc, &input_array));\n\n                    let mut arr_dsc = input_array.clone();\n                    heap_sort(&mut arr_dsc, false);\n                    assert!(is_descending_sorted(&arr_dsc) && have_same_elements(&arr_dsc, &input_array));\n                }\n            )*\n        }\n    }\n\n    test_heap_sort! {\n        empty_array: Vec::<i32>::new(),\n        single_element_array: vec![5],\n        sorted: vec![1, 2, 3, 4, 5],\n        sorted_desc: vec![5, 4, 3, 2, 1, 0],\n        basic_0: vec![9, 8, 7, 6, 5],\n        basic_1: vec![8, 3, 1, 5, 7],\n        basic_2: vec![4, 5, 7, 1, 2, 3, 2, 8, 5, 4, 9, 9, 100, 1, 2, 3, 6, 4, 3],\n        duplicated_elements: vec![5, 5, 5, 5, 5],\n        strings: vec![\"aa\", \"a\", \"ba\", \"ab\"],\n    }\n}\n"
  },
  {
    "path": "src/sorting/insertion_sort.rs",
    "content": "/// Sorts a mutable slice using in-place insertion sort algorithm.\n///\n/// Time complexity is `O(n^2)`, where `n` is the number of elements.\n/// Space complexity is `O(1)` as it sorts elements in-place.\npub fn insertion_sort<T: Ord + Copy>(arr: &mut [T]) {\n    for i in 1..arr.len() {\n        let mut j = i;\n        let cur = arr[i];\n\n        while j > 0 && cur < arr[j - 1] {\n            arr[j] = arr[j - 1];\n            j -= 1;\n        }\n\n        arr[j] = cur;\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn empty() {\n        let mut arr: [u8; 0] = [];\n        let cloned = arr;\n        insertion_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n\n    #[test]\n    fn one_element() {\n        let mut arr: [char; 1] = ['a'];\n        let cloned = arr;\n        insertion_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n\n    #[test]\n    fn already_sorted() {\n        let mut arr: [&str; 3] = [\"a\", \"b\", \"c\"];\n        let cloned = arr;\n        insertion_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n\n    #[test]\n    fn basic() {\n        let mut arr: [&str; 4] = [\"d\", \"a\", \"c\", \"b\"];\n        let cloned = arr;\n        insertion_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n\n    #[test]\n    fn odd_number_of_elements() {\n        let mut arr: Vec<&str> = vec![\"d\", \"a\", \"c\", \"e\", \"b\"];\n        let cloned = arr.clone();\n        insertion_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n\n    #[test]\n    fn repeated_elements() {\n        let mut arr: Vec<usize> = vec![542, 542, 542, 542];\n        let cloned = arr.clone();\n        insertion_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/intro_sort.rs",
    "content": "// Intro Sort (Also known as Introspective Sort)\n// Introspective Sort is hybrid sort (Quick Sort + Heap Sort + Insertion Sort)\n// https://en.wikipedia.org/wiki/Introsort\nfn insertion_sort<T: Ord>(arr: &mut [T]) {\n    for i in 1..arr.len() {\n        let mut j = i;\n        while j > 0 && arr[j] < arr[j - 1] {\n            arr.swap(j, j - 1);\n            j -= 1;\n        }\n    }\n}\n\nfn heapify<T: Ord>(arr: &mut [T], n: usize, i: usize) {\n    let mut largest = i;\n    let left = 2 * i + 1;\n    let right = 2 * i + 2;\n\n    if left < n && arr[left] > arr[largest] {\n        largest = left;\n    }\n\n    if right < n && arr[right] > arr[largest] {\n        largest = right;\n    }\n\n    if largest != i {\n        arr.swap(i, largest);\n        heapify(arr, n, largest);\n    }\n}\n\nfn heap_sort<T: Ord>(arr: &mut [T]) {\n    let n = arr.len();\n\n    // Build a max-heap\n    for i in (0..n / 2).rev() {\n        heapify(arr, n, i);\n    }\n\n    // Extract elements from the heap one by one\n    for i in (0..n).rev() {\n        arr.swap(0, i);\n        heapify(arr, i, 0);\n    }\n}\n\npub fn intro_sort<T: Ord>(arr: &mut [T]) {\n    let len = arr.len();\n    let max_depth = (2.0 * len as f64).log2() as usize + 1;\n\n    fn intro_sort_recursive<T: Ord>(arr: &mut [T], max_depth: usize) {\n        let len = arr.len();\n\n        if len <= 16 {\n            insertion_sort(arr);\n        } else if max_depth == 0 {\n            heap_sort(arr);\n        } else {\n            let pivot = partition(arr);\n            intro_sort_recursive(&mut arr[..pivot], max_depth - 1);\n            intro_sort_recursive(&mut arr[pivot + 1..], max_depth - 1);\n        }\n    }\n\n    fn partition<T: Ord>(arr: &mut [T]) -> usize {\n        let len = arr.len();\n        let pivot_index = len / 2;\n        arr.swap(pivot_index, len - 1);\n\n        let mut i = 0;\n        for j in 0..len - 1 {\n            if arr[j] <= arr[len - 1] {\n                arr.swap(i, j);\n                i += 1;\n            }\n        }\n\n        arr.swap(i, len - 1);\n        i\n    }\n\n    intro_sort_recursive(arr, max_depth);\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_intro_sort() {\n        // Test with integers\n        let mut arr1 = vec![67, 34, 29, 15, 21, 9, 99];\n        intro_sort(&mut arr1);\n        assert_eq!(arr1, vec![9, 15, 21, 29, 34, 67, 99]);\n\n        // Test with strings\n        let mut arr2 = vec![\"sydney\", \"london\", \"tokyo\", \"beijing\", \"mumbai\"];\n        intro_sort(&mut arr2);\n        assert_eq!(arr2, vec![\"beijing\", \"london\", \"mumbai\", \"sydney\", \"tokyo\"]);\n\n        // Test with an empty array\n        let mut arr3: Vec<i32> = vec![];\n        intro_sort(&mut arr3);\n        assert_eq!(arr3, vec![]);\n    }\n}\n"
  },
  {
    "path": "src/sorting/merge_sort.rs",
    "content": "fn merge<T: Ord + Copy>(arr: &mut [T], mid: usize) {\n    // Create temporary vectors to support the merge.\n    let left_half = arr[..mid].to_vec();\n    let right_half = arr[mid..].to_vec();\n\n    // Indexes to track the positions while merging.\n    let mut l = 0;\n    let mut r = 0;\n\n    for v in arr {\n        // Choose either the smaller element, or from whichever vec is not exhausted.\n        if r == right_half.len() || (l < left_half.len() && left_half[l] < right_half[r]) {\n            *v = left_half[l];\n            l += 1;\n        } else {\n            *v = right_half[r];\n            r += 1;\n        }\n    }\n}\n\npub fn top_down_merge_sort<T: Ord + Copy>(arr: &mut [T]) {\n    if arr.len() > 1 {\n        let mid = arr.len() / 2;\n        // Sort the left half recursively.\n        top_down_merge_sort(&mut arr[..mid]);\n        // Sort the right half recursively.\n        top_down_merge_sort(&mut arr[mid..]);\n        // Combine the two halves.\n        merge(arr, mid);\n    }\n}\n\npub fn bottom_up_merge_sort<T: Copy + Ord>(a: &mut [T]) {\n    if a.len() > 1 {\n        let len: usize = a.len();\n        let mut sub_array_size: usize = 1;\n        while sub_array_size < len {\n            let mut start_index: usize = 0;\n            // still have more than one sub-arrays to merge\n            while len - start_index > sub_array_size {\n                let end_idx: usize = if start_index + 2 * sub_array_size > len {\n                    len\n                } else {\n                    start_index + 2 * sub_array_size\n                };\n                // merge a[start_index..start_index+sub_array_size] and a[start_index+sub_array_size..end_idx]\n                // NOTE: mid is a relative index number starting from `start_index`\n                merge(&mut a[start_index..end_idx], sub_array_size);\n                // update `start_index` to merge the next sub-arrays\n                start_index = end_idx;\n            }\n            sub_array_size *= 2;\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    #[cfg(test)]\n    mod top_down_merge_sort {\n        use super::super::*;\n        use crate::sorting::have_same_elements;\n        use crate::sorting::is_sorted;\n\n        #[test]\n        fn basic() {\n            let mut res = vec![10, 8, 4, 3, 1, 9, 2, 7, 5, 6];\n            let cloned = res.clone();\n            top_down_merge_sort(&mut res);\n            assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n        }\n\n        #[test]\n        fn basic_string() {\n            let mut res = vec![\"a\", \"bb\", \"d\", \"cc\"];\n            let cloned = res.clone();\n            top_down_merge_sort(&mut res);\n            assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n        }\n\n        #[test]\n        fn empty() {\n            let mut res = Vec::<u8>::new();\n            let cloned = res.clone();\n            top_down_merge_sort(&mut res);\n            assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n        }\n\n        #[test]\n        fn one_element() {\n            let mut res = vec![1];\n            let cloned = res.clone();\n            top_down_merge_sort(&mut res);\n            assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n        }\n\n        #[test]\n        fn pre_sorted() {\n            let mut res = vec![1, 2, 3, 4];\n            let cloned = res.clone();\n            top_down_merge_sort(&mut res);\n            assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n        }\n\n        #[test]\n        fn reverse_sorted() {\n            let mut res = vec![4, 3, 2, 1];\n            let cloned = res.clone();\n            top_down_merge_sort(&mut res);\n            assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n        }\n    }\n\n    #[cfg(test)]\n    mod bottom_up_merge_sort {\n        use super::super::*;\n        use crate::sorting::have_same_elements;\n        use crate::sorting::is_sorted;\n\n        #[test]\n        fn basic() {\n            let mut res = vec![10, 8, 4, 3, 1, 9, 2, 7, 5, 6];\n            let cloned = res.clone();\n            bottom_up_merge_sort(&mut res);\n            assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n        }\n\n        #[test]\n        fn basic_string() {\n            let mut res = vec![\"a\", \"bb\", \"d\", \"cc\"];\n            let cloned = res.clone();\n            bottom_up_merge_sort(&mut res);\n            assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n        }\n\n        #[test]\n        fn empty() {\n            let mut res = Vec::<u8>::new();\n            let cloned = res.clone();\n            bottom_up_merge_sort(&mut res);\n            assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n        }\n\n        #[test]\n        fn one_element() {\n            let mut res = vec![1];\n            let cloned = res.clone();\n            bottom_up_merge_sort(&mut res);\n            assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n        }\n\n        #[test]\n        fn pre_sorted() {\n            let mut res = vec![1, 2, 3, 4];\n            let cloned = res.clone();\n            bottom_up_merge_sort(&mut res);\n            assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n        }\n\n        #[test]\n        fn reverse_sorted() {\n            let mut res = vec![4, 3, 2, 1];\n            let cloned = res.clone();\n            bottom_up_merge_sort(&mut res);\n            assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n        }\n    }\n}\n"
  },
  {
    "path": "src/sorting/mod.rs",
    "content": "mod bead_sort;\nmod binary_insertion_sort;\nmod bingo_sort;\nmod bitonic_sort;\nmod bogo_sort;\nmod bubble_sort;\nmod bucket_sort;\nmod cocktail_shaker_sort;\nmod comb_sort;\nmod counting_sort;\nmod cycle_sort;\nmod dutch_national_flag_sort;\nmod exchange_sort;\nmod gnome_sort;\nmod heap_sort;\nmod insertion_sort;\nmod intro_sort;\nmod merge_sort;\nmod odd_even_sort;\nmod pancake_sort;\nmod patience_sort;\nmod pigeonhole_sort;\nmod quick_sort;\nmod quick_sort_3_ways;\nmod radix_sort;\nmod selection_sort;\nmod shell_sort;\nmod sleep_sort;\n#[cfg(test)]\nmod sort_utils;\nmod stooge_sort;\nmod tim_sort;\nmod tree_sort;\nmod wave_sort;\nmod wiggle_sort;\n\npub use self::bead_sort::bead_sort;\npub use self::binary_insertion_sort::binary_insertion_sort;\npub use self::bingo_sort::bingo_sort;\npub use self::bitonic_sort::bitonic_sort;\npub use self::bogo_sort::bogo_sort;\npub use self::bubble_sort::bubble_sort;\npub use self::bucket_sort::bucket_sort;\npub use self::cocktail_shaker_sort::cocktail_shaker_sort;\npub use self::comb_sort::comb_sort;\npub use self::counting_sort::counting_sort;\npub use self::counting_sort::generic_counting_sort;\npub use self::cycle_sort::cycle_sort;\npub use self::dutch_national_flag_sort::dutch_national_flag_sort;\npub use self::exchange_sort::exchange_sort;\npub use self::gnome_sort::gnome_sort;\npub use self::heap_sort::heap_sort;\npub use self::insertion_sort::insertion_sort;\npub use self::intro_sort::intro_sort;\npub use self::merge_sort::bottom_up_merge_sort;\npub use self::merge_sort::top_down_merge_sort;\npub use self::odd_even_sort::odd_even_sort;\npub use self::pancake_sort::pancake_sort;\npub use self::patience_sort::patience_sort;\npub use self::pigeonhole_sort::pigeonhole_sort;\npub use self::quick_sort::{partition, quick_sort};\npub use self::quick_sort_3_ways::quick_sort_3_ways;\npub use self::radix_sort::radix_sort;\npub use self::selection_sort::selection_sort;\npub use self::shell_sort::shell_sort;\npub use self::sleep_sort::sleep_sort;\npub use self::stooge_sort::stooge_sort;\npub use self::tim_sort::tim_sort;\npub use self::tree_sort::tree_sort;\npub use self::wave_sort::wave_sort;\npub use self::wiggle_sort::wiggle_sort;\n\n#[cfg(test)]\nuse std::cmp;\n\n#[cfg(test)]\npub fn have_same_elements<T>(a: &[T], b: &[T]) -> bool\nwhere\n    // T: cmp::PartialOrd,\n    // If HashSet is used\n    T: cmp::PartialOrd + cmp::Eq + std::hash::Hash,\n{\n    use std::collections::HashSet;\n\n    if a.len() == b.len() {\n        // This is O(n^2) but performs better on smaller data sizes\n        //b.iter().all(|item| a.contains(item))\n\n        // This is O(n), performs well on larger data sizes\n        let set_a: HashSet<&T> = a.iter().collect();\n        let set_b: HashSet<&T> = b.iter().collect();\n        set_a == set_b\n    } else {\n        false\n    }\n}\n\n#[cfg(test)]\npub fn is_sorted<T>(arr: &[T]) -> bool\nwhere\n    T: cmp::PartialOrd,\n{\n    arr.windows(2).all(|w| w[0] <= w[1])\n}\n\n#[cfg(test)]\npub fn is_descending_sorted<T>(arr: &[T]) -> bool\nwhere\n    T: cmp::PartialOrd,\n{\n    arr.windows(2).all(|w| w[0] >= w[1])\n}\n\n#[cfg(test)]\nmod tests {\n    #[test]\n    fn is_sorted() {\n        use super::*;\n\n        assert!(is_sorted(&[] as &[isize]));\n        assert!(is_sorted(&[\"a\"]));\n        assert!(is_sorted(&[1, 2, 3]));\n        assert!(is_sorted(&[0, 1, 1]));\n\n        assert!(!is_sorted(&[1, 0]));\n        assert!(!is_sorted(&[2, 3, 1, -1, 5]));\n    }\n}\n"
  },
  {
    "path": "src/sorting/odd_even_sort.rs",
    "content": "pub fn odd_even_sort<T: Ord>(arr: &mut [T]) {\n    let len = arr.len();\n    if len == 0 {\n        return;\n    }\n\n    let mut sorted = false;\n    while !sorted {\n        sorted = true;\n\n        for i in (1..len - 1).step_by(2) {\n            if arr[i] > arr[i + 1] {\n                arr.swap(i, i + 1);\n                sorted = false;\n            }\n        }\n\n        for i in (0..len - 1).step_by(2) {\n            if arr[i] > arr[i + 1] {\n                arr.swap(i, i + 1);\n                sorted = false;\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn basic() {\n        let mut arr = vec![3, 5, 1, 2, 4, 6];\n        let cloned = arr.clone();\n        odd_even_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n\n    #[test]\n    fn empty() {\n        let mut arr = Vec::<i32>::new();\n        let cloned = arr.clone();\n        odd_even_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n\n    #[test]\n    fn one_element() {\n        let mut arr = vec![3];\n        let cloned = arr.clone();\n        odd_even_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n\n    #[test]\n    fn pre_sorted() {\n        let mut arr = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n        let cloned = arr.clone();\n        odd_even_sort(&mut arr);\n        assert!(is_sorted(&arr) && have_same_elements(&arr, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/pancake_sort.rs",
    "content": "use std::cmp;\n\npub fn pancake_sort<T>(arr: &mut [T]) -> Vec<T>\nwhere\n    T: cmp::PartialEq + cmp::Ord + cmp::PartialOrd + Clone,\n{\n    let len = arr.len();\n    if len < 2 {\n        arr.to_vec();\n    }\n    for i in (0..len).rev() {\n        let max_index = arr\n            .iter()\n            .take(i + 1)\n            .enumerate()\n            .max_by_key(|&(_, elem)| elem)\n            .map(|(idx, _)| idx)\n            .unwrap();\n        if max_index != i {\n            arr[0..=max_index].reverse();\n            arr[0..=i].reverse();\n        }\n    }\n    arr.to_vec()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn basic() {\n        let res = pancake_sort(&mut [6, 5, -8, 3, 2, 3]);\n        assert_eq!(res, vec![-8, 2, 3, 3, 5, 6]);\n    }\n\n    #[test]\n    fn already_sorted() {\n        let res = pancake_sort(&mut [\"a\", \"b\", \"c\"]);\n        assert_eq!(res, vec![\"a\", \"b\", \"c\"]);\n    }\n\n    #[test]\n    fn odd_number_of_elements() {\n        let res = pancake_sort(&mut [\"d\", \"a\", \"c\", \"e\", \"b\"]);\n        assert_eq!(res, vec![\"a\", \"b\", \"c\", \"d\", \"e\"]);\n    }\n\n    #[test]\n    fn one_element() {\n        let res = pancake_sort(&mut [3]);\n        assert_eq!(res, vec![3]);\n    }\n\n    #[test]\n    fn empty() {\n        let res = pancake_sort(&mut [] as &mut [u8]);\n        assert_eq!(res, vec![]);\n    }\n}\n"
  },
  {
    "path": "src/sorting/patience_sort.rs",
    "content": "use std::vec;\n\npub fn patience_sort<T: Ord + Copy>(arr: &mut [T]) {\n    if arr.is_empty() {\n        return;\n    }\n\n    // collect piles from arr\n    let mut piles: Vec<Vec<T>> = Vec::new();\n    for &card in arr.iter() {\n        let mut left = 0usize;\n        let mut right = piles.len();\n\n        while left < right {\n            let mid = left + (right - left) / 2;\n            if piles[mid][piles[mid].len() - 1] >= card {\n                right = mid;\n            } else {\n                left = mid + 1;\n            }\n        }\n\n        if left == piles.len() {\n            piles.push(vec![card]);\n        } else {\n            piles[left].push(card);\n        }\n    }\n\n    // merge the piles\n    let mut idx = 0usize;\n    while let Some((min_id, pile)) = piles\n        .iter()\n        .enumerate()\n        .min_by_key(|(_, pile)| *pile.last().unwrap())\n    {\n        arr[idx] = *pile.last().unwrap();\n        idx += 1;\n        piles[min_id].pop();\n\n        if piles[min_id].is_empty() {\n            _ = piles.remove(min_id);\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn basic() {\n        let mut array = vec![\n            -2, 7, 15, -14, 0, 15, 0, 10_033, 7, -7, -4, -13, 5, 8, -14, 12,\n        ];\n        let cloned = array.clone();\n        patience_sort(&mut array);\n        assert!(is_sorted(&array) && have_same_elements(&array, &cloned));\n    }\n\n    #[test]\n    fn empty() {\n        let mut array = Vec::<i32>::new();\n        let cloned = array.clone();\n        patience_sort(&mut array);\n        assert!(is_sorted(&array) && have_same_elements(&array, &cloned));\n    }\n\n    #[test]\n    fn one_element() {\n        let mut array = vec![3];\n        let cloned = array.clone();\n        patience_sort(&mut array);\n        assert!(is_sorted(&array) && have_same_elements(&array, &cloned));\n    }\n\n    #[test]\n    fn pre_sorted() {\n        let mut array = vec![-123_456, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n        let cloned = array.clone();\n        patience_sort(&mut array);\n        assert!(is_sorted(&array) && have_same_elements(&array, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/pigeonhole_sort.rs",
    "content": "// From Wikipedia: Pigeonhole sorting is a sorting algorithm that is suitable for sorting lists of elements where the number of elements (n) and the length of the range of possible key values (N) are approximately the same. It requires O(n + N) time.\n\npub fn pigeonhole_sort(array: &mut [i32]) {\n    if let (Some(min), Some(max)) = (array.iter().min(), array.iter().max()) {\n        let holes_range: usize = (max - min + 1) as usize;\n        let mut holes = vec![0; holes_range];\n        let mut holes_repeat = vec![0; holes_range];\n        for i in array.iter() {\n            let index = *i - min;\n            holes[index as usize] = *i;\n            holes_repeat[index as usize] += 1;\n        }\n        let mut index = 0;\n        for i in 0..holes_range {\n            while holes_repeat[i] > 0 {\n                array[index] = holes[i];\n                index += 1;\n                holes_repeat[i] -= 1;\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::super::is_sorted;\n    use super::*;\n\n    #[test]\n    fn test1() {\n        let mut arr1 = [3, 3, 3, 1, 2, 6, 5, 5, 5, 4, 1, 6, 3];\n        pigeonhole_sort(&mut arr1);\n        assert!(is_sorted(&arr1));\n        let mut arr2 = [6, 5, 4, 3, 2, 1];\n        pigeonhole_sort(&mut arr2);\n        assert!(is_sorted(&arr2));\n    }\n}\n"
  },
  {
    "path": "src/sorting/quick_sort.rs",
    "content": "pub fn partition<T: PartialOrd>(arr: &mut [T], lo: usize, hi: usize) -> usize {\n    let pivot = hi;\n    let mut i = lo;\n    let mut j = hi - 1;\n\n    loop {\n        while arr[i] < arr[pivot] {\n            i += 1;\n        }\n        while j > 0 && arr[j] > arr[pivot] {\n            j -= 1;\n        }\n        if j == 0 || i >= j {\n            break;\n        } else if arr[i] == arr[j] {\n            i += 1;\n            j -= 1;\n        } else {\n            arr.swap(i, j);\n        }\n    }\n    arr.swap(i, pivot);\n    i\n}\n\nfn _quick_sort<T: Ord>(arr: &mut [T], mut lo: usize, mut hi: usize) {\n    while lo < hi {\n        let pivot = partition(arr, lo, hi);\n\n        if pivot - lo < hi - pivot {\n            if pivot > 0 {\n                _quick_sort(arr, lo, pivot - 1);\n            }\n            lo = pivot + 1;\n        } else {\n            _quick_sort(arr, pivot + 1, hi);\n            hi = pivot - 1;\n        }\n    }\n}\n\npub fn quick_sort<T: Ord>(arr: &mut [T]) {\n    let len = arr.len();\n    if len > 1 {\n        _quick_sort(arr, 0, len - 1);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n    use crate::sorting::sort_utils;\n\n    #[test]\n    fn basic() {\n        let mut res = vec![10, 8, 4, 3, 1, 9, 2, 7, 5, 6];\n        let cloned = res.clone();\n        quick_sort(&mut res);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn basic_string() {\n        let mut res = vec![\"a\", \"bb\", \"d\", \"cc\"];\n        let cloned = res.clone();\n        quick_sort(&mut res);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn empty() {\n        let mut res = Vec::<u8>::new();\n        let cloned = res.clone();\n        quick_sort(&mut res);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn one_element() {\n        let mut res = vec![1];\n        let cloned = res.clone();\n        quick_sort(&mut res);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn pre_sorted() {\n        let mut res = vec![1, 2, 3, 4];\n        let cloned = res.clone();\n        quick_sort(&mut res);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn reverse_sorted() {\n        let mut res = vec![4, 3, 2, 1];\n        let cloned = res.clone();\n        quick_sort(&mut res);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn large_elements() {\n        let mut res = sort_utils::generate_random_vec(300000, 0, 1000000);\n        let cloned = res.clone();\n        sort_utils::log_timed(\"large elements test\", || {\n            quick_sort(&mut res);\n        });\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn nearly_ordered_elements() {\n        let mut res = sort_utils::generate_nearly_ordered_vec(3000, 10);\n        let cloned = res.clone();\n\n        sort_utils::log_timed(\"nearly ordered elements test\", || {\n            quick_sort(&mut res);\n        });\n\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn repeated_elements() {\n        let mut res = sort_utils::generate_repeated_elements_vec(1000000, 3);\n        let cloned = res.clone();\n\n        sort_utils::log_timed(\"repeated elements test\", || {\n            quick_sort(&mut res);\n        });\n\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/quick_sort_3_ways.rs",
    "content": "use std::cmp::{Ord, Ordering};\n\nuse rand::RngExt;\n\nfn _quick_sort_3_ways<T: Ord>(arr: &mut [T], lo: usize, hi: usize) {\n    if lo >= hi {\n        return;\n    }\n\n    let mut rng = rand::rng();\n    arr.swap(lo, rng.random_range(lo..=hi));\n\n    let mut lt = lo; // arr[lo+1, lt] < v\n    let mut gt = hi + 1; // arr[gt, r] > v\n    let mut i = lo + 1; // arr[lt + 1, i) == v\n\n    while i < gt {\n        match arr[i].cmp(&arr[lo]) {\n            Ordering::Less => {\n                arr.swap(i, lt + 1);\n                i += 1;\n                lt += 1;\n            }\n            Ordering::Greater => {\n                arr.swap(i, gt - 1);\n                gt -= 1;\n            }\n            Ordering::Equal => {\n                i += 1;\n            }\n        }\n    }\n\n    arr.swap(lo, lt);\n\n    if lt > 1 {\n        _quick_sort_3_ways(arr, lo, lt - 1);\n    }\n\n    _quick_sort_3_ways(arr, gt, hi);\n}\n\npub fn quick_sort_3_ways<T: Ord>(arr: &mut [T]) {\n    let len = arr.len();\n    if len > 1 {\n        _quick_sort_3_ways(arr, 0, len - 1);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n    use crate::sorting::sort_utils;\n\n    #[test]\n    fn basic() {\n        let mut res = vec![10, 8, 4, 3, 1, 9, 2, 7, 5, 6];\n        let cloned = res.clone();\n        sort_utils::log_timed(\"basic\", || {\n            quick_sort_3_ways(&mut res);\n        });\n\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn basic_string() {\n        let mut res = vec![\"a\", \"bb\", \"d\", \"cc\"];\n        let cloned = res.clone();\n        sort_utils::log_timed(\"basic string\", || {\n            quick_sort_3_ways(&mut res);\n        });\n\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn empty() {\n        let mut res = Vec::<u8>::new();\n        let cloned = res.clone();\n        sort_utils::log_timed(\"empty\", || {\n            quick_sort_3_ways(&mut res);\n        });\n\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn one_element() {\n        let mut res = sort_utils::generate_random_vec(1, 0, 1);\n        let cloned = res.clone();\n        sort_utils::log_timed(\"one element\", || {\n            quick_sort_3_ways(&mut res);\n        });\n\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn pre_sorted() {\n        let mut res = sort_utils::generate_nearly_ordered_vec(300000, 0);\n        let cloned = res.clone();\n        sort_utils::log_timed(\"pre sorted\", || {\n            quick_sort_3_ways(&mut res);\n        });\n\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn reverse_sorted() {\n        let mut res = sort_utils::generate_reverse_ordered_vec(300000);\n        let cloned = res.clone();\n        sort_utils::log_timed(\"reverse sorted\", || {\n            quick_sort_3_ways(&mut res);\n        });\n\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn large_elements() {\n        let mut res = sort_utils::generate_random_vec(300000, 0, 1000000);\n        let cloned = res.clone();\n        sort_utils::log_timed(\"large elements test\", || {\n            quick_sort_3_ways(&mut res);\n        });\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn nearly_ordered_elements() {\n        let mut res = sort_utils::generate_nearly_ordered_vec(300000, 10);\n        let cloned = res.clone();\n\n        sort_utils::log_timed(\"nearly ordered elements test\", || {\n            quick_sort_3_ways(&mut res);\n        });\n\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn repeated_elements() {\n        let mut res = sort_utils::generate_repeated_elements_vec(1000000, 3);\n        let cloned = res.clone();\n\n        sort_utils::log_timed(\"repeated elements test\", || {\n            quick_sort_3_ways(&mut res);\n        });\n\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/radix_sort.rs",
    "content": "/// Sorts the elements of `arr` in-place using radix sort.\n///\n/// Time complexity is `O((n + b) * logb(k))`, where `n` is the number of elements,\n/// `b` is the base (the radix), and `k` is the largest element.\n/// When `n` and `b` are roughly the same maginitude, this algorithm runs in linear time.\n///\n/// Space complexity is `O(n + b)`.\npub fn radix_sort(arr: &mut [u64]) {\n    let max: usize = match arr.iter().max() {\n        Some(&x) => x as usize,\n        None => return,\n    };\n    // Make radix a power of 2 close to arr.len() for optimal runtime\n    let radix = arr.len().next_power_of_two();\n    // Counting sort by each digit from least to most significant\n    let mut place = 1;\n    while place <= max {\n        let digit_of = |x| x as usize / place % radix;\n        // Count digit occurrences\n        let mut counter = vec![0; radix];\n        for &x in arr.iter() {\n            counter[digit_of(x)] += 1;\n        }\n        // Compute last index of each digit\n        for i in 1..radix {\n            counter[i] += counter[i - 1];\n        }\n        // Write elements to their new indices\n        for &x in arr.to_owned().iter().rev() {\n            counter[digit_of(x)] -= 1;\n            arr[counter[digit_of(x)]] = x;\n        }\n        place *= radix;\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::radix_sort;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn empty() {\n        let mut a: [u64; 0] = [];\n        let cloned = a;\n        radix_sort(&mut a);\n        assert!(is_sorted(&a) && have_same_elements(&a, &cloned));\n    }\n\n    #[test]\n    fn descending() {\n        let mut v = vec![201, 127, 64, 37, 24, 4, 1];\n        let cloned = v.clone();\n        radix_sort(&mut v);\n        assert!(is_sorted(&v) && have_same_elements(&v, &cloned));\n    }\n\n    #[test]\n    fn ascending() {\n        let mut v = vec![1, 4, 24, 37, 64, 127, 201];\n        let cloned = v.clone();\n        radix_sort(&mut v);\n        assert!(is_sorted(&v) && have_same_elements(&v, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/selection_sort.rs",
    "content": "pub fn selection_sort<T: Ord>(arr: &mut [T]) {\n    let len = arr.len();\n    for left in 0..len {\n        let mut smallest = left;\n        for right in (left + 1)..len {\n            if arr[right] < arr[smallest] {\n                smallest = right;\n            }\n        }\n        arr.swap(smallest, left);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn basic() {\n        let mut res = vec![\"d\", \"a\", \"c\", \"b\"];\n        let cloned = res.clone();\n        selection_sort(&mut res);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn empty() {\n        let mut res = Vec::<u8>::new();\n        let cloned = res.clone();\n        selection_sort(&mut res);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn one_element() {\n        let mut res = vec![\"a\"];\n        let cloned = res.clone();\n        selection_sort(&mut res);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n\n    #[test]\n    fn pre_sorted() {\n        let mut res = vec![\"a\", \"b\", \"c\"];\n        let cloned = res.clone();\n        selection_sort(&mut res);\n        assert!(is_sorted(&res) && have_same_elements(&res, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/shell_sort.rs",
    "content": "pub fn shell_sort<T: Ord + Copy>(values: &mut [T]) {\n    // shell sort works by swiping the value at a given gap and decreasing the gap to 1\n    fn insertion<T: Ord + Copy>(values: &mut [T], start: usize, gap: usize) {\n        for i in ((start + gap)..values.len()).step_by(gap) {\n            let val_current = values[i];\n            let mut pos = i;\n            // make swaps\n            while pos >= gap && values[pos - gap] > val_current {\n                values[pos] = values[pos - gap];\n                pos -= gap;\n            }\n            values[pos] = val_current;\n        }\n    }\n\n    let mut count_sublist = values.len() / 2; // makes gap as long as half of the array\n    while count_sublist > 0 {\n        for pos_start in 0..count_sublist {\n            insertion(values, pos_start, count_sublist);\n        }\n        count_sublist /= 2; // makes gap as half of previous\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::shell_sort;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn basic() {\n        let mut vec = vec![3, 5, 6, 3, 1, 4];\n        let cloned = vec.clone();\n        shell_sort(&mut vec);\n        assert!(is_sorted(&vec) && have_same_elements(&vec, &cloned));\n    }\n\n    #[test]\n    fn empty() {\n        let mut vec: Vec<i32> = vec![];\n        let cloned = vec.clone();\n        shell_sort(&mut vec);\n        assert!(is_sorted(&vec) && have_same_elements(&vec, &cloned));\n    }\n\n    #[test]\n    fn reverse() {\n        let mut vec = vec![6, 5, 4, 3, 2, 1];\n        let cloned = vec.clone();\n        shell_sort(&mut vec);\n        assert!(is_sorted(&vec) && have_same_elements(&vec, &cloned));\n    }\n\n    #[test]\n    fn already_sorted() {\n        let mut vec = vec![1, 2, 3, 4, 5, 6];\n        let cloned = vec.clone();\n        shell_sort(&mut vec);\n        assert!(is_sorted(&vec) && have_same_elements(&vec, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/sleep_sort.rs",
    "content": "use std::sync::mpsc;\nuse std::thread;\nuse std::time::Duration;\n\npub fn sleep_sort(vec: &[usize]) -> Vec<usize> {\n    let len = vec.len();\n    let (tx, rx) = mpsc::channel();\n\n    for &x in vec.iter() {\n        let tx: mpsc::Sender<usize> = tx.clone();\n        thread::spawn(move || {\n            thread::sleep(Duration::from_millis((20 * x) as u64));\n            tx.send(x).expect(\"panic\");\n        });\n    }\n    let mut sorted_list: Vec<usize> = Vec::new();\n\n    for _ in 0..len {\n        sorted_list.push(rx.recv().unwrap())\n    }\n\n    sorted_list\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn empty() {\n        let res = sleep_sort(&[]);\n        assert_eq!(res, &[]);\n    }\n\n    #[test]\n    fn single_element() {\n        let res = sleep_sort(&[1]);\n        assert_eq!(res, &[1]);\n    }\n\n    #[test]\n    fn sorted_array() {\n        let res = sleep_sort(&[1, 2, 3, 4]);\n        assert_eq!(res, &[1, 2, 3, 4]);\n    }\n\n    #[test]\n    fn unsorted_array() {\n        let res = sleep_sort(&[3, 4, 2, 1]);\n        assert_eq!(res, &[1, 2, 3, 4]);\n    }\n\n    #[test]\n    fn odd_number_of_elements() {\n        let res = sleep_sort(&[3, 1, 7]);\n        assert_eq!(res, &[1, 3, 7]);\n    }\n\n    #[test]\n    fn repeated_elements() {\n        let res = sleep_sort(&[1, 1, 1, 1]);\n        assert_eq!(res, &[1, 1, 1, 1]);\n    }\n\n    #[test]\n    fn random_elements() {\n        let res = sleep_sort(&[5, 3, 7, 10, 1, 0, 8]);\n        assert_eq!(res, &[0, 1, 3, 5, 7, 8, 10]);\n    }\n}\n"
  },
  {
    "path": "src/sorting/sort_utils.rs",
    "content": "use rand::RngExt;\nuse std::time::Instant;\n\n#[cfg(test)]\npub fn generate_random_vec(n: u32, range_l: i32, range_r: i32) -> Vec<i32> {\n    let mut arr = Vec::<i32>::with_capacity(n as usize);\n    let mut rng = rand::rng();\n    let mut count = n;\n\n    while count > 0 {\n        arr.push(rng.random_range(range_l..=range_r));\n        count -= 1;\n    }\n\n    arr\n}\n\n#[cfg(test)]\npub fn generate_nearly_ordered_vec(n: u32, swap_times: u32) -> Vec<i32> {\n    let mut arr: Vec<i32> = (0..n as i32).collect();\n    let mut rng = rand::rng();\n\n    let mut count = swap_times;\n\n    while count > 0 {\n        arr.swap(\n            rng.random_range(0..n as usize),\n            rng.random_range(0..n as usize),\n        );\n        count -= 1;\n    }\n\n    arr\n}\n\n#[cfg(test)]\npub fn generate_ordered_vec(n: u32) -> Vec<i32> {\n    generate_nearly_ordered_vec(n, 0)\n}\n\n#[cfg(test)]\npub fn generate_reverse_ordered_vec(n: u32) -> Vec<i32> {\n    let mut arr = generate_ordered_vec(n);\n    arr.reverse();\n    arr\n}\n\n#[cfg(test)]\npub fn generate_repeated_elements_vec(n: u32, unique_elements: u8) -> Vec<i32> {\n    let mut rng = rand::rng();\n    let v = rng.random_range(0..n as i32);\n    generate_random_vec(n, v, v + unique_elements as i32)\n}\n\n#[cfg(test)]\npub fn log_timed<F>(test_name: &str, f: F)\nwhere\n    F: FnOnce(),\n{\n    let before = Instant::now();\n    f();\n    println!(\"Elapsed time of {:?} is {:?}\", test_name, before.elapsed());\n}\n"
  },
  {
    "path": "src/sorting/stooge_sort.rs",
    "content": "fn _stooge_sort<T: Ord>(arr: &mut [T], start: usize, end: usize) {\n    if arr[start] > arr[end] {\n        arr.swap(start, end);\n    }\n\n    if start + 1 >= end {\n        return;\n    }\n\n    let k = (end - start + 1) / 3;\n\n    _stooge_sort(arr, start, end - k);\n    _stooge_sort(arr, start + k, end);\n    _stooge_sort(arr, start, end - k);\n}\n\npub fn stooge_sort<T: Ord>(arr: &mut [T]) {\n    let len = arr.len();\n    if len == 0 {\n        return;\n    }\n\n    _stooge_sort(arr, 0, len - 1);\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use crate::sorting::have_same_elements;\n    use crate::sorting::is_sorted;\n\n    #[test]\n    fn basic() {\n        let mut vec = vec![3, 5, 6, 3, 1, 4];\n        let cloned = vec.clone();\n        stooge_sort(&mut vec);\n        assert!(is_sorted(&vec) && have_same_elements(&vec, &cloned));\n    }\n\n    #[test]\n    fn empty() {\n        let mut vec: Vec<i32> = vec![];\n        let cloned = vec.clone();\n        stooge_sort(&mut vec);\n        assert!(is_sorted(&vec) && have_same_elements(&vec, &cloned));\n    }\n\n    #[test]\n    fn reverse() {\n        let mut vec = vec![6, 5, 4, 3, 2, 1];\n        let cloned = vec.clone();\n        stooge_sort(&mut vec);\n        assert!(is_sorted(&vec) && have_same_elements(&vec, &cloned));\n    }\n\n    #[test]\n    fn already_sorted() {\n        let mut vec = vec![1, 2, 3, 4, 5, 6];\n        let cloned = vec.clone();\n        stooge_sort(&mut vec);\n        assert!(is_sorted(&vec) && have_same_elements(&vec, &cloned));\n    }\n}\n"
  },
  {
    "path": "src/sorting/tim_sort.rs",
    "content": "//! Implements Tim sort algorithm.\n//!\n//! Tim sort is a hybrid sorting algorithm derived from merge sort and insertion sort.\n//! It is designed to perform well on many kinds of real-world data.\n\nuse crate::sorting::insertion_sort;\nuse std::cmp;\n\nstatic MIN_MERGE: usize = 32;\n\n/// Calculates the minimum run length for Tim sort based on the length of the array.\n///\n/// The minimum run length is determined using a heuristic that ensures good performance.\n///\n/// # Arguments\n///\n/// * `array_length` - The length of the array.\n///\n/// # Returns\n///\n/// The minimum run length.\nfn compute_min_run_length(array_length: usize) -> usize {\n    let mut remaining_length = array_length;\n    let mut result = 0;\n\n    while remaining_length >= MIN_MERGE {\n        result |= remaining_length & 1;\n        remaining_length >>= 1;\n    }\n\n    remaining_length + result\n}\n\n/// Merges two sorted subarrays into a single sorted subarray.\n///\n/// This function merges two sorted subarrays of the provided slice into a single sorted subarray.\n///\n/// # Arguments\n///\n/// * `arr` - The slice containing the subarrays to be merged.\n/// * `left` - The starting index of the first subarray.\n/// * `mid` - The ending index of the first subarray.\n/// * `right` - The ending index of the second subarray.\nfn merge<T: Ord + Copy>(arr: &mut [T], left: usize, mid: usize, right: usize) {\n    let left_slice = arr[left..=mid].to_vec();\n    let right_slice = arr[mid + 1..=right].to_vec();\n    let mut i = 0;\n    let mut j = 0;\n    let mut k = left;\n\n    while i < left_slice.len() && j < right_slice.len() {\n        if left_slice[i] <= right_slice[j] {\n            arr[k] = left_slice[i];\n            i += 1;\n        } else {\n            arr[k] = right_slice[j];\n            j += 1;\n        }\n        k += 1;\n    }\n\n    // Copy any remaining elements from the left subarray\n    while i < left_slice.len() {\n        arr[k] = left_slice[i];\n        k += 1;\n        i += 1;\n    }\n\n    // Copy any remaining elements from the right subarray\n    while j < right_slice.len() {\n        arr[k] = right_slice[j];\n        k += 1;\n        j += 1;\n    }\n}\n\n/// Sorts a slice using Tim sort algorithm.\n///\n/// This function sorts the provided slice in-place using the Tim sort algorithm.\n///\n/// # Arguments\n///\n/// * `arr` - The slice to be sorted.\npub fn tim_sort<T: Ord + Copy>(arr: &mut [T]) {\n    let n = arr.len();\n    let min_run = compute_min_run_length(MIN_MERGE);\n\n    // Perform insertion sort on small subarrays\n    let mut i = 0;\n    while i < n {\n        insertion_sort(&mut arr[i..cmp::min(i + MIN_MERGE, n)]);\n        i += min_run;\n    }\n\n    // Merge sorted subarrays\n    let mut size = min_run;\n    while size < n {\n        let mut left = 0;\n        while left < n {\n            let mid = left + size - 1;\n            let right = cmp::min(left + 2 * size - 1, n - 1);\n            if mid < right {\n                merge(arr, left, mid, right);\n            }\n\n            left += 2 * size;\n        }\n        size *= 2;\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::{have_same_elements, is_sorted};\n\n    #[test]\n    fn min_run_length_returns_correct_value() {\n        assert_eq!(compute_min_run_length(0), 0);\n        assert_eq!(compute_min_run_length(10), 10);\n        assert_eq!(compute_min_run_length(33), 17);\n        assert_eq!(compute_min_run_length(64), 16);\n    }\n\n    macro_rules! test_merge {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input_arr, l, m, r, expected) = $inputs;\n                    let mut arr = input_arr.clone();\n                    merge(&mut arr, l, m, r);\n                    assert_eq!(arr, expected);\n                }\n            )*\n        }\n    }\n\n    test_merge! {\n        left_and_right_subarrays_into_array: (vec![0, 2, 4, 1, 3, 5], 0, 2, 5, vec![0, 1, 2, 3, 4, 5]),\n        with_empty_left_subarray: (vec![1, 2, 3], 0, 0, 2, vec![1, 2, 3]),\n        with_empty_right_subarray: (vec![1, 2, 3], 0, 2, 2, vec![1, 2, 3]),\n        with_empty_left_and_right_subarrays: (vec![1, 2, 3], 1, 0, 0, vec![1, 2, 3]),\n    }\n\n    macro_rules! test_tim_sort {\n        ($($name:ident: $input:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let mut array = $input;\n                    let cloned = array.clone();\n                    tim_sort(&mut array);\n                    assert!(is_sorted(&array) && have_same_elements(&array, &cloned));\n                }\n            )*\n        }\n    }\n\n    test_tim_sort! {\n        sorts_basic_array_correctly: vec![-2, 7, 15, -14, 0, 15, 0, 7, -7, -4, -13, 5, 8, -14, 12],\n        sorts_long_array_correctly: vec![-2, 7, 15, -14, 0, 15, 0, 7, -7, -4, -13, 5, 8, -14, 12, 5, 3, 9, 22, 1, 1, 2, 3, 9, 6, 5, 4, 5, 6, 7, 8, 9, 1],\n        handles_empty_array: Vec::<i32>::new(),\n        handles_single_element_array: vec![3],\n        handles_pre_sorted_array: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    }\n}\n"
  },
  {
    "path": "src/sorting/tree_sort.rs",
    "content": "// Author : cyrixninja\n// Tree Sort Algorithm\n// https://en.wikipedia.org/wiki/Tree_sort\n// Wikipedia :A tree sort is a sort algorithm that builds a binary search tree from the elements to be sorted, and then traverses the tree (in-order) so that the elements come out in sorted order.\n// Its typical use is sorting elements online: after each insertion, the set of elements seen so far is available in sorted order.\n\nstruct TreeNode<T> {\n    value: T,\n    left: Option<Box<TreeNode<T>>>,\n    right: Option<Box<TreeNode<T>>>,\n}\n\nimpl<T> TreeNode<T> {\n    fn new(value: T) -> Self {\n        TreeNode {\n            value,\n            left: None,\n            right: None,\n        }\n    }\n}\n\nstruct BinarySearchTree<T> {\n    root: Option<Box<TreeNode<T>>>,\n}\n\nimpl<T: Ord + Clone> BinarySearchTree<T> {\n    fn new() -> Self {\n        BinarySearchTree { root: None }\n    }\n\n    fn insert(&mut self, value: T) {\n        self.root = Some(Self::insert_recursive(self.root.take(), value));\n    }\n\n    fn insert_recursive(root: Option<Box<TreeNode<T>>>, value: T) -> Box<TreeNode<T>> {\n        match root {\n            None => Box::new(TreeNode::new(value)),\n            Some(mut node) => {\n                if value <= node.value {\n                    node.left = Some(Self::insert_recursive(node.left.take(), value));\n                } else {\n                    node.right = Some(Self::insert_recursive(node.right.take(), value));\n                }\n                node\n            }\n        }\n    }\n\n    fn in_order_traversal(&self, result: &mut Vec<T>) {\n        Self::in_order_recursive(&self.root, result);\n    }\n\n    fn in_order_recursive(root: &Option<Box<TreeNode<T>>>, result: &mut Vec<T>) {\n        if let Some(node) = root {\n            Self::in_order_recursive(&node.left, result);\n            result.push(node.value.clone());\n            Self::in_order_recursive(&node.right, result);\n        }\n    }\n}\n\npub fn tree_sort<T: Ord + Clone>(arr: &mut Vec<T>) {\n    let mut tree = BinarySearchTree::new();\n\n    for elem in arr.iter().cloned() {\n        tree.insert(elem);\n    }\n\n    let mut result = Vec::new();\n    tree.in_order_traversal(&mut result);\n\n    *arr = result;\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_empty_array() {\n        let mut arr: Vec<i32> = vec![];\n        tree_sort(&mut arr);\n        assert_eq!(arr, vec![]);\n    }\n\n    #[test]\n    fn test_single_element() {\n        let mut arr = vec![8];\n        tree_sort(&mut arr);\n        assert_eq!(arr, vec![8]);\n    }\n\n    #[test]\n    fn test_already_sorted() {\n        let mut arr = vec![1, 2, 3, 4, 5];\n        tree_sort(&mut arr);\n        assert_eq!(arr, vec![1, 2, 3, 4, 5]);\n    }\n\n    #[test]\n    fn test_reverse_sorted() {\n        let mut arr = vec![5, 4, 3, 2, 1];\n        tree_sort(&mut arr);\n        assert_eq!(arr, vec![1, 2, 3, 4, 5]);\n    }\n\n    #[test]\n    fn test_random() {\n        let mut arr = vec![9, 6, 10, 11, 2, 19];\n        tree_sort(&mut arr);\n        assert_eq!(arr, vec![2, 6, 9, 10, 11, 19]);\n    }\n}\n"
  },
  {
    "path": "src/sorting/wave_sort.rs",
    "content": "/// Wave Sort Algorithm\n///\n/// Wave Sort is a sorting algorithm that works in O(n log n) time assuming\n/// the sort function used works in O(n log n) time.\n/// It arranges elements in an array into a sequence where every alternate\n/// element is either greater or smaller than its adjacent elements.\n///\n/// Reference:\n/// [Wave Sort Algorithm - GeeksforGeeks](https://www.geeksforgeeks.org/sort-array-wave-form-2/)\n///\n/// # Examples\n///\n/// use the_algorithms_rust::sorting::wave_sort;\n/// let array = vec![10, 90, 49, 2, 1, 5, 23];\n/// let result = wave_sort(array);\n/// // Result: [2, 1, 10, 5, 49, 23, 90]\n///\npub fn wave_sort<T: Ord>(arr: &mut [T]) {\n    let n = arr.len();\n    arr.sort();\n\n    for i in (0..n - 1).step_by(2) {\n        arr.swap(i, i + 1);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_case_1() {\n        let mut array = vec![10, 90, 49, 2, 1, 5, 23];\n        wave_sort(&mut array);\n        let expected = vec![2, 1, 10, 5, 49, 23, 90];\n        assert_eq!(&array, &expected);\n    }\n\n    #[test]\n    fn test_case_2() {\n        let mut array = vec![1, 3, 4, 2, 7, 8];\n        wave_sort(&mut array);\n        let expected = vec![2, 1, 4, 3, 8, 7];\n        assert_eq!(&array, &expected);\n    }\n\n    #[test]\n    fn test_case_3() {\n        let mut array = vec![3, 3, 3, 3];\n        wave_sort(&mut array);\n        let expected = vec![3, 3, 3, 3];\n        assert_eq!(&array, &expected);\n    }\n\n    #[test]\n    fn test_case_4() {\n        let mut array = vec![9, 4, 6, 8, 14, 3];\n        wave_sort(&mut array);\n        let expected = vec![4, 3, 8, 6, 14, 9];\n        assert_eq!(&array, &expected);\n    }\n\n    #[test]\n    fn test_case_5() {\n        let mut array = vec![5, 10, 15, 20, 25];\n        wave_sort(&mut array);\n        let expected = vec![10, 5, 20, 15, 25];\n        assert_eq!(&array, &expected);\n    }\n}\n"
  },
  {
    "path": "src/sorting/wiggle_sort.rs",
    "content": "//Wiggle Sort.\n//Given an unsorted array nums, reorder it such\n//that nums[0] < nums[1] > nums[2] < nums[3]....\n//For example:\n//if input numbers = [3, 5, 2, 1, 6, 4]\n//one possible Wiggle Sorted answer is [3, 5, 1, 6, 2, 4].\n\npub fn wiggle_sort(nums: &mut Vec<i32>) -> &mut Vec<i32> {\n    //Rust implementation of wiggle.\n    //    Example:\n    //    >>> wiggle_sort([0, 5, 3, 2, 2])\n    //    [0, 5, 2, 3, 2]\n    //    >>> wiggle_sort([])\n    //    []\n    //    >>> wiggle_sort([-2, -5, -45])\n    //    [-45, -2, -5]\n\n    let len = nums.len();\n    for i in 1..len {\n        let num_x = nums[i - 1];\n        let num_y = nums[i];\n        if (i % 2 == 1) == (num_x > num_y) {\n            nums[i - 1] = num_y;\n            nums[i] = num_x;\n        }\n    }\n    nums\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sorting::have_same_elements;\n\n    fn is_wiggle_sorted(nums: &[i32]) -> bool {\n        if nums.is_empty() {\n            return true;\n        }\n        let mut previous = nums[0];\n        let mut result = true;\n        nums.iter().enumerate().skip(1).for_each(|(i, &item)| {\n            if i != 0 {\n                result =\n                    result && ((i % 2 == 1 && previous < item) || (i % 2 == 0 && previous > item));\n            }\n\n            previous = item;\n        });\n        result\n    }\n\n    #[test]\n    fn wingle_elements() {\n        let arr = vec![3, 5, 2, 1, 6, 4];\n        let mut cloned = arr.clone();\n        let res = wiggle_sort(&mut cloned);\n        assert!(is_wiggle_sorted(res));\n        assert!(have_same_elements(res, &arr));\n    }\n\n    #[test]\n    fn odd_number_of_elements() {\n        let arr = vec![4, 1, 3, 5, 2];\n        let mut cloned = arr.clone();\n        let res = wiggle_sort(&mut cloned);\n        assert!(is_wiggle_sorted(res));\n        assert!(have_same_elements(res, &arr));\n    }\n\n    #[test]\n    fn repeated_elements() {\n        let arr = vec![5, 5, 5, 5];\n        let mut cloned = arr.clone();\n        let res = wiggle_sort(&mut cloned);\n\n        // Negative test, can't be wiggle sorted\n        assert!(!is_wiggle_sorted(res));\n        assert!(have_same_elements(res, &arr));\n    }\n}\n"
  },
  {
    "path": "src/string/README.md",
    "content": "## String Algorithms\n\n### [Aho-Corasick Algorithm](./aho_corasick.rs)\nFrom [Wikipedia][aho-corasick-wiki]: a string-searching algorithm invented by Alfred V. Aho and Margaret J. Corasick in 1975.[1] It is a kind of dictionary-matching algorithm that locates elements of a finite set of strings (the \"dictionary\") within an input text. It matches all strings simultaneously.\n\n[aho-corasick-wiki]: https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm\n\n\n### [Burrows-Wheeler transform](./burrows_wheeler_transform.rs)\nFrom [Wikipedia][burrows-wheeler-wiki]: The Burrows–Wheeler transform (BWT, also called block-sorting compression) rearranges a character string into runs of similar characters. This is useful for compression, since it tends to be easy to compress a string that has runs of repeated characters by techniques such as move-to-front transform and run-length encoding. More importantly, the transformation is reversible, without needing to store any additional data except the position of the first original character. The BWT is thus a \"free\" method of improving the efficiency of text compression algorithms, costing only some extra computation. \n\n__Properties__\n* Worst-case performance  O(n)\n\n[burrows-wheeler-wiki]: https://en.wikipedia.org/wiki/Burrows%E2%80%93Wheeler_transform\n\n\n### [Knuth Morris Pratt](./knuth_morris_pratt.rs)\nFrom [Wikipedia][kmp-wiki]: searches for occurrences of a \"word\" W within a main \"text string\" S by employing the observation that when a mismatch occurs, the word itself embodies sufficient information to determine where the next match could begin, thus bypassing re-examination of previously matched characters.\n  Knuth Morris Pratt search runs in linear time in the length of W and S.\n\n__Properties__\n* Case performance  O(s + w)\n* Case space complexity  O(w)\n\n[kmp-wiki]: https://en.wikipedia.org/wiki/Knuth–Morris–Pratt_algorithm\n\n\n\n### [Manacher](./manacher.rs)\nFrom [Wikipedia][manacher-wiki]: find a longest palindrome in a string in linear time.\n\n__Properties__\n* Worst-case time complexity is O(n)\n* Worst-case space complexity is O(n)\n\n[manacher-wiki]: https://en.wikipedia.org/wiki/Longest_palindromic_substring#Manacher's_algorithm\n\n\n### [Rabin Karp](./rabin_karp.rs)\nFrom [Wikipedia][rabin-karp-wiki]: a string-searching algorithm created by Richard M. Karp and Michael O. Rabin that uses hashing\nto find an exact match of a pattern string in a text.\n\n[rabin-karp-wiki]: https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm\n\n\n### [Hamming Distance](./hamming_distance.rs)\nFrom [Wikipedia][hamming-distance-wiki]: In information theory, the Hamming distance between two strings of equal length is the number of positions at which the corresponding symbols are different. In other words, it measures the minimum number of substitutions required to change one string into the other, or the minimum number of errors that could have transformed one string into the other. In a more general context, the Hamming distance is one of several string metrics for measuring the edit distance between two sequences. It is named after the American mathematician Richard Hamming.\n\n[run-length-encoding-wiki]: https://en.wikipedia.org/wiki/Run-length_encoding\n\n### [Run Length Encoding](./run_length_encoding.rs)\nFrom [Wikipedia][run-length-encoding-wiki]: a form of lossless data compression in which runs of data (sequences in which the same data value occurs in many consecutive data elements) are stored as a single data value and count, rather than as the original run.\n\n[hamming-distance-wiki]: https://en.wikipedia.org/wiki/Hamming_distance\n"
  },
  {
    "path": "src/string/aho_corasick.rs",
    "content": "use std::cell::RefCell;\nuse std::collections::BTreeMap;\nuse std::collections::VecDeque;\nuse std::rc::{Rc, Weak};\n\n#[derive(Default)]\nstruct ACNode {\n    trans: BTreeMap<char, Rc<RefCell<ACNode>>>,\n    suffix: Weak<RefCell<ACNode>>, // the suffix(fail) link\n    lengths: Vec<usize>,           // lengths of matched patterns ended at this node\n}\n\n#[derive(Default)]\npub struct AhoCorasick {\n    root: Rc<RefCell<ACNode>>,\n}\n\nimpl AhoCorasick {\n    pub fn new(words: &[&str]) -> Self {\n        let root = Rc::new(RefCell::new(ACNode::default()));\n        for word in words {\n            let mut cur = Rc::clone(&root);\n            for c in word.chars() {\n                cur = Rc::clone(Rc::clone(&cur).borrow_mut().trans.entry(c).or_default());\n            }\n            cur.borrow_mut().lengths.push(word.len());\n        }\n        Self::build_suffix(Rc::clone(&root));\n        Self { root }\n    }\n\n    fn build_suffix(root: Rc<RefCell<ACNode>>) {\n        let mut q = VecDeque::new();\n        q.push_back(Rc::clone(&root));\n        while let Some(parent) = q.pop_front() {\n            let parent = parent.borrow();\n            for (c, child) in &parent.trans {\n                q.push_back(Rc::clone(child));\n                let mut child = child.borrow_mut();\n                let mut suffix = parent.suffix.upgrade();\n                loop {\n                    match &suffix {\n                        None => {\n                            child.lengths.extend(root.borrow().lengths.clone());\n                            child.suffix = Rc::downgrade(&root);\n                            break;\n                        }\n                        Some(node) => {\n                            if node.borrow().trans.contains_key(c) {\n                                let node = &node.borrow().trans[c];\n                                child.lengths.extend(node.borrow().lengths.clone());\n                                child.suffix = Rc::downgrade(node);\n                                break;\n                            }\n                            suffix = suffix.unwrap().borrow().suffix.upgrade();\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    pub fn search<'a>(&self, s: &'a str) -> Vec<&'a str> {\n        let mut ans = vec![];\n        let mut cur = Rc::clone(&self.root);\n        let mut position: usize = 0;\n        for c in s.chars() {\n            loop {\n                if let Some(child) = Rc::clone(&cur).borrow().trans.get(&c) {\n                    cur = Rc::clone(child);\n                    break;\n                }\n                let suffix = cur.borrow().suffix.clone();\n                match suffix.upgrade() {\n                    Some(node) => cur = node,\n                    None => break,\n                }\n            }\n            position += c.len_utf8();\n            for &len in &cur.borrow().lengths {\n                ans.push(&s[position - len..position]);\n            }\n        }\n        ans\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_aho_corasick() {\n        let dict = [\"abc\", \"abcd\", \"xyz\", \"acxy\", \"efg\", \"123\", \"678\", \"6543\"];\n        let ac = AhoCorasick::new(&dict);\n        let res = ac.search(\"ababcxyzacxy12678acxy6543\");\n        assert_eq!(res, [\"abc\", \"xyz\", \"acxy\", \"678\", \"acxy\", \"6543\",]);\n    }\n\n    #[test]\n    fn test_aho_corasick_with_utf8() {\n        let dict = [\n            \"abc\",\n            \"中文\",\n            \"abc中\",\n            \"abcd\",\n            \"xyz\",\n            \"acxy\",\n            \"efg\",\n            \"123\",\n            \"678\",\n            \"6543\",\n            \"ハンバーガー\",\n        ];\n        let ac = AhoCorasick::new(&dict);\n        let res = ac.search(\"ababc中xyzacxy12678acxyハンバーガー6543中文\");\n        assert_eq!(\n            res,\n            [\n                \"abc\",\n                \"abc中\",\n                \"xyz\",\n                \"acxy\",\n                \"678\",\n                \"acxy\",\n                \"ハンバーガー\",\n                \"6543\",\n                \"中文\"\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "src/string/anagram.rs",
    "content": "use std::collections::HashMap;\n\n/// Custom error type representing an invalid character found in the input.\n#[derive(Debug, PartialEq)]\npub enum AnagramError {\n    NonAlphabeticCharacter,\n}\n\n/// Checks if two strings are anagrams, ignoring spaces and case sensitivity.\n///\n/// # Arguments\n///\n/// * `s` - First input string.\n/// * `t` - Second input string.\n///\n/// # Returns\n///\n/// * `Ok(true)` if the strings are anagrams.\n/// * `Ok(false)` if the strings are not anagrams.\n/// * `Err(AnagramError)` if either string contains non-alphabetic characters.\npub fn check_anagram(s: &str, t: &str) -> Result<bool, AnagramError> {\n    let s_cleaned = clean_string(s)?;\n    let t_cleaned = clean_string(t)?;\n\n    Ok(char_count(&s_cleaned) == char_count(&t_cleaned))\n}\n\n/// Cleans the input string by removing spaces and converting to lowercase.\n/// Returns an error if any non-alphabetic character is found.\n///\n/// # Arguments\n///\n/// * `s` - Input string to clean.\n///\n/// # Returns\n///\n/// * `Ok(String)` containing the cleaned string (no spaces, lowercase).\n/// * `Err(AnagramError)` if the string contains non-alphabetic characters.\nfn clean_string(s: &str) -> Result<String, AnagramError> {\n    s.chars()\n        .filter(|c| !c.is_whitespace())\n        .map(|c| {\n            if c.is_alphabetic() {\n                Ok(c.to_ascii_lowercase())\n            } else {\n                Err(AnagramError::NonAlphabeticCharacter)\n            }\n        })\n        .collect()\n}\n\n/// Computes the histogram of characters in a string.\n///\n/// # Arguments\n///\n/// * `s` - Input string.\n///\n/// # Returns\n///\n/// * A `HashMap` where the keys are characters and values are their count.\nfn char_count(s: &str) -> HashMap<char, usize> {\n    let mut res = HashMap::new();\n    for c in s.chars() {\n        *res.entry(c).or_insert(0) += 1;\n    }\n    res\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_cases {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (s, t, expected) = $test_case;\n                    assert_eq!(check_anagram(s, t), expected);\n                    assert_eq!(check_anagram(t, s), expected);\n                }\n            )*\n        }\n    }\n\n    test_cases! {\n        empty_strings: (\"\", \"\", Ok(true)),\n        empty_and_non_empty: (\"\", \"Ted Morgan\", Ok(false)),\n        single_char_same: (\"z\", \"Z\", Ok(true)),\n        single_char_diff: (\"g\", \"h\", Ok(false)),\n        valid_anagram_lowercase: (\"cheater\", \"teacher\", Ok(true)),\n        valid_anagram_with_spaces: (\"madam curie\", \"radium came\", Ok(true)),\n        valid_anagram_mixed_cases: (\"Satan\", \"Santa\", Ok(true)),\n        valid_anagram_with_spaces_and_mixed_cases: (\"Anna Madrigal\", \"A man and a girl\", Ok(true)),\n        new_york_times: (\"New York Times\", \"monkeys write\", Ok(true)),\n        church_of_scientology: (\"Church of Scientology\", \"rich chosen goofy cult\", Ok(true)),\n        mcdonalds_restaurants: (\"McDonald's restaurants\", \"Uncle Sam's standard rot\", Err(AnagramError::NonAlphabeticCharacter)),\n        coronavirus: (\"coronavirus\", \"carnivorous\", Ok(true)),\n        synonym_evil: (\"evil\", \"vile\", Ok(true)),\n        synonym_gentleman: (\"a gentleman\", \"elegant man\", Ok(true)),\n        antigram: (\"restful\", \"fluster\", Ok(true)),\n        sentences: (\"William Shakespeare\", \"I am a weakish speller\", Ok(true)),\n        part_of_speech_adj_to_verb: (\"silent\", \"listen\", Ok(true)),\n        anagrammatized: (\"Anagrams\", \"Ars magna\", Ok(true)),\n        non_anagram: (\"rat\", \"car\", Ok(false)),\n        invalid_anagram_with_special_char: (\"hello!\", \"world\", Err(AnagramError::NonAlphabeticCharacter)),\n        invalid_anagram_with_numeric_chars: (\"test123\", \"321test\", Err(AnagramError::NonAlphabeticCharacter)),\n        invalid_anagram_with_symbols: (\"check@anagram\", \"check@nagaram\", Err(AnagramError::NonAlphabeticCharacter)),\n        non_anagram_length_mismatch: (\"abc\", \"abcd\", Ok(false)),\n    }\n}\n"
  },
  {
    "path": "src/string/autocomplete_using_trie.rs",
    "content": "/*\n    It autocomplete by prefix using added words.\n\n    word List => [\"apple\", \"orange\", \"oregano\"]\n    prefix => \"or\"\n    matches => [\"orange\", \"oregano\"]\n*/\n\nuse std::collections::HashMap;\n\nconst END: char = '#';\n\n#[derive(Debug)]\nstruct Trie(HashMap<char, Box<Trie>>);\n\nimpl Trie {\n    fn new() -> Self {\n        Trie(HashMap::new())\n    }\n\n    fn insert(&mut self, text: &str) {\n        let mut trie = self;\n\n        for c in text.chars() {\n            trie = trie.0.entry(c).or_insert_with(|| Box::new(Trie::new()));\n        }\n\n        trie.0.insert(END, Box::new(Trie::new()));\n    }\n\n    fn find(&self, prefix: &str) -> Vec<String> {\n        let mut trie = self;\n\n        for c in prefix.chars() {\n            let char_trie = trie.0.get(&c);\n            if let Some(char_trie) = char_trie {\n                trie = char_trie;\n            } else {\n                return vec![];\n            }\n        }\n\n        Self::_elements(trie)\n            .iter()\n            .map(|s| prefix.to_owned() + s)\n            .collect()\n    }\n\n    fn _elements(map: &Trie) -> Vec<String> {\n        let mut results = vec![];\n\n        for (c, v) in map.0.iter() {\n            let mut sub_result = vec![];\n            if c == &END {\n                sub_result.push(\"\".to_owned())\n            } else {\n                Self::_elements(v)\n                    .iter()\n                    .map(|s| sub_result.push(c.to_string() + s))\n                    .collect()\n            }\n\n            results.extend(sub_result)\n        }\n\n        results\n    }\n}\n\npub struct Autocomplete {\n    trie: Trie,\n}\n\nimpl Autocomplete {\n    fn new() -> Self {\n        Self { trie: Trie::new() }\n    }\n\n    pub fn insert_words<T: AsRef<str>>(&mut self, words: &[T]) {\n        for word in words {\n            self.trie.insert(word.as_ref());\n        }\n    }\n\n    pub fn find_words(&self, prefix: &str) -> Vec<String> {\n        self.trie.find(prefix)\n    }\n}\n\nimpl Default for Autocomplete {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::Autocomplete;\n\n    #[test]\n    fn test_autocomplete() {\n        let words = vec![\"apple\", \"orange\", \"oregano\"];\n\n        let mut auto_complete = Autocomplete::new();\n        auto_complete.insert_words(&words);\n\n        let prefix = \"app\";\n        let mut auto_completed_words = auto_complete.find_words(prefix);\n\n        let mut apple = vec![\"apple\"];\n        apple.sort();\n\n        auto_completed_words.sort();\n        assert_eq!(auto_completed_words, apple);\n\n        let prefix = \"or\";\n        let mut auto_completed_words = auto_complete.find_words(prefix);\n\n        let mut prefix_or = vec![\"orange\", \"oregano\"];\n        prefix_or.sort();\n\n        auto_completed_words.sort();\n        assert_eq!(auto_completed_words, prefix_or);\n    }\n}\n"
  },
  {
    "path": "src/string/boyer_moore_search.rs",
    "content": "//! This module implements the Boyer-Moore string search algorithm, an efficient method\n//! for finding all occurrences of a pattern within a given text. The algorithm skips\n//! sections of the text by leveraging two key rules: the bad character rule and the\n//! good suffix rule (only the bad character rule is implemented here for simplicity).\n\nuse std::collections::HashMap;\n\n/// Builds the bad character table for the Boyer-Moore algorithm.\n/// This table stores the last occurrence of each character in the pattern.\n///\n/// # Arguments\n/// * `pat` - The pattern as a slice of characters.\n///\n/// # Returns\n/// A `HashMap` where the keys are characters from the pattern and the values are their\n/// last known positions within the pattern.\nfn build_bad_char_table(pat: &[char]) -> HashMap<char, isize> {\n    let mut bad_char_table = HashMap::new();\n    for (i, &ch) in pat.iter().enumerate() {\n        bad_char_table.insert(ch, i as isize);\n    }\n    bad_char_table\n}\n\n/// Calculates the shift when a full match occurs in the Boyer-Moore algorithm.\n/// It uses the bad character table to determine how much to shift the pattern.\n///\n/// # Arguments\n/// * `shift` - The current shift of the pattern on the text.\n/// * `pat_len` - The length of the pattern.\n/// * `text_len` - The length of the text.\n/// * `bad_char_table` - The bad character table built for the pattern.\n/// * `text` - The text as a slice of characters.\n///\n/// # Returns\n/// The number of positions to shift the pattern after a match.\nfn calc_match_shift(\n    shift: isize,\n    pat_len: isize,\n    text_len: isize,\n    bad_char_table: &HashMap<char, isize>,\n    text: &[char],\n) -> isize {\n    if shift + pat_len >= text_len {\n        return 1;\n    }\n    let next_ch = text[(shift + pat_len) as usize];\n    pat_len - bad_char_table.get(&next_ch).unwrap_or(&-1)\n}\n\n/// Calculates the shift when a mismatch occurs in the Boyer-Moore algorithm.\n/// The bad character rule is used to determine how far to shift the pattern.\n///\n/// # Arguments\n/// * `mis_idx` - The mismatch index in the pattern.\n/// * `shift` - The current shift of the pattern on the text.\n/// * `text` - The text as a slice of characters.\n/// * `bad_char_table` - The bad character table built for the pattern.\n///\n/// # Returns\n/// The number of positions to shift the pattern after a mismatch.\nfn calc_mismatch_shift(\n    mis_idx: isize,\n    shift: isize,\n    text: &[char],\n    bad_char_table: &HashMap<char, isize>,\n) -> isize {\n    let mis_ch = text[(shift + mis_idx) as usize];\n    let bad_char_shift = bad_char_table.get(&mis_ch).unwrap_or(&-1);\n    std::cmp::max(1, mis_idx - bad_char_shift)\n}\n\n/// Performs the Boyer-Moore string search algorithm, which searches for all\n/// occurrences of a pattern within a text.\n///\n/// The Boyer-Moore algorithm is efficient for large texts and patterns, as it\n/// skips sections of the text based on the bad character rule and other optimizations.\n///\n/// # Arguments\n/// * `text` - The text to search within as a string slice.\n/// * `pat` - The pattern to search for as a string slice.\n///\n/// # Returns\n/// A vector of starting indices where the pattern occurs in the text.\npub fn boyer_moore_search(text: &str, pat: &str) -> Vec<usize> {\n    let mut positions = Vec::new();\n\n    let text_len = text.len() as isize;\n    let pat_len = pat.len() as isize;\n\n    // Handle edge cases where the text or pattern is empty, or the pattern is longer than the text\n    if text_len == 0 || pat_len == 0 || pat_len > text_len {\n        return positions;\n    }\n\n    // Convert text and pattern to character vectors for easier indexing\n    let pat: Vec<char> = pat.chars().collect();\n    let text: Vec<char> = text.chars().collect();\n\n    // Build the bad character table for the pattern\n    let bad_char_table = build_bad_char_table(&pat);\n\n    let mut shift = 0;\n\n    // Main loop: shift the pattern over the text\n    while shift <= text_len - pat_len {\n        let mut j = pat_len - 1;\n\n        // Compare pattern from right to left\n        while j >= 0 && pat[j as usize] == text[(shift + j) as usize] {\n            j -= 1;\n        }\n\n        // If we found a match (j < 0), record the position\n        if j < 0 {\n            positions.push(shift as usize);\n            shift += calc_match_shift(shift, pat_len, text_len, &bad_char_table, &text);\n        } else {\n            // If mismatch, calculate how far to shift based on the bad character rule\n            shift += calc_mismatch_shift(j, shift, &text, &bad_char_table);\n        }\n    }\n\n    positions\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! boyer_moore_tests {\n        ($($name:ident: $tc:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (text, pattern, expected) = $tc;\n                    assert_eq!(boyer_moore_search(text, pattern), expected);\n                }\n            )*\n        };\n    }\n\n    boyer_moore_tests! {\n        test_simple_match: (\"AABCAB12AFAABCABFFEGABCAB\", \"ABCAB\", vec![1, 11, 20]),\n        test_no_match: (\"AABCAB12AFAABCABFFEGABCAB\", \"FFF\", vec![]),\n        test_partial_match: (\"AABCAB12AFAABCABFFEGABCAB\", \"CAB\", vec![3, 13, 22]),\n        test_empty_text: (\"\", \"A\", vec![]),\n        test_empty_pattern: (\"ABC\", \"\", vec![]),\n        test_both_empty: (\"\", \"\", vec![]),\n        test_pattern_longer_than_text: (\"ABC\", \"ABCDEFG\", vec![]),\n        test_single_character_text: (\"A\", \"A\", vec![0]),\n        test_single_character_pattern: (\"AAAA\", \"A\", vec![0, 1, 2, 3]),\n        test_case_sensitivity: (\"ABCabcABC\", \"abc\", vec![3]),\n        test_overlapping_patterns: (\"AAAAA\", \"AAA\", vec![0, 1, 2]),\n        test_special_characters: (\"@!#$$%^&*\", \"$$\", vec![3]),\n        test_numerical_pattern: (\"123456789123456\", \"456\", vec![3, 12]),\n        test_partial_overlap_no_match: (\"ABCD\", \"ABCDE\", vec![]),\n        test_single_occurrence: (\"XXXXXXXXXXXXXXXXXXPATTERNXXXXXXXXXXXXXXXXXX\", \"PATTERN\", vec![18]),\n        test_single_occurrence_with_noise: (\"PATPATPATPATTERNPAT\", \"PATTERN\", vec![9]),\n    }\n}\n"
  },
  {
    "path": "src/string/burrows_wheeler_transform.rs",
    "content": "pub fn burrows_wheeler_transform(input: &str) -> (String, usize) {\n    let len = input.len();\n\n    let mut table = Vec::<String>::with_capacity(len);\n    for i in 0..len {\n        table.push(input[i..].to_owned() + &input[..i]);\n    }\n    table.sort_by_key(|a| a.to_lowercase());\n\n    let mut encoded = String::new();\n    let mut index: usize = 0;\n    for (i, item) in table.iter().enumerate().take(len) {\n        encoded.push(item.chars().last().unwrap());\n        if item.eq(&input) {\n            index = i;\n        }\n    }\n\n    (encoded, index)\n}\n\npub fn inv_burrows_wheeler_transform<T: AsRef<str>>(input: (T, usize)) -> String {\n    let len = input.0.as_ref().len();\n    let mut table = Vec::<(usize, char)>::with_capacity(len);\n    for i in 0..len {\n        table.push((i, input.0.as_ref().chars().nth(i).unwrap()));\n    }\n\n    table.sort_by(|a, b| a.1.cmp(&b.1));\n\n    let mut decoded = String::new();\n    let mut idx = input.1;\n    for _ in 0..len {\n        decoded.push(table[idx].1);\n        idx = table[idx].0;\n    }\n\n    decoded\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    //Ensure function stand-alone legitimacy\n    fn stand_alone_function() {\n        assert_eq!(\n            burrows_wheeler_transform(\"CARROT\"),\n            (\"CTRRAO\".to_owned(), 1usize)\n        );\n        assert_eq!(inv_burrows_wheeler_transform((\"CTRRAO\", 1usize)), \"CARROT\");\n        assert_eq!(\n            burrows_wheeler_transform(\"THEALGORITHMS\"),\n            (\"EHLTTRAHGOMSI\".to_owned(), 11usize)\n        );\n        assert_eq!(\n            inv_burrows_wheeler_transform((\"EHLTTRAHGOMSI\".to_string(), 11usize)),\n            \"THEALGORITHMS\"\n        );\n        assert_eq!(\n            burrows_wheeler_transform(\"!.!.!??.=::\"),\n            (\":..!!?:=.?!\".to_owned(), 0usize)\n        );\n        assert_eq!(\n            inv_burrows_wheeler_transform((\":..!!?:=.?!\", 0usize)),\n            \"!.!.!??.=::\"\n        );\n    }\n    #[test]\n    fn basic_characters() {\n        assert_eq!(\n            inv_burrows_wheeler_transform(burrows_wheeler_transform(\"CARROT\")),\n            \"CARROT\"\n        );\n        assert_eq!(\n            inv_burrows_wheeler_transform(burrows_wheeler_transform(\"TOMATO\")),\n            \"TOMATO\"\n        );\n        assert_eq!(\n            inv_burrows_wheeler_transform(burrows_wheeler_transform(\"THISISATEST\")),\n            \"THISISATEST\"\n        );\n        assert_eq!(\n            inv_burrows_wheeler_transform(burrows_wheeler_transform(\"THEALGORITHMS\")),\n            \"THEALGORITHMS\"\n        );\n        assert_eq!(\n            inv_burrows_wheeler_transform(burrows_wheeler_transform(\"RUST\")),\n            \"RUST\"\n        );\n    }\n\n    #[test]\n    fn special_characters() {\n        assert_eq!(\n            inv_burrows_wheeler_transform(burrows_wheeler_transform(\"!.!.!??.=::\")),\n            \"!.!.!??.=::\"\n        );\n        assert_eq!(\n            inv_burrows_wheeler_transform(burrows_wheeler_transform(\"!{}{}(((&&%%!??.=::\")),\n            \"!{}{}(((&&%%!??.=::\"\n        );\n        assert_eq!(\n            inv_burrows_wheeler_transform(burrows_wheeler_transform(\"//&$[]\")),\n            \"//&$[]\"\n        );\n    }\n\n    #[test]\n    fn empty() {\n        assert_eq!(\n            inv_burrows_wheeler_transform(burrows_wheeler_transform(\"\")),\n            \"\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/string/duval_algorithm.rs",
    "content": "//! Implementation of Duval's Algorithm to compute the standard factorization of a string\n//! into Lyndon words. A Lyndon word is defined as a string that is strictly smaller\n//! (lexicographically) than any of its nontrivial suffixes. This implementation operates\n//! in linear time and space.\n\n/// Performs Duval's algorithm to factorize a given string into its Lyndon words.\n///\n/// # Arguments\n///\n/// * `s` - A slice of characters representing the input string.\n///\n/// # Returns\n///\n/// A vector of strings, where each string is a Lyndon word, representing the factorization\n/// of the input string.\n///\n/// # Time Complexity\n///\n/// The algorithm runs in O(n) time, where `n` is the length of the input string.\npub fn duval_algorithm(s: &str) -> Vec<String> {\n    factorize_duval(&s.chars().collect::<Vec<char>>())\n}\n\n/// Helper function that takes a string slice, converts it to a vector of characters,\n/// and then applies the Duval factorization algorithm to find the Lyndon words.\n///\n/// # Arguments\n///\n/// * `s` - A string slice representing the input text.\n///\n/// # Returns\n///\n/// A vector of strings, each representing a Lyndon word in the factorization.\nfn factorize_duval(s: &[char]) -> Vec<String> {\n    let mut start = 0;\n    let mut factors: Vec<String> = Vec::new();\n\n    while start < s.len() {\n        let mut end = start + 1;\n        let mut repeat = start;\n\n        while end < s.len() && s[repeat] <= s[end] {\n            if s[repeat] < s[end] {\n                repeat = start;\n            } else {\n                repeat += 1;\n            }\n            end += 1;\n        }\n\n        while start <= repeat {\n            factors.push(s[start..start + end - repeat].iter().collect::<String>());\n            start += end - repeat;\n        }\n    }\n\n    factors\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    macro_rules! test_duval_algorithm {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (text, expected) = $inputs;\n                    assert_eq!(duval_algorithm(text), expected);\n                }\n            )*\n        }\n    }\n\n    test_duval_algorithm! {\n        repeating_with_suffix: (\"abcdabcdababc\", [\"abcd\", \"abcd\", \"ababc\"]),\n        single_repeating_char: (\"aaa\", [\"a\", \"a\", \"a\"]),\n        single: (\"ababb\", [\"ababb\"]),\n        unicode: (\"അഅഅ\", [\"അ\", \"അ\", \"അ\"]),\n        empty_string: (\"\", Vec::<String>::new()),\n        single_char: (\"x\", [\"x\"]),\n        palindrome: (\"racecar\", [\"r\", \"acecar\"]),\n        long_repeating: (\"aaaaaa\", [\"a\", \"a\", \"a\", \"a\", \"a\", \"a\"]),\n        mixed_repeating: (\"ababcbabc\", [\"ababcbabc\"]),\n        non_repeating_sorted: (\"abcdefg\", [\"abcdefg\"]),\n        alternating_increasing: (\"abababab\", [\"ab\", \"ab\", \"ab\", \"ab\"]),\n        long_repeating_lyndon: (\"abcabcabcabc\", [\"abc\", \"abc\", \"abc\", \"abc\"]),\n        decreasing_order: (\"zyxwvutsrqponm\", [\"z\", \"y\", \"x\", \"w\", \"v\", \"u\", \"t\", \"s\", \"r\", \"q\", \"p\", \"o\", \"n\", \"m\"]),\n        alphanumeric_mixed: (\"a1b2c3a1\", [\"a\", \"1b2c3a\", \"1\"]),\n        special_characters: (\"a@b#c$d\", [\"a\", \"@b\", \"#c$d\"]),\n        unicode_complex: (\"αβγδ\", [\"αβγδ\"]),\n        long_string_performance: (&\"a\".repeat(1_000_000), vec![\"a\"; 1_000_000]),\n        palindrome_repeating_prefix: (\"abccba\", [\"abccb\", \"a\"]),\n        interrupted_lyndon: (\"abcxabc\", [\"abcx\", \"abc\"]),\n    }\n}\n"
  },
  {
    "path": "src/string/hamming_distance.rs",
    "content": "/// Error type for Hamming distance calculation.\n#[derive(Debug, PartialEq)]\npub enum HammingDistanceError {\n    InputStringsHaveDifferentLength,\n}\n\n/// Calculates the Hamming distance between two strings.\n///\n/// The Hamming distance is defined as the number of positions at which the corresponding characters of the two strings are different.\npub fn hamming_distance(string_a: &str, string_b: &str) -> Result<usize, HammingDistanceError> {\n    if string_a.len() != string_b.len() {\n        return Err(HammingDistanceError::InputStringsHaveDifferentLength);\n    }\n\n    let distance = string_a\n        .chars()\n        .zip(string_b.chars())\n        .filter(|(a, b)| a != b)\n        .count();\n\n    Ok(distance)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_hamming_distance {\n        ($($name:ident: $tc:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (str_a, str_b, expected) = $tc;\n                    assert_eq!(hamming_distance(str_a, str_b), expected);\n                    assert_eq!(hamming_distance(str_b, str_a), expected);\n                }\n            )*\n        }\n    }\n\n    test_hamming_distance! {\n        empty_inputs: (\"\", \"\", Ok(0)),\n        different_length: (\"0\", \"\", Err(HammingDistanceError::InputStringsHaveDifferentLength)),\n        length_1_inputs_identical: (\"a\", \"a\", Ok(0)),\n        length_1_inputs_different: (\"a\", \"b\", Ok(1)),\n        same_strings: (\"rust\", \"rust\", Ok(0)),\n        regular_input_0: (\"karolin\", \"kathrin\", Ok(3)),\n        regular_input_1: (\"kathrin\", \"kerstin\", Ok(4)),\n        regular_input_2: (\"00000\", \"11111\", Ok(5)),\n        different_case: (\"x\", \"X\", Ok(1)),\n        strings_with_no_common_chars: (\"abcd\", \"wxyz\", Ok(4)),\n        long_strings_one_diff: (&\"a\".repeat(1000), &(\"a\".repeat(999) + \"b\"), Ok(1)),\n        long_strings_many_diffs: (&(\"a\".repeat(500) + &\"b\".repeat(500)), &(\"b\".repeat(500) + &\"a\".repeat(500)), Ok(1000)),\n        strings_with_special_chars_identical: (\"!@#$%^\", \"!@#$%^\", Ok(0)),\n        strings_with_special_chars_diff: (\"!@#$%^\", \"&*()_+\", Ok(6)),\n    }\n}\n"
  },
  {
    "path": "src/string/isogram.rs",
    "content": "//! This module provides functionality to check if a given string is an isogram.\n//! An isogram is a word or phrase in which no letter occurs more than once.\n\nuse std::collections::HashMap;\n\n/// Enum representing possible errors that can occur while checking for isograms.\n#[derive(Debug, PartialEq, Eq)]\npub enum IsogramError {\n    /// Indicates that the input contains a non-alphabetic character.\n    NonAlphabeticCharacter,\n}\n\n/// Counts the occurrences of each alphabetic character in a given string.\n///\n/// This function takes a string slice as input. It counts how many times each alphabetic character\n/// appears in the input string and returns a hashmap where the keys are characters and the values\n/// are their respective counts.\n///\n/// # Arguments\n///\n/// * `s` - A string slice that contains the input to count characters from.\n///\n/// # Errors\n///\n/// Returns an error if the input contains non-alphabetic characters (excluding spaces).\n///\n/// # Note\n///\n/// This function treats uppercase and lowercase letters as equivalent (case-insensitive).\n/// Spaces are ignored and do not affect the character count.\nfn count_letters(s: &str) -> Result<HashMap<char, usize>, IsogramError> {\n    let mut letter_counts = HashMap::new();\n\n    for ch in s.to_ascii_lowercase().chars() {\n        if !ch.is_ascii_alphabetic() && !ch.is_whitespace() {\n            return Err(IsogramError::NonAlphabeticCharacter);\n        }\n\n        if ch.is_ascii_alphabetic() {\n            *letter_counts.entry(ch).or_insert(0) += 1;\n        }\n    }\n\n    Ok(letter_counts)\n}\n\n/// Checks if the given input string is an isogram.\n///\n/// This function takes a string slice as input. It counts the occurrences of each\n/// alphabetic character (ignoring case and spaces).\n///\n/// # Arguments\n///\n/// * `input` - A string slice that contains the input to check for isogram properties.\n///\n/// # Return\n///\n/// - `Ok(true)` if all characters appear only once, or `Ok(false)` if any character appears more than once.\n/// - `Err(IsogramError::NonAlphabeticCharacter)` if the input contains any non-alphabetic characters.\npub fn is_isogram(s: &str) -> Result<bool, IsogramError> {\n    let letter_counts = count_letters(s)?;\n    Ok(letter_counts.values().all(|&count| count == 1))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! isogram_tests {\n        ($($name:ident: $tc:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $tc;\n                    assert_eq!(is_isogram(input), expected);\n                }\n            )*\n        };\n    }\n\n    isogram_tests! {\n        isogram_simple: (\"isogram\", Ok(true)),\n        isogram_case_insensitive: (\"Isogram\", Ok(true)),\n        isogram_with_spaces: (\"a b c d e\", Ok(true)),\n        isogram_mixed: (\"Dermatoglyphics\", Ok(true)),\n        isogram_long: (\"Subdermatoglyphic\", Ok(true)),\n        isogram_german_city: (\"Malitzschkendorf\", Ok(true)),\n        perfect_pangram: (\"Cwm fjord bank glyphs vext quiz\", Ok(true)),\n        isogram_sentences: (\"The big dwarf only jumps\", Ok(true)),\n        isogram_french: (\"Lampez un fort whisky\", Ok(true)),\n        isogram_portuguese: (\"Velho traduz sim\", Ok(true)),\n        isogram_spanish: (\"Centrifugadlos\", Ok(true)),\n        invalid_isogram_with_repeated_char: (\"hello\", Ok(false)),\n        invalid_isogram_with_numbers: (\"abc123\", Err(IsogramError::NonAlphabeticCharacter)),\n        invalid_isogram_with_special_char: (\"abc!\", Err(IsogramError::NonAlphabeticCharacter)),\n        invalid_isogram_with_comma: (\"Velho, traduz sim\", Err(IsogramError::NonAlphabeticCharacter)),\n        invalid_isogram_with_spaces: (\"a b c d a\", Ok(false)),\n        invalid_isogram_with_repeated_phrase: (\"abcabc\", Ok(false)),\n        isogram_empty_string: (\"\", Ok(true)),\n        isogram_single_character: (\"a\", Ok(true)),\n        invalid_isogram_multiple_same_characters: (\"aaaa\", Ok(false)),\n        invalid_isogram_with_symbols: (\"abc@#$%\", Err(IsogramError::NonAlphabeticCharacter)),\n    }\n}\n"
  },
  {
    "path": "src/string/isomorphism.rs",
    "content": "//! This module provides functionality to determine whether two strings are isomorphic.\n//!\n//! Two strings are considered isomorphic if the characters in one string can be replaced\n//! by some mapping relation to obtain the other string.\nuse std::collections::HashMap;\n\n/// Determines whether two strings are isomorphic.\n///\n/// # Arguments\n///\n/// * `s` - The first string.\n/// * `t` - The second string.\n///\n/// # Returns\n///\n/// `true` if the strings are isomorphic, `false` otherwise.\npub fn is_isomorphic(s: &str, t: &str) -> bool {\n    let s_chars: Vec<char> = s.chars().collect();\n    let t_chars: Vec<char> = t.chars().collect();\n    if s_chars.len() != t_chars.len() {\n        return false;\n    }\n    let mut s_to_t_map = HashMap::new();\n    let mut t_to_s_map = HashMap::new();\n    for (s_char, t_char) in s_chars.into_iter().zip(t_chars) {\n        if !check_mapping(&mut s_to_t_map, s_char, t_char)\n            || !check_mapping(&mut t_to_s_map, t_char, s_char)\n        {\n            return false;\n        }\n    }\n    true\n}\n\n/// Checks the mapping between two characters and updates the map.\n///\n/// # Arguments\n///\n/// * `map` - The HashMap to store the mapping.\n/// * `key` - The key character.\n/// * `value` - The value character.\n///\n/// # Returns\n///\n/// `true` if the mapping is consistent, `false` otherwise.\nfn check_mapping(map: &mut HashMap<char, char>, key: char, value: char) -> bool {\n    match map.get(&key) {\n        Some(&mapped_char) => mapped_char == value,\n        None => {\n            map.insert(key, value);\n            true\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::is_isomorphic;\n    macro_rules! test_is_isomorphic {\n        ($($name:ident: $inputs:expr,)*) => {\n        $(\n            #[test]\n            fn $name() {\n                let (s, t, expected) = $inputs;\n                assert_eq!(is_isomorphic(s, t), expected);\n                assert_eq!(is_isomorphic(t, s), expected);\n                assert!(is_isomorphic(s, s));\n                assert!(is_isomorphic(t, t));\n            }\n        )*\n        }\n    }\n    test_is_isomorphic! {\n        isomorphic: (\"egg\", \"add\", true),\n        isomorphic_long: (\"abcdaabdcdbbabababacdadad\", \"AbCdAAbdCdbbAbAbAbACdAdAd\", true),\n        not_isomorphic: (\"egg\", \"adc\", false),\n        non_isomorphic_long: (\"abcdaabdcdbbabababacdadad\", \"AACdAAbdCdbbAbAbAbACdAdAd\", false),\n        isomorphic_unicode: (\"天苍苍\", \"野茫茫\", true),\n        isomorphic_unicode_different_byte_size: (\"abb\", \"野茫茫\", true),\n        empty: (\"\", \"\", true),\n        different_length: (\"abc\", \"abcd\", false),\n    }\n}\n"
  },
  {
    "path": "src/string/jaro_winkler_distance.rs",
    "content": "// In computer science and statistics,\n// the Jaro–Winkler distance is a string metric measuring an edit distance\n// between two sequences.\n// It is a variant proposed in 1990 by William E. Winkler\n// of the Jaro distance metric (1989, Matthew A. Jaro).\n\npub fn jaro_winkler_distance(str1: &str, str2: &str) -> f64 {\n    if str1.is_empty() || str2.is_empty() {\n        return 0.0;\n    }\n    fn get_matched_characters(s1: &str, s2: &str) -> String {\n        let mut s2 = s2.to_string();\n        let mut matched: Vec<char> = Vec::new();\n        let limit = std::cmp::min(s1.len(), s2.len()) / 2;\n        for (i, l) in s1.chars().enumerate() {\n            let left = std::cmp::max(0, i as i32 - limit as i32) as usize;\n            let right = std::cmp::min(i + limit + 1, s2.len());\n            if s2[left..right].contains(l) {\n                matched.push(l);\n                let a = &s2[0..s2.find(l).expect(\"this exists\")];\n                let b = &s2[(s2.find(l).expect(\"this exists\") + 1)..];\n                s2 = format!(\"{a} {b}\");\n            }\n        }\n        matched.iter().collect::<String>()\n    }\n\n    let matching_1 = get_matched_characters(str1, str2);\n    let matching_2 = get_matched_characters(str2, str1);\n    let match_count = matching_1.len();\n\n    // transposition\n    let transpositions = {\n        let mut count = 0;\n        for (c1, c2) in matching_1.chars().zip(matching_2.chars()) {\n            if c1 != c2 {\n                count += 1;\n            }\n        }\n        count / 2\n    };\n\n    let jaro: f64 = {\n        if match_count == 0 {\n            return 0.0;\n        }\n        (1_f64 / 3_f64)\n            * (match_count as f64 / str1.len() as f64\n                + match_count as f64 / str2.len() as f64\n                + (match_count - transpositions) as f64 / match_count as f64)\n    };\n\n    let mut prefix_len = 0.0;\n    let bound = std::cmp::min(std::cmp::min(str1.len(), str2.len()), 4);\n    for (c1, c2) in str1[..bound].chars().zip(str2[..bound].chars()) {\n        if c1 == c2 {\n            prefix_len += 1.0;\n        } else {\n            break;\n        }\n    }\n    jaro + (0.1 * prefix_len * (1.0 - jaro))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_jaro_winkler_distance() {\n        let a = jaro_winkler_distance(\"hello\", \"world\");\n        assert_eq!(a, 0.4666666666666666);\n        let a = jaro_winkler_distance(\"martha\", \"marhta\");\n        assert_eq!(a, 0.9611111111111111);\n        let a = jaro_winkler_distance(\"martha\", \"marhat\");\n        assert_eq!(a, 0.9611111111111111);\n        let a = jaro_winkler_distance(\"test\", \"test\");\n        assert_eq!(a, 1.0);\n        let a = jaro_winkler_distance(\"test\", \"\");\n        assert_eq!(a, 0.0);\n        let a = jaro_winkler_distance(\"hello world\", \"HeLLo W0rlD\");\n        assert_eq!(a, 0.6363636363636364);\n    }\n}\n"
  },
  {
    "path": "src/string/knuth_morris_pratt.rs",
    "content": "//! Knuth-Morris-Pratt string matching algorithm implementation in Rust.\n//!\n//! This module contains the implementation of the KMP algorithm, which is used for finding\n//! occurrences of a pattern string within a text string efficiently. The algorithm preprocesses\n//! the pattern to create a partial match table, which allows for efficient searching.\n\n/// Finds all occurrences of the pattern in the given string using the Knuth-Morris-Pratt algorithm.\n///\n/// # Arguments\n///\n/// * `string` - The string to search within.\n/// * `pattern` - The pattern string to search for.\n///\n/// # Returns\n///\n/// A vector of starting indices where the pattern is found in the string. If the pattern or the\n/// string is empty, an empty vector is returned.\npub fn knuth_morris_pratt(string: &str, pattern: &str) -> Vec<usize> {\n    if string.is_empty() || pattern.is_empty() {\n        return vec![];\n    }\n\n    let text_chars = string.chars().collect::<Vec<char>>();\n    let pattern_chars = pattern.chars().collect::<Vec<char>>();\n    let partial_match_table = build_partial_match_table(&pattern_chars);\n    find_pattern(&text_chars, &pattern_chars, &partial_match_table)\n}\n\n/// Builds the partial match table (also known as \"prefix table\") for the given pattern.\n///\n/// The partial match table is used to skip characters while matching the pattern in the text.\n/// Each entry at index `i` in the table indicates the length of the longest proper prefix of\n/// the substring `pattern[0..i]` which is also a suffix of this substring.\n///\n/// # Arguments\n///\n/// * `pattern_chars` - The pattern string as a slice of characters.\n///\n/// # Returns\n///\n/// A vector representing the partial match table.\nfn build_partial_match_table(pattern_chars: &[char]) -> Vec<usize> {\n    let mut partial_match_table = vec![0];\n    pattern_chars\n        .iter()\n        .enumerate()\n        .skip(1)\n        .for_each(|(index, &char)| {\n            let mut length = partial_match_table[index - 1];\n            while length > 0 && pattern_chars[length] != char {\n                length = partial_match_table[length - 1];\n            }\n            partial_match_table.push(if pattern_chars[length] == char {\n                length + 1\n            } else {\n                length\n            });\n        });\n    partial_match_table\n}\n\n/// Finds all occurrences of the pattern in the given string using the precomputed partial match table.\n///\n/// This function iterates through the string and uses the partial match table to efficiently find\n/// all starting indices of the pattern in the string.\n///\n/// # Arguments\n///\n/// * `text_chars` - The string to search within as a slice of characters.\n/// * `pattern_chars` - The pattern string to search for as a slice of characters.\n/// * `partial_match_table` - The precomputed partial match table for the pattern.\n///\n/// # Returns\n///\n/// A vector of starting indices where the pattern is found in the string.\nfn find_pattern(\n    text_chars: &[char],\n    pattern_chars: &[char],\n    partial_match_table: &[usize],\n) -> Vec<usize> {\n    let mut result_indices = vec![];\n    let mut match_length = 0;\n\n    text_chars\n        .iter()\n        .enumerate()\n        .for_each(|(text_index, &text_char)| {\n            while match_length > 0 && text_char != pattern_chars[match_length] {\n                match_length = partial_match_table[match_length - 1];\n            }\n            if text_char == pattern_chars[match_length] {\n                match_length += 1;\n            }\n            if match_length == pattern_chars.len() {\n                result_indices.push(text_index + 1 - match_length);\n                match_length = partial_match_table[match_length - 1];\n            }\n        });\n\n    result_indices\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_knuth_morris_pratt {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, pattern, expected) = $inputs;\n                    assert_eq!(knuth_morris_pratt(input, pattern), expected);\n                }\n            )*\n        }\n    }\n\n    test_knuth_morris_pratt! {\n        each_letter_matches: (\"aaa\", \"a\", vec![0, 1, 2]),\n        a_few_seperate_matches: (\"abababa\", \"ab\", vec![0, 2, 4]),\n        unicode: (\"അഅഅ\", \"അ\", vec![0, 1, 2]),\n        unicode_no_match_but_similar_bytes: (\n            &String::from_utf8(vec![224, 180, 133]).unwrap(),\n            &String::from_utf8(vec![224, 180, 132]).unwrap(),\n            vec![]\n        ),\n        one_match: (\"ABC ABCDAB ABCDABCDABDE\",  \"ABCDABD\", vec![15]),\n        lots_of_matches: (\"aaabaabaaaaa\",  \"aa\", vec![0, 1, 4, 7, 8, 9, 10]),\n        lots_of_intricate_matches: (\"ababababa\", \"aba\", vec![0, 2, 4, 6]),\n        not_found0: (\"abcde\", \"f\", vec![]),\n        not_found1: (\"abcde\", \"ac\", vec![]),\n        not_found2: (\"ababab\", \"bababa\", vec![]),\n        empty_string: (\"\", \"abcdef\", vec![]),\n        empty_pattern: (\"abcdef\", \"\", vec![]),\n        single_character_string: (\"a\", \"a\", vec![0]),\n        single_character_pattern: (\"abcdef\", \"d\", vec![3]),\n        pattern_at_start: (\"abcdef\", \"abc\", vec![0]),\n        pattern_at_end: (\"abcdef\", \"def\", vec![3]),\n        pattern_in_middle: (\"abcdef\", \"cd\", vec![2]),\n        no_match_with_repeated_characters: (\"aaaaaa\", \"b\", vec![]),\n        pattern_longer_than_string: (\"abc\", \"abcd\", vec![]),\n        very_long_string: (&\"a\".repeat(10000), \"a\", (0..10000).collect::<Vec<usize>>()),\n        very_long_pattern: (&\"a\".repeat(10000), &\"a\".repeat(9999), (0..2).collect::<Vec<usize>>()),\n    }\n}\n"
  },
  {
    "path": "src/string/levenshtein_distance.rs",
    "content": "//! Provides functions to calculate the Levenshtein distance between two strings.\n//!\n//! The Levenshtein distance is a measure of the similarity between two strings by calculating the minimum number of single-character\n//! edits (insertions, deletions, or substitutions) required to change one string into the other.\n\nuse std::cmp::min;\n\n/// Calculates the Levenshtein distance between two strings using a naive dynamic programming approach.\n///\n/// The Levenshtein distance is a measure of the similarity between two strings by calculating the minimum number of single-character\n/// edits (insertions, deletions, or substitutions) required to change one string into the other.\n///\n/// # Arguments\n///\n/// * `string1` - A reference to the first string.\n/// * `string2` - A reference to the second string.\n///\n/// # Returns\n///\n/// The Levenshtein distance between the two input strings.\n///\n/// This function computes the Levenshtein distance by constructing a dynamic programming matrix and iteratively filling it in.\n/// It follows the standard top-to-bottom, left-to-right approach for filling in the matrix.\n///\n/// # Complexity\n///\n/// - Time complexity: O(nm),\n/// - Space complexity: O(nm),\n///\n/// where n and m are lengths of `string1` and `string2`.\n///\n/// Note that this implementation uses a straightforward dynamic programming approach without any space optimization.\n/// It may consume more memory for larger input strings compared to the optimized version.\npub fn naive_levenshtein_distance(string1: &str, string2: &str) -> usize {\n    let distance_matrix: Vec<Vec<usize>> = (0..=string1.len())\n        .map(|i| {\n            (0..=string2.len())\n                .map(|j| {\n                    if i == 0 {\n                        j\n                    } else if j == 0 {\n                        i\n                    } else {\n                        0\n                    }\n                })\n                .collect()\n        })\n        .collect();\n\n    let updated_matrix = (1..=string1.len()).fold(distance_matrix, |matrix, i| {\n        (1..=string2.len()).fold(matrix, |mut inner_matrix, j| {\n            let cost = usize::from(string1.as_bytes()[i - 1] != string2.as_bytes()[j - 1]);\n            inner_matrix[i][j] = (inner_matrix[i - 1][j - 1] + cost)\n                .min(inner_matrix[i][j - 1] + 1)\n                .min(inner_matrix[i - 1][j] + 1);\n            inner_matrix\n        })\n    });\n\n    updated_matrix[string1.len()][string2.len()]\n}\n\n/// Calculates the Levenshtein distance between two strings using an optimized dynamic programming approach.\n///\n/// This edit distance is defined as 1 point per insertion, substitution, or deletion required to make the strings equal.\n///\n/// # Arguments\n///\n/// * `string1` - The first string.\n/// * `string2` - The second string.\n///\n/// # Returns\n///\n/// The Levenshtein distance between the two input strings.\n/// For a detailed explanation, check the example on [Wikipedia](https://en.wikipedia.org/wiki/Levenshtein_distance).\n/// This function iterates over the bytes in the string, so it may not behave entirely as expected for non-ASCII strings.\n///\n/// Note that this implementation utilizes an optimized dynamic programming approach, significantly reducing the space complexity from O(nm) to O(n), where n and m are the lengths of `string1` and `string2`.\n///\n/// Additionally, it minimizes space usage by leveraging the shortest string horizontally and the longest string vertically in the computation matrix.\n///\n/// # Complexity\n///\n/// - Time complexity: O(nm),\n/// - Space complexity: O(n),\n///\n/// where n and m are lengths of `string1` and `string2`.\npub fn optimized_levenshtein_distance(string1: &str, string2: &str) -> usize {\n    if string1.is_empty() {\n        return string2.len();\n    }\n    let l1 = string1.len();\n    let mut prev_dist: Vec<usize> = (0..=l1).collect();\n\n    for (row, c2) in string2.chars().enumerate() {\n        // we'll keep a reference to matrix[i-1][j-1] (top-left cell)\n        let mut prev_substitution_cost = prev_dist[0];\n        // diff with empty string, since `row` starts at 0, it's `row + 1`\n        prev_dist[0] = row + 1;\n\n        for (col, c1) in string1.chars().enumerate() {\n            // \"on the left\" in the matrix (i.e. the value we just computed)\n            let deletion_cost = prev_dist[col] + 1;\n            // \"on the top\" in the matrix (means previous)\n            let insertion_cost = prev_dist[col + 1] + 1;\n            let substitution_cost = if c1 == c2 {\n                // last char is the same on both ends, so the min_distance is left unchanged from matrix[i-1][i+1]\n                prev_substitution_cost\n            } else {\n                // substitute the last character\n                prev_substitution_cost + 1\n            };\n            // save the old value at (i-1, j-1)\n            prev_substitution_cost = prev_dist[col + 1];\n            prev_dist[col + 1] = _min3(deletion_cost, insertion_cost, substitution_cost);\n        }\n    }\n    prev_dist[l1]\n}\n\n#[inline]\nfn _min3<T: Ord>(a: T, b: T, c: T) -> T {\n    min(a, min(b, c))\n}\n\n#[cfg(test)]\nmod tests {\n    const LEVENSHTEIN_DISTANCE_TEST_CASES: &[(&str, &str, usize)] = &[\n        (\"\", \"\", 0),\n        (\"Hello, World!\", \"Hello, World!\", 0),\n        (\"\", \"Rust\", 4),\n        (\"horse\", \"ros\", 3),\n        (\"tan\", \"elephant\", 6),\n        (\"execute\", \"intention\", 8),\n    ];\n\n    macro_rules! levenshtein_distance_tests {\n        ($function:ident) => {\n            mod $function {\n                use super::*;\n\n                fn run_test_case(string1: &str, string2: &str, expected_distance: usize) {\n                    assert_eq!(super::super::$function(string1, string2), expected_distance);\n                    assert_eq!(super::super::$function(string2, string1), expected_distance);\n                    assert_eq!(super::super::$function(string1, string1), 0);\n                    assert_eq!(super::super::$function(string2, string2), 0);\n                }\n\n                #[test]\n                fn test_levenshtein_distance() {\n                    for &(string1, string2, expected_distance) in\n                        LEVENSHTEIN_DISTANCE_TEST_CASES.iter()\n                    {\n                        run_test_case(string1, string2, expected_distance);\n                    }\n                }\n            }\n        };\n    }\n\n    levenshtein_distance_tests!(naive_levenshtein_distance);\n    levenshtein_distance_tests!(optimized_levenshtein_distance);\n}\n"
  },
  {
    "path": "src/string/lipogram.rs",
    "content": "use std::collections::HashSet;\n\n/// Represents possible errors that can occur when checking for lipograms.\n#[derive(Debug, PartialEq, Eq)]\npub enum LipogramError {\n    /// Indicates that a non-alphabetic character was found in the input.\n    NonAlphabeticCharacter,\n    /// Indicates that a missing character is not in lowercase.\n    NonLowercaseMissingChar,\n}\n\n/// Computes the set of missing alphabetic characters from the input string.\n///\n/// # Arguments\n///\n/// * `in_str` - A string slice that contains the input text.\n///\n/// # Returns\n///\n/// Returns a `HashSet<char>` containing the lowercase alphabetic characters that are not present in `in_str`.\nfn compute_missing(in_str: &str) -> HashSet<char> {\n    let alphabet: HashSet<char> = ('a'..='z').collect();\n\n    let letters_used: HashSet<char> = in_str\n        .to_lowercase()\n        .chars()\n        .filter(|c| c.is_ascii_alphabetic())\n        .collect();\n\n    alphabet.difference(&letters_used).cloned().collect()\n}\n\n/// Checks if the provided string is a lipogram, meaning it is missing specific characters.\n///\n/// # Arguments\n///\n/// * `lipogram_str` - A string slice that contains the text to be checked for being a lipogram.\n/// * `missing_chars` - A reference to a `HashSet<char>` containing the expected missing characters.\n///\n/// # Returns\n///\n/// Returns `Ok(true)` if the string is a lipogram that matches the provided missing characters,\n/// `Ok(false)` if it does not match, or a `LipogramError` if the input contains invalid characters.\npub fn is_lipogram(\n    lipogram_str: &str,\n    missing_chars: &HashSet<char>,\n) -> Result<bool, LipogramError> {\n    for &c in missing_chars {\n        if !c.is_lowercase() {\n            return Err(LipogramError::NonLowercaseMissingChar);\n        }\n    }\n\n    for c in lipogram_str.chars() {\n        if !c.is_ascii_alphabetic() && !c.is_whitespace() {\n            return Err(LipogramError::NonAlphabeticCharacter);\n        }\n    }\n\n    let missing = compute_missing(lipogram_str);\n    Ok(missing == *missing_chars)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_lipogram {\n        ($($name:ident: $tc:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, missing_chars, expected) = $tc;\n                    assert_eq!(is_lipogram(input, &missing_chars), expected);\n                }\n            )*\n        }\n    }\n\n    test_lipogram! {\n        perfect_pangram: (\n            \"The quick brown fox jumps over the lazy dog\",\n            HashSet::from([]),\n            Ok(true)\n        ),\n        lipogram_single_missing: (\n            \"The quick brown fox jumped over the lazy dog\",\n            HashSet::from(['s']),\n            Ok(true)\n        ),\n        lipogram_multiple_missing: (\n            \"The brown fox jumped over the lazy dog\",\n            HashSet::from(['q', 'i', 'c', 'k', 's']),\n            Ok(true)\n        ),\n        long_lipogram_single_missing: (\n            \"A jovial swain should not complain of any buxom fair who mocks his pain and thinks it gain to quiz his awkward air\",\n            HashSet::from(['e']),\n            Ok(true)\n        ),\n        invalid_non_lowercase_chars: (\n            \"The quick brown fox jumped over the lazy dog\",\n            HashSet::from(['X']),\n            Err(LipogramError::NonLowercaseMissingChar)\n        ),\n        invalid_non_alphabetic_input: (\n            \"The quick brown fox jumps over the lazy dog 123@!\",\n            HashSet::from([]),\n            Err(LipogramError::NonAlphabeticCharacter)\n        ),\n    }\n}\n"
  },
  {
    "path": "src/string/manacher.rs",
    "content": "pub fn manacher(s: String) -> String {\n    let l = s.len();\n    if l <= 1 {\n        return s;\n    }\n\n    // MEMO: We need to detect odd palindrome as well,\n    // therefore, inserting dummy string so that\n    // we can find a pair with dummy center character.\n    let mut chars: Vec<char> = Vec::with_capacity(s.len() * 2 + 1);\n    for c in s.chars() {\n        chars.push('#');\n        chars.push(c);\n    }\n    chars.push('#');\n\n    // List: storing the length of palindrome at each index of string\n    let mut length_of_palindrome = vec![1usize; chars.len()];\n    // Integer: Current checking palindrome's center index\n    let mut current_center: usize = 0;\n    // Integer: Right edge index existing the radius away from current center\n    let mut right_from_current_center: usize = 0;\n\n    for i in 0..chars.len() {\n        // 1: Check if we are looking at right side of palindrome.\n        if right_from_current_center > i && i > current_center {\n            // 1-1: If so copy from the left side of palindrome.\n            // If the value + index exceeds the right edge index, we should cut and check palindrome later #3.\n            length_of_palindrome[i] = std::cmp::min(\n                right_from_current_center - i,\n                length_of_palindrome[2 * current_center - i],\n            );\n            // 1-2: Move the checking palindrome to new index if it exceeds the right edge.\n            if length_of_palindrome[i] + i >= right_from_current_center {\n                current_center = i;\n                right_from_current_center = length_of_palindrome[i] + i;\n                // 1-3: If radius exceeds the end of list, it means checking is over.\n                // You will never get the larger value because the string will get only shorter.\n                if right_from_current_center >= chars.len() - 1 {\n                    break;\n                }\n            } else {\n                // 1-4: If the checking index doesn't exceeds the right edge,\n                // it means the length is just as same as the left side.\n                // You don't need to check anymore.\n                continue;\n            }\n        }\n\n        // Integer: Current radius from checking index\n        // If it's copied from left side and more than 1,\n        // it means it's ensured so you don't need to check inside radius.\n        let mut radius: usize = (length_of_palindrome[i] - 1) / 2;\n        radius += 1;\n        // 2: Checking palindrome.\n        // Need to care about overflow usize.\n        while i >= radius && i + radius <= chars.len() - 1 && chars[i - radius] == chars[i + radius]\n        {\n            length_of_palindrome[i] += 2;\n            radius += 1;\n        }\n    }\n\n    // 3: Find the maximum length and generate answer.\n    let center_of_max = length_of_palindrome\n        .iter()\n        .enumerate()\n        .max_by_key(|(_, &value)| value)\n        .map(|(idx, _)| idx)\n        .unwrap();\n    let radius_of_max = (length_of_palindrome[center_of_max] - 1) / 2;\n    let answer = &chars[(center_of_max - radius_of_max)..=(center_of_max + radius_of_max)]\n        .iter()\n        .collect::<String>();\n    answer.replace('#', \"\")\n}\n\n#[cfg(test)]\nmod tests {\n    use super::manacher;\n\n    #[test]\n    fn get_longest_palindrome_by_manacher() {\n        assert_eq!(manacher(\"babad\".to_string()), \"aba\".to_string());\n        assert_eq!(manacher(\"cbbd\".to_string()), \"bb\".to_string());\n        assert_eq!(manacher(\"a\".to_string()), \"a\".to_string());\n\n        let ac_ans = manacher(\"ac\".to_string());\n        assert!(ac_ans == *\"a\" || ac_ans == *\"c\");\n    }\n}\n"
  },
  {
    "path": "src/string/mod.rs",
    "content": "mod aho_corasick;\nmod anagram;\nmod autocomplete_using_trie;\nmod boyer_moore_search;\nmod burrows_wheeler_transform;\nmod duval_algorithm;\nmod hamming_distance;\nmod isogram;\nmod isomorphism;\nmod jaro_winkler_distance;\nmod knuth_morris_pratt;\nmod levenshtein_distance;\nmod lipogram;\nmod manacher;\nmod palindrome;\nmod pangram;\nmod rabin_karp;\nmod reverse;\nmod run_length_encoding;\nmod shortest_palindrome;\nmod suffix_array;\nmod suffix_array_manber_myers;\nmod suffix_tree;\nmod z_algorithm;\n\npub use self::aho_corasick::AhoCorasick;\npub use self::anagram::check_anagram;\npub use self::autocomplete_using_trie::Autocomplete;\npub use self::boyer_moore_search::boyer_moore_search;\npub use self::burrows_wheeler_transform::{\n    burrows_wheeler_transform, inv_burrows_wheeler_transform,\n};\npub use self::duval_algorithm::duval_algorithm;\npub use self::hamming_distance::hamming_distance;\npub use self::isogram::is_isogram;\npub use self::isomorphism::is_isomorphic;\npub use self::jaro_winkler_distance::jaro_winkler_distance;\npub use self::knuth_morris_pratt::knuth_morris_pratt;\npub use self::levenshtein_distance::{naive_levenshtein_distance, optimized_levenshtein_distance};\npub use self::lipogram::is_lipogram;\npub use self::manacher::manacher;\npub use self::palindrome::is_palindrome;\npub use self::pangram::is_pangram;\npub use self::pangram::PangramStatus;\npub use self::rabin_karp::rabin_karp;\npub use self::reverse::reverse;\npub use self::run_length_encoding::{run_length_decoding, run_length_encoding};\npub use self::shortest_palindrome::shortest_palindrome;\npub use self::suffix_array::generate_suffix_array;\npub use self::suffix_array_manber_myers::generate_suffix_array_manber_myers;\npub use self::suffix_tree::{Node, SuffixTree};\npub use self::z_algorithm::match_pattern;\npub use self::z_algorithm::z_array;\n"
  },
  {
    "path": "src/string/palindrome.rs",
    "content": "//! A module for checking if a given string is a palindrome.\n\n/// Checks if the given string is a palindrome.\n///\n/// A palindrome is a sequence that reads the same backward as forward.\n/// This function ignores non-alphanumeric characters and is case-insensitive.\n///\n/// # Arguments\n///\n/// * `s` - A string slice that represents the input to be checked.\n///\n/// # Returns\n///\n/// * `true` if the string is a palindrome; otherwise, `false`.\npub fn is_palindrome(s: &str) -> bool {\n    let mut chars = s\n        .chars()\n        .filter(|c| c.is_alphanumeric())\n        .map(|c| c.to_ascii_lowercase());\n\n    while let (Some(c1), Some(c2)) = (chars.next(), chars.next_back()) {\n        if c1 != c2 {\n            return false;\n        }\n    }\n\n    true\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! palindrome_tests {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $inputs;\n                    assert_eq!(is_palindrome(input), expected);\n                }\n            )*\n        }\n    }\n\n    palindrome_tests! {\n        odd_palindrome: (\"madam\", true),\n        even_palindrome: (\"deified\", true),\n        single_character_palindrome: (\"x\", true),\n        single_word_palindrome: (\"eye\", true),\n        case_insensitive_palindrome: (\"RaceCar\", true),\n        mixed_case_and_punctuation_palindrome: (\"A man, a plan, a canal, Panama!\", true),\n        mixed_case_and_space_palindrome: (\"No 'x' in Nixon\", true),\n        empty_string: (\"\", true),\n        pompeii_palindrome: (\"Roma-Olima-Milo-Amor\", true),\n        napoleon_palindrome: (\"Able was I ere I saw Elba\", true),\n        john_taylor_palindrome: (\"Lewd did I live, & evil I did dwel\", true),\n        well_know_english_palindrome: (\"Never odd or even\", true),\n        palindromic_phrase: (\"Rats live on no evil star\", true),\n        names_palindrome: (\"Hannah\", true),\n        prime_minister_of_cambodia: (\"Lon Nol\", true),\n        japanese_novelist_and_manga_writer: (\"Nisio Isin\", true),\n        actor: (\"Robert Trebor\", true),\n        rock_vocalist: (\"Ola Salo\", true),\n        pokemon_species: (\"Girafarig\", true),\n        lychrel_num_56: (\"121\", true),\n        universal_palindrome_date: (\"02/02/2020\", true),\n        french_palindrome: (\"une Slave valse nu\", true),\n        finnish_palindrome: (\"saippuakivikauppias\", true),\n        non_palindrome_simple: (\"hello\", false),\n        non_palindrome_with_punctuation: (\"hello!\", false),\n        non_palindrome_mixed_case: (\"Hello, World\", false),\n    }\n}\n"
  },
  {
    "path": "src/string/pangram.rs",
    "content": "//! This module provides functionality to check if a given string is a pangram.\n//!\n//! A pangram is a sentence that contains every letter of the alphabet at least once.\n//! This module can distinguish between a non-pangram, a regular pangram, and a\n//! perfect pangram, where each letter appears exactly once.\n\nuse std::collections::HashSet;\n\n/// Represents the status of a string in relation to the pangram classification.\n#[derive(PartialEq, Debug)]\npub enum PangramStatus {\n    NotPangram,\n    Pangram,\n    PerfectPangram,\n}\n\nfn compute_letter_counts(pangram_str: &str) -> std::collections::HashMap<char, usize> {\n    let mut letter_counts = std::collections::HashMap::new();\n\n    for ch in pangram_str\n        .to_lowercase()\n        .chars()\n        .filter(|c| c.is_ascii_alphabetic())\n    {\n        *letter_counts.entry(ch).or_insert(0) += 1;\n    }\n\n    letter_counts\n}\n\n/// Determines if the input string is a pangram, and classifies it as either a regular or perfect pangram.\n///\n/// # Arguments\n///\n/// * `pangram_str` - A reference to the string slice to be checked for pangram status.\n///\n/// # Returns\n///\n/// A `PangramStatus` enum indicating whether the string is a pangram, and if so, whether it is a perfect pangram.\npub fn is_pangram(pangram_str: &str) -> PangramStatus {\n    let letter_counts = compute_letter_counts(pangram_str);\n\n    let alphabet: HashSet<char> = ('a'..='z').collect();\n    let used_letters: HashSet<_> = letter_counts.keys().cloned().collect();\n\n    if used_letters != alphabet {\n        return PangramStatus::NotPangram;\n    }\n\n    if letter_counts.values().all(|&count| count == 1) {\n        PangramStatus::PerfectPangram\n    } else {\n        PangramStatus::Pangram\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! pangram_tests {\n        ($($name:ident: $tc:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $tc;\n                    assert_eq!(is_pangram(input), expected);\n                }\n            )*\n        };\n    }\n\n    pangram_tests! {\n        test_not_pangram_simple: (\"This is not a pangram\", PangramStatus::NotPangram),\n        test_not_pangram_day: (\"today is a good day\", PangramStatus::NotPangram),\n        test_not_pangram_almost: (\"this is almost a pangram but it does not have bcfghjkqwxy and the last letter\", PangramStatus::NotPangram),\n        test_pangram_standard: (\"The quick brown fox jumps over the lazy dog\", PangramStatus::Pangram),\n        test_pangram_boxer: (\"A mad boxer shot a quick, gloved jab to the jaw of his dizzy opponent\", PangramStatus::Pangram),\n        test_pangram_discotheques: (\"Amazingly few discotheques provide jukeboxes\", PangramStatus::Pangram),\n        test_pangram_zebras: (\"How vexingly quick daft zebras jump\", PangramStatus::Pangram),\n        test_perfect_pangram_jock: (\"Mr. Jock, TV quiz PhD, bags few lynx\", PangramStatus::PerfectPangram),\n        test_empty_string: (\"\", PangramStatus::NotPangram),\n        test_repeated_letter: (\"aaaaa\", PangramStatus::NotPangram),\n        test_non_alphabetic: (\"12345!@#$%\", PangramStatus::NotPangram),\n        test_mixed_case_pangram: (\"ThE QuiCk BroWn FoX JumPs OveR tHe LaZy DoG\", PangramStatus::Pangram),\n        test_perfect_pangram_with_symbols: (\"Mr. Jock, TV quiz PhD, bags few lynx!\", PangramStatus::PerfectPangram),\n        test_long_non_pangram: (&\"a\".repeat(1000), PangramStatus::NotPangram),\n        test_near_pangram_missing_one_letter: (\"The quick brown fox jumps over the lazy do\", PangramStatus::NotPangram),\n        test_near_pangram_missing_two_letters: (\"The quick brwn f jumps ver the lazy dg\", PangramStatus::NotPangram),\n        test_near_pangram_with_special_characters: (\"Th3 qu!ck brown f0x jumps 0v3r th3 l@zy d0g.\", PangramStatus::NotPangram),\n    }\n}\n"
  },
  {
    "path": "src/string/rabin_karp.rs",
    "content": "//! This module implements the Rabin-Karp string searching algorithm.\n//! It uses a rolling hash technique to find all occurrences of a pattern\n//! within a target string efficiently.\n\nconst MOD: usize = 101;\nconst RADIX: usize = 256;\n\n/// Finds all starting indices where the `pattern` appears in the `text`.\n///\n/// # Arguments\n/// * `text` - The string where the search is performed.\n/// * `pattern` - The substring pattern to search for.\n///\n/// # Returns\n/// A vector of starting indices where the pattern is found.\npub fn rabin_karp(text: &str, pattern: &str) -> Vec<usize> {\n    if text.is_empty() || pattern.is_empty() || pattern.len() > text.len() {\n        return vec![];\n    }\n\n    let pat_hash = compute_hash(pattern);\n    let mut radix_pow = 1;\n\n    // Compute RADIX^(n-1) % MOD\n    for _ in 0..pattern.len() - 1 {\n        radix_pow = (radix_pow * RADIX) % MOD;\n    }\n\n    let mut rolling_hash = 0;\n    let mut result = vec![];\n    for i in 0..=text.len() - pattern.len() {\n        rolling_hash = if i == 0 {\n            compute_hash(&text[0..pattern.len()])\n        } else {\n            update_hash(text, i - 1, i + pattern.len() - 1, rolling_hash, radix_pow)\n        };\n        if rolling_hash == pat_hash && pattern[..] == text[i..i + pattern.len()] {\n            result.push(i);\n        }\n    }\n    result\n}\n\n/// Calculates the hash of a string using the Rabin-Karp formula.\n///\n/// # Arguments\n/// * `s` - The string to calculate the hash for.\n///\n/// # Returns\n/// The hash value of the string modulo `MOD`.\nfn compute_hash(s: &str) -> usize {\n    let mut hash_val = 0;\n    for &byte in s.as_bytes().iter() {\n        hash_val = (hash_val * RADIX + byte as usize) % MOD;\n    }\n    hash_val\n}\n\n/// Updates the rolling hash when shifting the search window.\n///\n/// # Arguments\n/// * `s` - The full text where the search is performed.\n/// * `old_idx` - The index of the character that is leaving the window.\n/// * `new_idx` - The index of the new character entering the window.\n/// * `old_hash` - The hash of the previous substring.\n/// * `radix_pow` - The precomputed value of RADIX^(n-1) % MOD.\n///\n/// # Returns\n/// The updated hash for the new substring.\nfn update_hash(\n    s: &str,\n    old_idx: usize,\n    new_idx: usize,\n    old_hash: usize,\n    radix_pow: usize,\n) -> usize {\n    let mut new_hash = old_hash;\n    let old_char = s.as_bytes()[old_idx] as usize;\n    let new_char = s.as_bytes()[new_idx] as usize;\n    new_hash = (new_hash + MOD - (old_char * radix_pow % MOD)) % MOD;\n    new_hash = (new_hash * RADIX + new_char) % MOD;\n    new_hash\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_cases {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (text, pattern, expected) = $inputs;\n                    assert_eq!(rabin_karp(text, pattern), expected);\n                }\n            )*\n        };\n    }\n\n    test_cases! {\n        single_match_at_start: (\"hello world\", \"hello\", vec![0]),\n        single_match_at_end: (\"hello world\", \"world\", vec![6]),\n        single_match_in_middle: (\"abc def ghi\", \"def\", vec![4]),\n        multiple_matches: (\"ababcabc\", \"abc\", vec![2, 5]),\n        overlapping_matches: (\"aaaaa\", \"aaa\", vec![0, 1, 2]),\n        no_match: (\"abcdefg\", \"xyz\", vec![]),\n        pattern_is_entire_string: (\"abc\", \"abc\", vec![0]),\n        target_is_multiple_patterns: (\"abcabcabc\", \"abc\", vec![0, 3, 6]),\n        empty_text: (\"\", \"abc\", vec![]),\n        empty_pattern: (\"abc\", \"\", vec![]),\n        empty_text_and_pattern: (\"\", \"\", vec![]),\n        pattern_larger_than_text: (\"abc\", \"abcd\", vec![]),\n        large_text_small_pattern: (&(\"a\".repeat(1000) + \"b\"), \"b\", vec![1000]),\n        single_char_match: (\"a\", \"a\", vec![0]),\n        single_char_no_match: (\"a\", \"b\", vec![]),\n        large_pattern_no_match: (\"abc\", \"defghi\", vec![]),\n        repeating_chars: (\"aaaaaa\", \"aa\", vec![0, 1, 2, 3, 4]),\n        special_characters: (\"abc$def@ghi\", \"$def@\", vec![3]),\n        numeric_and_alphabetic_mix: (\"abc123abc456\", \"123abc\", vec![3]),\n        case_sensitivity: (\"AbcAbc\", \"abc\", vec![]),\n    }\n}\n"
  },
  {
    "path": "src/string/reverse.rs",
    "content": "/// Reverses the given string.\n///\n/// # Arguments\n///\n/// * `text` - A string slice that holds the string to be reversed.\n///\n/// # Returns\n///\n/// * A new `String` that is the reverse of the input string.\npub fn reverse(text: &str) -> String {\n    text.chars().rev().collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_cases {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $test_case;\n                    assert_eq!(reverse(input), expected);\n                }\n            )*\n        };\n    }\n\n    test_cases! {\n        test_simple_palindrome: (\"racecar\", \"racecar\"),\n        test_non_palindrome: (\"abcdef\", \"fedcba\"),\n        test_sentence_with_spaces: (\"step on no pets\", \"step on no pets\"),\n        test_empty_string: (\"\", \"\"),\n        test_single_character: (\"a\", \"a\"),\n        test_leading_trailing_spaces: (\"  hello  \", \"  olleh  \"),\n        test_unicode_characters: (\"你好\", \"好你\"),\n        test_mixed_content: (\"a1b2c3!\", \"!3c2b1a\"),\n    }\n}\n"
  },
  {
    "path": "src/string/run_length_encoding.rs",
    "content": "pub fn run_length_encoding(target: &str) -> String {\n    if target.trim().is_empty() {\n        return \"\".to_string();\n    }\n    let mut count: i32 = 0;\n    let mut base_character: String = \"\".to_string();\n    let mut encoded_target = String::new();\n\n    for c in target.chars() {\n        if base_character == *\"\" {\n            base_character = c.to_string();\n        }\n        if c.to_string() == base_character {\n            count += 1;\n        } else {\n            encoded_target.push_str(&count.to_string());\n            count = 1;\n            encoded_target.push_str(&base_character);\n            base_character = c.to_string();\n        }\n    }\n    encoded_target.push_str(&count.to_string());\n    encoded_target.push_str(&base_character);\n\n    encoded_target\n}\n\npub fn run_length_decoding(target: &str) -> String {\n    if target.trim().is_empty() {\n        return \"\".to_string();\n    }\n    let mut character_count = String::new();\n    let mut decoded_target = String::new();\n\n    for c in target.chars() {\n        character_count.push(c);\n        let is_numeric: bool = character_count.parse::<i32>().is_ok();\n\n        if !is_numeric {\n            let pop_char: char = character_count.pop().unwrap();\n            decoded_target.push_str(\n                &pop_char\n                    .to_string()\n                    .repeat(character_count.parse().unwrap()),\n            );\n            character_count = \"\".to_string();\n        }\n    }\n\n    decoded_target\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_run_length {\n        ($($name:ident: $test_case:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (raw_str, encoded) = $test_case;\n                    assert_eq!(run_length_encoding(raw_str), encoded);\n                    assert_eq!(run_length_decoding(encoded), raw_str);\n                }\n            )*\n        };\n    }\n\n    test_run_length! {\n        empty_input: (\"\", \"\"),\n        repeated_char: (\"aaaaaaaaaa\", \"10a\"),\n        no_repeated: (\"abcdefghijk\", \"1a1b1c1d1e1f1g1h1i1j1k\"),\n        regular_input: (\"aaaaabbbcccccdddddddddd\", \"5a3b5c10d\"),\n        two_blocks_with_same_char: (\"aaabbaaaa\", \"3a2b4a\"),\n        long_input: (\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbcccccdddddddddd\", \"200a3b5c10d\"),\n    }\n}\n"
  },
  {
    "path": "src/string/shortest_palindrome.rs",
    "content": "//! This module provides functions for finding the shortest palindrome\n//! that can be formed by adding characters to the left of a given string.\n//! References\n//!\n//! - [KMP](https://www.scaler.com/topics/data-structures/kmp-algorithm/)\n//! - [Prefix Functions and KPM](https://oi-wiki.org/string/kmp/)\n\n/// Finds the shortest palindrome that can be formed by adding characters\n/// to the left of the given string `s`.\n///\n/// # Arguments\n///\n/// * `s` - A string slice that holds the input string.\n///\n/// # Returns\n///\n/// Returns a new string that is the shortest palindrome, formed by adding\n/// the necessary characters to the beginning of `s`.\npub fn shortest_palindrome(s: &str) -> String {\n    if s.is_empty() {\n        return \"\".to_string();\n    }\n\n    let original_chars: Vec<char> = s.chars().collect();\n    let suffix_table = compute_suffix(&original_chars);\n\n    let mut reversed_chars: Vec<char> = s.chars().rev().collect();\n    // The prefix of the original string matches the suffix of the reversed string.\n    let prefix_match = compute_prefix_match(&original_chars, &reversed_chars, &suffix_table);\n\n    reversed_chars.append(&mut original_chars[prefix_match[original_chars.len() - 1]..].to_vec());\n    reversed_chars.iter().collect()\n}\n\n/// Computes the suffix table used for the KMP (Knuth-Morris-Pratt) string\n/// matching algorithm.\n///\n/// # Arguments\n///\n/// * `chars` - A slice of characters for which the suffix table is computed.\n///\n/// # Returns\n///\n/// Returns a vector of `usize` representing the suffix table. Each element\n/// at index `i` indicates the longest proper suffix which is also a proper\n/// prefix of the substring `chars[0..=i]`.\npub fn compute_suffix(chars: &[char]) -> Vec<usize> {\n    let mut suffix = vec![0; chars.len()];\n    for i in 1..chars.len() {\n        let mut j = suffix[i - 1];\n        while j > 0 && chars[j] != chars[i] {\n            j = suffix[j - 1];\n        }\n        suffix[i] = j + (chars[j] == chars[i]) as usize;\n    }\n    suffix\n}\n\n/// Computes the prefix matches of the original string against its reversed\n/// version using the suffix table.\n///\n/// # Arguments\n///\n/// * `original` - A slice of characters representing the original string.\n/// * `reversed` - A slice of characters representing the reversed string.\n/// * `suffix` - A slice containing the suffix table computed for the original string.\n///\n/// # Returns\n///\n/// Returns a vector of `usize` where each element at index `i` indicates the\n/// length of the longest prefix of `original` that matches a suffix of\n/// `reversed[0..=i]`.\npub fn compute_prefix_match(original: &[char], reversed: &[char], suffix: &[usize]) -> Vec<usize> {\n    let mut match_table = vec![0; original.len()];\n    match_table[0] = usize::from(original[0] == reversed[0]);\n    for i in 1..original.len() {\n        let mut j = match_table[i - 1];\n        while j > 0 && reversed[i] != original[j] {\n            j = suffix[j - 1];\n        }\n        match_table[i] = j + usize::from(reversed[i] == original[j]);\n    }\n    match_table\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::string::is_palindrome;\n\n    macro_rules! test_shortest_palindrome {\n        ($($name:ident: $inputs:expr,)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = $inputs;\n                    assert!(is_palindrome(expected));\n                    assert_eq!(shortest_palindrome(input), expected);\n                    assert_eq!(shortest_palindrome(expected), expected);\n                }\n            )*\n        }\n    }\n\n    test_shortest_palindrome! {\n        empty: (\"\", \"\"),\n        extend_left_1: (\"aacecaaa\", \"aaacecaaa\"),\n        extend_left_2: (\"abcd\", \"dcbabcd\"),\n        unicode_1: (\"അ\", \"അ\"),\n        unicode_2: (\"a牛\", \"牛a牛\"),\n        single_char: (\"x\", \"x\"),\n        already_palindrome: (\"racecar\", \"racecar\"),\n        extend_left_3: (\"abcde\", \"edcbabcde\"),\n        extend_left_4: (\"abca\", \"acbabca\"),\n        long_string: (\"abcdefg\", \"gfedcbabcdefg\"),\n        repetitive: (\"aaaaa\", \"aaaaa\"),\n        complex: (\"abacdfgdcaba\", \"abacdgfdcabacdfgdcaba\"),\n    }\n}\n"
  },
  {
    "path": "src/string/suffix_array.rs",
    "content": "// In computer science, a suffix array is a sorted array of all suffixes of a string.\n// It is a data structure used in, among others, full-text indices, data-compression algorithms,\n// and the field of bibliometrics. Source: https://en.wikipedia.org/wiki/Suffix_array\n\nuse std::cmp::Ordering;\n\n#[derive(Clone)]\nstruct Suffix {\n    index: usize,\n    rank: (i32, i32),\n}\n\nimpl Suffix {\n    fn cmp(&self, b: &Self) -> Ordering {\n        let a = self;\n        let ((a1, a2), (b1, b2)) = (a.rank, b.rank);\n        match a1.cmp(&b1) {\n            Ordering::Equal => {\n                if a2 < b2 {\n                    Ordering::Less\n                } else {\n                    Ordering::Greater\n                }\n            }\n            o => o,\n        }\n    }\n}\n\npub fn generate_suffix_array(txt: &str) -> Vec<usize> {\n    let n = txt.len();\n    let mut suffixes: Vec<Suffix> = vec![\n        Suffix {\n            index: 0,\n            rank: (-1, -1)\n        };\n        n\n    ];\n    for (i, suf) in suffixes.iter_mut().enumerate() {\n        suf.index = i;\n        suf.rank.0 = (txt.chars().nth(i).expect(\"this should exist\") as u32 - 'a' as u32) as i32;\n        suf.rank.1 = if (i + 1) < n {\n            (txt.chars().nth(i + 1).expect(\"this should exist\") as u32 - 'a' as u32) as i32\n        } else {\n            -1\n        }\n    }\n    suffixes.sort_by(|a, b| a.cmp(b));\n    let mut ind = vec![0; n];\n    let mut k = 4;\n    while k < 2 * n {\n        let mut rank = 0;\n        let mut prev_rank = suffixes[0].rank.0;\n        suffixes[0].rank.0 = rank;\n        ind[suffixes[0].index] = 0;\n\n        for i in 1..n {\n            if suffixes[i].rank.0 == prev_rank && suffixes[i].rank.1 == suffixes[i - 1].rank.1 {\n                prev_rank = suffixes[i].rank.0;\n                suffixes[i].rank.0 = rank;\n            } else {\n                prev_rank = suffixes[i].rank.0;\n                rank += 1;\n                suffixes[i].rank.0 = rank;\n            }\n            ind[suffixes[i].index] = i;\n        }\n        for i in 0..n {\n            let next_index = suffixes[i].index + (k / 2);\n            suffixes[i].rank.1 = if next_index < n {\n                suffixes[ind[next_index]].rank.0\n            } else {\n                -1\n            }\n        }\n        suffixes.sort_by(|a, b| a.cmp(b));\n        k *= 2;\n    }\n    let mut suffix_arr = Vec::new();\n    for suf in suffixes {\n        suffix_arr.push(suf.index);\n    }\n    suffix_arr\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_suffix_array() {\n        let a = generate_suffix_array(\"banana\");\n        assert_eq!(a, vec![5, 3, 1, 0, 4, 2]);\n    }\n}\n"
  },
  {
    "path": "src/string/suffix_array_manber_myers.rs",
    "content": "pub fn generate_suffix_array_manber_myers(input: &str) -> Vec<usize> {\n    if input.is_empty() {\n        return Vec::new();\n    }\n    let n = input.len();\n    let mut suffixes: Vec<(usize, &str)> = Vec::with_capacity(n);\n\n    for (i, _suffix) in input.char_indices() {\n        suffixes.push((i, &input[i..]));\n    }\n\n    suffixes.sort_by_key(|&(_, s)| s);\n\n    let mut suffix_array: Vec<usize> = vec![0; n];\n    let mut rank = vec![0; n];\n\n    let mut cur_rank = 0;\n    let mut prev_suffix = &suffixes[0].1;\n\n    for (i, suffix) in suffixes.iter().enumerate() {\n        if &suffix.1 != prev_suffix {\n            cur_rank += 1;\n            prev_suffix = &suffix.1;\n        }\n        rank[suffix.0] = cur_rank;\n        suffix_array[i] = suffix.0;\n    }\n\n    let mut k = 1;\n    let mut new_rank: Vec<usize> = vec![0; n];\n\n    while k < n {\n        suffix_array.sort_by_key(|&x| (rank[x], rank[(x + k) % n]));\n\n        let mut cur_rank = 0;\n        let mut prev = suffix_array[0];\n        new_rank[prev] = cur_rank;\n\n        for &suffix in suffix_array.iter().skip(1) {\n            let next = suffix;\n            if (rank[prev], rank[(prev + k) % n]) != (rank[next], rank[(next + k) % n]) {\n                cur_rank += 1;\n            }\n            new_rank[next] = cur_rank;\n            prev = next;\n        }\n\n        std::mem::swap(&mut rank, &mut new_rank);\n\n        k <<= 1;\n    }\n\n    suffix_array\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_suffix_array() {\n        let input = \"banana\";\n        let expected_result = vec![5, 3, 1, 0, 4, 2];\n        assert_eq!(generate_suffix_array_manber_myers(input), expected_result);\n    }\n\n    #[test]\n    fn test_empty_string() {\n        let input = \"\";\n        let expected_result: Vec<usize> = Vec::new();\n        assert_eq!(generate_suffix_array_manber_myers(input), expected_result);\n    }\n\n    #[test]\n    fn test_single_character() {\n        let input = \"a\";\n        let expected_result = vec![0];\n        assert_eq!(generate_suffix_array_manber_myers(input), expected_result);\n    }\n    #[test]\n    fn test_repeating_characters() {\n        let input = \"zzzzzz\";\n        let expected_result = vec![5, 4, 3, 2, 1, 0];\n        assert_eq!(generate_suffix_array_manber_myers(input), expected_result);\n    }\n\n    #[test]\n    fn test_long_string() {\n        let input = \"abcdefghijklmnopqrstuvwxyz\";\n        let expected_result: Vec<usize> = (0..26).collect();\n        assert_eq!(generate_suffix_array_manber_myers(input), expected_result);\n    }\n\n    #[test]\n    fn test_mix_of_characters() {\n        let input = \"abracadabra!\";\n        let expected_result = vec![11, 10, 7, 0, 3, 5, 8, 1, 4, 6, 9, 2];\n        assert_eq!(generate_suffix_array_manber_myers(input), expected_result);\n    }\n\n    #[test]\n    fn test_whitespace_characters() {\n        let input = \" hello world \";\n        let expected_result = vec![12, 0, 6, 11, 2, 1, 10, 3, 4, 5, 8, 9, 7];\n        assert_eq!(generate_suffix_array_manber_myers(input), expected_result);\n    }\n}\n"
  },
  {
    "path": "src/string/suffix_tree.rs",
    "content": "// In computer science, a suffix tree (also called PAT tree or, in an earlier form, position tree)\n// is a compressed trie containing all the suffixes of the given text as their keys and positions\n// in the text as their values. Suffix trees allow particularly fast implementations of many\n// important string operations. Source: https://en.wikipedia.org/wiki/Suffix_tree\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct Node {\n    pub sub: String,    // substring of input string\n    pub ch: Vec<usize>, // vector of child nodes\n}\n\nimpl Node {\n    fn new(sub: String, children: Vec<usize>) -> Self {\n        Node {\n            sub,\n            ch: children.to_vec(),\n        }\n    }\n    pub fn empty() -> Self {\n        Node {\n            sub: \"\".to_string(),\n            ch: vec![],\n        }\n    }\n}\n\npub struct SuffixTree {\n    pub nodes: Vec<Node>,\n}\n\nimpl SuffixTree {\n    pub fn new(s: &str) -> Self {\n        let mut suf_tree = SuffixTree {\n            nodes: vec![Node::empty()],\n        };\n        for i in 0..s.len() {\n            let (_, substr) = s.split_at(i);\n            suf_tree.add_suffix(substr);\n        }\n        suf_tree\n    }\n    fn add_suffix(&mut self, suf: &str) {\n        let mut n = 0;\n        let mut i = 0;\n        while i < suf.len() {\n            let b = suf.chars().nth(i);\n            let mut x2 = 0;\n            let mut n2: usize;\n            loop {\n                let children = &self.nodes[n].ch;\n                if children.len() == x2 {\n                    n2 = self.nodes.len();\n                    self.nodes.push(Node::new(\n                        {\n                            let (_, sub) = suf.split_at(i);\n                            sub.to_string()\n                        },\n                        vec![],\n                    ));\n                    self.nodes[n].ch.push(n2);\n                    return;\n                }\n                n2 = children[x2];\n                if self.nodes[n2].sub.chars().next() == b {\n                    break;\n                }\n                x2 += 1;\n            }\n            let sub2 = self.nodes[n2].sub.clone();\n            let mut j = 0;\n            while j < sub2.len() {\n                if suf.chars().nth(i + j) != sub2.chars().nth(j) {\n                    let n3 = n2;\n                    n2 = self.nodes.len();\n                    self.nodes.push(Node::new(\n                        {\n                            let (sub, _) = sub2.split_at(j);\n                            sub.to_string()\n                        },\n                        vec![n3],\n                    ));\n                    let (_, temp_sub) = sub2.split_at(j);\n                    self.nodes[n3].sub = temp_sub.to_string();\n                    self.nodes[n].ch[x2] = n2;\n                    break;\n                }\n                j += 1;\n            }\n            i += j;\n            n = n2;\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_suffix_tree() {\n        let suf_tree = SuffixTree::new(\"banana$\");\n        assert_eq!(\n            suf_tree.nodes,\n            vec![\n                Node {\n                    sub: \"\".to_string(),\n                    ch: vec![1, 8, 6, 10]\n                },\n                Node {\n                    sub: \"banana$\".to_string(),\n                    ch: vec![]\n                },\n                Node {\n                    sub: \"na$\".to_string(),\n                    ch: vec![]\n                },\n                Node {\n                    sub: \"na$\".to_string(),\n                    ch: vec![]\n                },\n                Node {\n                    sub: \"na\".to_string(),\n                    ch: vec![2, 5]\n                },\n                Node {\n                    sub: \"$\".to_string(),\n                    ch: vec![]\n                },\n                Node {\n                    sub: \"na\".to_string(),\n                    ch: vec![3, 7]\n                },\n                Node {\n                    sub: \"$\".to_string(),\n                    ch: vec![]\n                },\n                Node {\n                    sub: \"a\".to_string(),\n                    ch: vec![4, 9]\n                },\n                Node {\n                    sub: \"$\".to_string(),\n                    ch: vec![]\n                },\n                Node {\n                    sub: \"$\".to_string(),\n                    ch: vec![]\n                }\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "src/string/z_algorithm.rs",
    "content": "//! This module provides functionalities to match patterns in strings\n//! and compute the Z-array for a given input string.\n\n/// Calculates the Z-value for a given substring of the input string\n/// based on a specified pattern.\n///\n/// # Parameters\n/// - `input_string`: A slice of elements that represents the input string.\n/// - `pattern`: A slice of elements representing the pattern to match.\n/// - `start_index`: The index in the input string to start checking for matches.\n/// - `z_value`: The initial Z-value to be computed.\n///\n/// # Returns\n/// The computed Z-value indicating the length of the matching prefix.\nfn calculate_z_value<T: Eq>(\n    input_string: &[T],\n    pattern: &[T],\n    start_index: usize,\n    mut z_value: usize,\n) -> usize {\n    let size = input_string.len();\n    let pattern_size = pattern.len();\n\n    while (start_index + z_value) < size && z_value < pattern_size {\n        if input_string[start_index + z_value] != pattern[z_value] {\n            break;\n        }\n        z_value += 1;\n    }\n    z_value\n}\n\n/// Initializes the Z-array value based on a previous match and updates\n/// it to optimize further calculations.\n///\n/// # Parameters\n/// - `z_array`: A mutable slice of the Z-array to be updated.\n/// - `i`: The current index in the input string.\n/// - `match_end`: The index of the last character matched in the pattern.\n/// - `last_match`: The index of the last match found.\n///\n/// # Returns\n/// The initialized Z-array value for the current index.\nfn initialize_z_array_from_previous_match(\n    z_array: &[usize],\n    i: usize,\n    match_end: usize,\n    last_match: usize,\n) -> usize {\n    std::cmp::min(z_array[i - last_match], match_end - i + 1)\n}\n\n/// Finds the starting indices of all full matches of the pattern\n/// in the Z-array.\n///\n/// # Parameters\n/// - `z_array`: A slice of the Z-array containing computed Z-values.\n/// - `pattern_size`: The length of the pattern to find in the Z-array.\n///\n/// # Returns\n/// A vector containing the starting indices of full matches.\nfn find_full_matches(z_array: &[usize], pattern_size: usize) -> Vec<usize> {\n    z_array\n        .iter()\n        .enumerate()\n        .filter_map(|(idx, &z_value)| (z_value == pattern_size).then_some(idx))\n        .collect()\n}\n\n/// Matches the occurrences of a pattern in an input string starting\n/// from a specified index.\n///\n/// # Parameters\n/// - `input_string`: A slice of elements to search within.\n/// - `pattern`: A slice of elements that represents the pattern to match.\n/// - `start_index`: The index in the input string to start the search.\n/// - `only_full_matches`: If true, only full matches of the pattern will be returned.\n///\n/// # Returns\n/// A vector containing the starting indices of the matches.\nfn match_with_z_array<T: Eq>(\n    input_string: &[T],\n    pattern: &[T],\n    start_index: usize,\n    only_full_matches: bool,\n) -> Vec<usize> {\n    let size = input_string.len();\n    let pattern_size = pattern.len();\n    let mut last_match: usize = 0;\n    let mut match_end: usize = 0;\n    let mut z_array = vec![0usize; size];\n\n    for i in start_index..size {\n        if i <= match_end {\n            z_array[i] = initialize_z_array_from_previous_match(&z_array, i, match_end, last_match);\n        }\n\n        z_array[i] = calculate_z_value(input_string, pattern, i, z_array[i]);\n\n        if i + z_array[i] > match_end + 1 {\n            match_end = i + z_array[i] - 1;\n            last_match = i;\n        }\n    }\n\n    if only_full_matches {\n        find_full_matches(&z_array, pattern_size)\n    } else {\n        z_array\n    }\n}\n\n/// Constructs the Z-array for the given input string.\n///\n/// The Z-array is an array where the i-th element is the length of the longest\n/// substring starting from s[i] that is also a prefix of s.\n///\n/// # Parameters\n/// - `input`: A slice of the input string for which the Z-array is to be constructed.\n///\n/// # Returns\n/// A vector representing the Z-array of the input string.\npub fn z_array<T: Eq>(input: &[T]) -> Vec<usize> {\n    match_with_z_array(input, input, 1, false)\n}\n\n/// Matches the occurrences of a given pattern in an input string.\n///\n/// This function acts as a wrapper around `match_with_z_array` to provide a simpler\n/// interface for pattern matching, returning only full matches.\n///\n/// # Parameters\n/// - `input`: A slice of the input string where the pattern will be searched.\n/// - `pattern`: A slice of the pattern to search for in the input string.\n///\n/// # Returns\n/// A vector of indices where the pattern matches the input string.\npub fn match_pattern<T: Eq>(input: &[T], pattern: &[T]) -> Vec<usize> {\n    match_with_z_array(input, pattern, 0, true)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    macro_rules! test_match_pattern {\n        ($($name:ident: ($input:expr, $pattern:expr, $expected:expr),)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, pattern, expected) = ($input, $pattern, $expected);\n                    assert_eq!(match_pattern(input.as_bytes(), pattern.as_bytes()), expected);\n                }\n            )*\n        };\n    }\n\n    macro_rules! test_z_array_cases {\n        ($($name:ident: ($input:expr, $expected:expr),)*) => {\n            $(\n                #[test]\n                fn $name() {\n                    let (input, expected) = ($input, $expected);\n                    assert_eq!(z_array(input.as_bytes()), expected);\n                }\n            )*\n        };\n    }\n\n    test_match_pattern! {\n        simple_match: (\"abcabcabc\", \"abc\", vec![0, 3, 6]),\n        no_match: (\"abcdef\", \"xyz\", vec![]),\n        single_char_match: (\"aaaaaa\", \"a\", vec![0, 1, 2, 3, 4, 5]),\n        overlapping_match: (\"abababa\", \"aba\", vec![0, 2, 4]),\n        full_string_match: (\"pattern\", \"pattern\", vec![0]),\n        empty_pattern: (\"nonempty\", \" \", vec![]),\n        pattern_larger_than_text: (\"small\", \"largerpattern\", vec![]),\n        repeated_pattern_in_text: (\n            \"aaaaaaaa\",\n            \"aaa\",\n            vec![0, 1, 2, 3, 4, 5]\n        ),\n        pattern_not_in_lipsum: (\n            concat!(\n                \"lorem ipsum dolor sit amet, consectetur \",\n                \"adipiscing elit, sed do eiusmod tempor \",\n                \"incididunt ut labore et dolore magna aliqua\"\n            ),\n            \";alksdjfoiwer\",\n            vec![]\n        ),\n        pattern_in_lipsum: (\n            concat!(\n                \"lorem ipsum dolor sit amet, consectetur \",\n                \"adipiscing elit, sed do eiusmod tempor \",\n                \"incididunt ut labore et dolore magna aliqua\"\n            ),\n            \"m\",\n            vec![4, 10, 23, 68, 74, 110]\n        ),\n    }\n\n    test_z_array_cases! {\n        basic_z_array: (\"aabaabab\", vec![0, 1, 0, 4, 1, 0, 1, 0]),\n        empty_string: (\"\", vec![]),\n        single_char_z_array: (\"a\", vec![0]),\n        repeated_char_z_array: (\"aaaaaa\", vec![0, 5, 4, 3, 2, 1]),\n    }\n}\n"
  }
]