[
  {
    "path": ".devcontainer/devcontainer.json",
    "content": "{\n\t\"name\": \"The Algorithms C#\",\n\t\"image\": \"mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm\",\n\t\"customizations\": {\n\t\t\"vscode\": {\n\t\t\t\"extensions\": [\n\t\t\t\t\"ms-dotnettools.csharp\",\n\t\t\t\t\"ms-dotnettools.csdevkit\",\n\t\t\t\t\"nunit.nunit-adapter\",\n\t\t\t\t\"fluentassertions.fluentassertions\"\n\t\t\t]\n\t\t}\n\t},\n\t\"postCreateCommand\": \"sudo chown -R $(whoami) /workspaces\"\n}"
  },
  {
    "path": ".editorconfig",
    "content": "[*]\ncharset = utf-8\nend_of_line = lf\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nindent_style = space\nindent_size = 4\n\n# Microsoft .NET properties\ncsharp_new_line_before_members_in_object_initializers = false\ncsharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion\ncsharp_space_after_cast = false\ncsharp_style_var_elsewhere = true:suggestion\ncsharp_style_var_for_built_in_types = true:suggestion\ncsharp_style_var_when_type_is_apparent = true:suggestion\ndotnet_naming_rule.private_constants_rule.import_to_resharper = as_predefined\ndotnet_naming_rule.private_constants_rule.severity = warning\ndotnet_naming_rule.private_constants_rule.style = upper_camel_case_style\ndotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols\ndotnet_naming_rule.private_instance_fields_rule.import_to_resharper = as_predefined\ndotnet_naming_rule.private_instance_fields_rule.severity = warning\ndotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style\ndotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols\ndotnet_naming_rule.private_static_fields_rule.import_to_resharper = as_predefined\ndotnet_naming_rule.private_static_fields_rule.severity = warning\ndotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style_1\ndotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols\ndotnet_naming_rule.private_static_readonly_rule.import_to_resharper = as_predefined\ndotnet_naming_rule.private_static_readonly_rule.severity = warning\ndotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style\ndotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols\ndotnet_naming_rule.unity_serialized_field_rule.import_to_resharper = True\ndotnet_naming_rule.unity_serialized_field_rule.resharper_description = Unity serialized field\ndotnet_naming_rule.unity_serialized_field_rule.resharper_guid = 5f0fdb63-c892-4d2c-9324-15c80b22a7ef\ndotnet_naming_rule.unity_serialized_field_rule.severity = warning\ndotnet_naming_rule.unity_serialized_field_rule.style = lower_camel_case_style\ndotnet_naming_rule.unity_serialized_field_rule.symbols = unity_serialized_field_symbols\ndotnet_naming_style.lower_camel_case_style.capitalization = camel_case\ndotnet_naming_style.lower_camel_case_style_1.capitalization = camel_case\ndotnet_naming_style.lower_camel_case_style_1.required_prefix = _\ndotnet_naming_style.upper_camel_case_style.capitalization = pascal_case\ndotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private\ndotnet_naming_symbols.private_constants_symbols.applicable_kinds = field\ndotnet_naming_symbols.private_constants_symbols.required_modifiers = const\ndotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private\ndotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field\ndotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private\ndotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field\ndotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static\ndotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private\ndotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field\ndotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static,readonly\ndotnet_naming_symbols.unity_serialized_field_symbols.applicable_accessibilities = *\ndotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds = unity_serialised_field\ndotnet_naming_symbols.unity_serialized_field_symbols.resharper_applicable_kinds = unity_serialised_field\ndotnet_naming_symbols.unity_serialized_field_symbols.resharper_required_modifiers = instance\ndotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none\ndotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none\ndotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none\ndotnet_style_predefined_type_for_locals_parameters_members = true:suggestion\ndotnet_style_predefined_type_for_member_access = true:suggestion\ndotnet_style_qualification_for_event = false:suggestion\ndotnet_style_qualification_for_field = false:suggestion\ndotnet_style_qualification_for_method = false:suggestion\ndotnet_style_qualification_for_property = false:suggestion\ndotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion\n\n# ReSharper properties\nresharper_autodetect_indent_settings = true\nresharper_braces_for_dowhile = required_for_multiline_statement\nresharper_braces_for_fixed = required_for_multiline_statement\nresharper_braces_for_for = required_for_multiline_statement\nresharper_braces_for_foreach = required_for_multiline_statement\nresharper_braces_for_ifelse = required_for_multiline_statement\nresharper_braces_for_lock = required_for_multiline_statement\nresharper_braces_for_using = required_for_multiline_statement\nresharper_braces_for_while = required_for_multiline_statement\nresharper_constructor_or_destructor_body = expression_body\nresharper_csharp_insert_final_newline = true\nresharper_csharp_wrap_after_declaration_lpar = true\nresharper_csharp_wrap_lines = false\nresharper_local_function_body = expression_body\nresharper_method_or_operator_body = expression_body\nresharper_new_line_before_while = true\nresharper_place_attribute_on_same_line = false\nresharper_space_after_cast = false\nresharper_space_within_single_line_array_initializer_braces = true\nresharper_trailing_comma_in_multiline_lists = true\nresharper_use_indent_from_vs = false\n\n# ReSharper inspection severities\nresharper_arrange_redundant_parentheses_highlighting = hint\nresharper_arrange_this_qualifier_highlighting = hint\nresharper_arrange_trailing_comma_in_multiline_lists_highlighting = suggestion\nresharper_arrange_type_member_modifiers_highlighting = hint\nresharper_arrange_type_modifiers_highlighting = hint\nresharper_built_in_type_reference_style_for_member_access_highlighting = hint\nresharper_built_in_type_reference_style_highlighting = hint\nresharper_redundant_base_qualifier_highlighting = warning\nresharper_suggest_var_or_type_built_in_types_highlighting = hint\nresharper_suggest_var_or_type_elsewhere_highlighting = hint\nresharper_suggest_var_or_type_simple_types_highlighting = hint\nresharper_web_config_module_not_resolved_highlighting = warning\nresharper_web_config_type_not_resolved_highlighting = warning\nresharper_web_config_wrong_module_highlighting = warning\n\n[{*.har,*.inputactions,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,jest.config}]\nindent_style = space\nindent_size = 2\n\n[{*.yaml,*.yml}]\nindent_style = space\nindent_size = 2\n\n[*.{appxmanifest,asax,ascx,aspx,axaml,build,cg,cginc,compute,cs,cshtml,dtd,fs,fsi,fsscript,fsx,hlsl,hlsli,hlslinc,master,ml,mli,nuspec,paml,razor,resw,resx,shader,skin,usf,ush,vb,xaml,xamlx,xoml,xsd}]\nindent_style = space\nindent_size = 4\ntab_width = 4\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "* @siriak\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: Something works wrong\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nHow to reproduce the behavior. Initial conditions, parameters, etc.\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Actual behavior**\nA clear and concise description of what has happened.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: Add something cool\nlabels: enhancement\nassignees: ''\n\n---\n\nI propose to add [algorithm/data structure] [name]. It helps to solve problems such as [...]. It's best described in book(s), on website(s): [...].\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "<!--\nPlease include a summary of the change.\nPlease also include relevant motivation and context (if applicable).\nPut 'x' in between square brackets to mark an item as complete.\n[x] means checked checkbox\n[ ] means unchecked checkbox\n-->\n\n- [ ] I have performed a self-review of my code\n- [ ] My code follows the style guidelines of this project\n- [ ] I have added tests that prove my fix is effective or that my feature works\n- [ ] New and existing unit tests pass locally with my changes\n- [ ] Comments in areas I changed are up to date\n- [ ] I have added comments to hard-to-understand areas of my code\n- [ ] I have made corresponding changes to the README.md\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non: [push, pull_request]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n        with:\n          fetch-depth: 0\n      - name: Setup .NET SDK\n        uses: actions/setup-dotnet@v3\n        with:\n          dotnet-version: 8.x\n      - name: Restore\n        run: dotnet restore\n      - name: Build\n        run: dotnet build --no-restore\n      - name: Test\n        run: dotnet test --no-restore --collect \"XPlat Code Coverage\"\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@v4\n        with:\n          fail_ci_if_error: true\n      - name: Upload coverage to codecov (with token)\n        if: >\n          github.repository == 'TheAlgorithms/C-Sharp' &&\n          (github.event_name != 'pull_request' ||\n          github.event.pull_request.head.repo.full_name == github.repository)\n        uses: codecov/codecov-action@v4\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          fail_ci_if_error: true\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: 'Close stale issues and PRs'\non:\n  schedule:\n    - cron: '0 0 * * *'\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/stale@v4\n        with:\n          stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.'\n          close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'\n          stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.'\n          close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.'\n          exempt-issue-labels: 'dont-close'\n          exempt-pr-labels: 'dont-close'\n          days-before-stale: 30\n          days-before-close: 7\n"
  },
  {
    "path": ".gitignore",
    "content": "# Visual Studio cache/options directory\n.vs/\n\n# Rider cache/options directory\n.idea/\n\n# Rider user config file\nC-Sharp.sln.DotSettings.user\n\n# Build results\nbin/\nobj/\nTestResults/\n"
  },
  {
    "path": "Algorithms/Algorithms.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <CodeAnalysisRuleSet>..\\stylecop.ruleset</CodeAnalysisRuleSet>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n    <DocumentationFile>./bin/Algorithms.xml</DocumentationFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <AdditionalFiles Include=\"..\\stylecop.json\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"SkiaSharp\" Version=\"2.88.8\" />\n    <PackageReference Include=\"SkiaSharp.NativeAssets.Linux.NoDependencies\" Version=\"2.88.8\" />\n    <PackageReference Include=\"StyleCop.Analyzers\" Version=\"1.2.0-beta.556\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\DataStructures\\DataStructures.csproj\" />\n    <ProjectReference Include=\"..\\Utilities\\Utilities.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Algorithms/Crypto/Digests/AsconDigest.cs",
    "content": "using System.Runtime.CompilerServices;\nusing Algorithms.Crypto.Utils;\n\nnamespace Algorithms.Crypto.Digests;\n\n/// <summary>\n/// Implements the Ascon cryptographic hash algorithm, providing both the standard Ascon-Hash and the Ascon-HashA variants.\n/// </summary>\n/// <remarks>\n/// The <see cref=\"AsconDigest\"/> class implements the Ascon hash function, a lightweight cryptographic algorithm designed for\n/// resource-constrained environments such as IoT devices. It provides two variants:\n/// <list type=\"bullet\">\n/// <item>\n/// <description>\n/// <see cref=\"AsconParameters.AsconHash\"/>: The standard Ascon-Hash variant with 12 rounds of the permutation function for enhanced security.\n/// </description>\n/// </item>\n/// <item>\n/// <description>\n/// <see cref=\"AsconParameters.AsconHashA\"/>: A performance-optimized variant with 8 rounds of the permutation function, offering a trade-off between security and performance.\n/// </description>\n/// </item>\n/// </list>\n/// <br />\n/// The AsconDigest processes data in 8-byte blocks, accumulating input until a block is complete, at which point it applies\n/// the permutation function to update the internal state. After all data has been processed, the hash value can be finalized\n/// and retrieved.\n/// <br />\n/// Ascon was designed to meet the requirements of lightweight cryptography, making it ideal for devices with limited computational power.\n/// </remarks>\npublic class AsconDigest : IDigest\n{\n    public enum AsconParameters\n    {\n        /// <summary>\n        /// Represents the Ascon Hash variant, the standard cryptographic hashing function of the Ascon family.\n        /// </summary>\n        /// <remarks>\n        /// AsconHash is the primary hashing algorithm in the Ascon family. It is designed for efficiency and security\n        /// in resource-constrained environments, such as IoT devices, and provides high resistance to cryptanalytic attacks.\n        /// This variant uses 12 rounds of the permutation function for increased security.\n        /// </remarks>\n        AsconHash,\n\n        /// <summary>\n        /// Represents the Ascon HashA variant, an alternative variant of the Ascon hashing function with fewer permutation rounds.\n        /// </summary>\n        /// <remarks>\n        /// AsconHashA is a variant of the Ascon hashing function that uses fewer rounds (8 rounds) of the permutation function,\n        /// trading off some security for improved performance in specific scenarios. It is still designed to be secure for many\n        /// applications, but it operates faster in environments where computational resources are limited.\n        /// </remarks>\n        AsconHashA,\n    }\n\n    /// <summary>\n    /// Specifies the Ascon variant being used (either Ascon-Hash or Ascon-HashA). This defines the cryptographic algorithm's behavior.\n    /// </summary>\n    private readonly AsconParameters asconParameters;\n\n    /// <summary>\n    /// The number of permutation rounds applied in the Ascon cryptographic process. This is determined by the selected Ascon variant.\n    /// </summary>\n    private readonly int asconPbRounds;\n\n    /// <summary>\n    /// Internal buffer that temporarily stores input data before it is processed in 8-byte blocks. The buffer is cleared after each block is processed.\n    /// </summary>\n    private readonly byte[] buffer = new byte[8];\n\n    /// <summary>\n    /// Internal state variable <c>x0</c> used in the cryptographic permutation function. This is updated continuously as input data is processed.\n    /// </summary>\n    private ulong x0;\n\n    /// <summary>\n    /// Internal state variable <c>x1</c> used in the cryptographic permutation function. This, along with other state variables, is updated during each round.\n    /// </summary>\n    private ulong x1;\n\n    /// <summary>\n    /// Internal state variable <c>x2</c> used in the cryptographic permutation function. It helps track the evolving state of the digest.\n    /// </summary>\n    private ulong x2;\n\n    /// <summary>\n    /// Internal state variable <c>x3</c> used in the cryptographic permutation function, contributing to the mixing and non-linearity of the state.\n    /// </summary>\n    private ulong x3;\n\n    /// <summary>\n    /// Internal state variable <c>x4</c> used in the cryptographic permutation function. This, along with <c>x0</c> to <c>x3</c>, ensures cryptographic security.\n    /// </summary>\n    private ulong x4;\n\n    /// <summary>\n    /// Tracks the current position within the <c>buffer</c> array. When <c>bufferPosition</c> reaches 8, the buffer is processed and reset.\n    /// </summary>\n    private int bufferPosition;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"AsconDigest\"/> class with the specified Ascon parameters.\n    /// </summary>\n    /// <param name=\"parameters\">The Ascon variant to use, either <see cref=\"AsconParameters.AsconHash\"/> or <see cref=\"AsconParameters.AsconHashA\"/>.</param>\n    /// <remarks>\n    /// This constructor sets up the digest by selecting the appropriate number of permutation rounds based on the Ascon variant.\n    /// <list type=\"bullet\">\n    /// <item><description>For <see cref=\"AsconParameters.AsconHash\"/>, 12 permutation rounds are used.</description></item>\n    /// <item><description>For <see cref=\"AsconParameters.AsconHashA\"/>, 8 permutation rounds are used.</description></item>\n    /// </list>\n    /// If an unsupported parameter is provided, the constructor throws an <see cref=\"ArgumentException\"/> to indicate that the parameter is invalid.\n    /// The internal state of the digest is then reset to prepare for processing input data.\n    /// </remarks>\n    /// <exception cref=\"ArgumentException\">Thrown when an invalid parameter setting is provided for Ascon Hash.</exception>\n    public AsconDigest(AsconParameters parameters)\n    {\n        // Set the Ascon parameter (AsconHash or AsconHashA) for this instance.\n        asconParameters = parameters;\n\n        // Determine the number of permutation rounds based on the Ascon variant.\n        asconPbRounds = parameters switch\n        {\n            AsconParameters.AsconHash => 12,  // 12 rounds for Ascon-Hash variant.\n            AsconParameters.AsconHashA => 8,  // 8 rounds for Ascon-HashA variant.\n            _ => throw new ArgumentException(\"Invalid parameter settings for Ascon Hash\"), // Throw exception for invalid parameter.\n        };\n\n        // Reset the internal state to prepare for new input.\n        Reset();\n    }\n\n    /// <summary>\n    /// Gets the name of the cryptographic algorithm based on the selected Ascon parameter.\n    /// </summary>\n    /// <value>\n    /// A string representing the name of the algorithm variant, either \"Ascon-Hash\" or \"Ascon-HashA\".\n    /// </value>\n    /// <remarks>\n    /// This property determines the algorithm name based on the selected Ascon variant when the instance was initialized.\n    /// It supports two variants:\n    /// <list type=\"bullet\">\n    /// <item><description>\"Ascon-Hash\" for the <see cref=\"AsconParameters.AsconHash\"/> variant.</description></item>\n    /// <item><description>\"Ascon-HashA\" for the <see cref=\"AsconParameters.AsconHashA\"/> variant.</description></item>\n    /// </list>\n    /// If an unsupported or unknown parameter is used, the property throws an <see cref=\"InvalidOperationException\"/>.\n    /// </remarks>\n    /// <exception cref=\"InvalidOperationException\">Thrown if an unknown Ascon parameter is encountered.</exception>\n    public string AlgorithmName\n    {\n        get\n        {\n            return asconParameters switch\n            {\n                AsconParameters.AsconHash => \"Ascon-Hash\",  // Return \"Ascon-Hash\" for AsconHash variant.\n                AsconParameters.AsconHashA => \"Ascon-HashA\", // Return \"Ascon-HashA\" for AsconHashA variant.\n                _ => throw new InvalidOperationException(), // Throw an exception for unknown Ascon parameters.\n            };\n        }\n    }\n\n    /// <summary>\n    /// Gets the size of the resulting hash produced by the digest, in bytes.\n    /// </summary>\n    /// <returns>The size of the hash, which is 32 bytes (256 bits) for this digest implementation.</returns>\n    /// <remarks>\n    /// This method returns the fixed size of the hash output produced by the digest algorithm. In this implementation,\n    /// the digest produces a 256-bit hash, which corresponds to 32 bytes. This is typical for cryptographic hash functions\n    /// that aim to provide a high level of security by generating a large output size.\n    /// </remarks>\n    public int GetDigestSize() => 32;\n\n    /// <summary>\n    /// Gets the internal block size of the digest in bytes.\n    /// </summary>\n    /// <returns>The internal block size of the digest, which is 8 bytes (64 bits).</returns>\n    /// <remarks>\n    /// This method returns the block size that the digest algorithm uses when processing input data. The input is processed\n    /// in chunks (blocks) of 8 bytes at a time. This block size determines how the input data is split and processed in multiple\n    /// steps before producing the final hash.\n    /// </remarks>\n    public int GetByteLength() => 8;\n\n    /// <summary>\n    /// Updates the cryptographic state by processing a single byte of input and adding it to the internal buffer.\n    /// </summary>\n    /// <param name=\"input\">The byte to be added to the internal buffer and processed.</param>\n    /// <remarks>\n    /// This method collects input bytes in an internal buffer. Once the buffer is filled (reaching 8 bytes), the buffer is processed\n    /// by converting it into a 64-bit unsigned integer in big-endian format and XORing it with the internal state variable <c>x0</c>.\n    /// After processing the buffer, the permutation function <see cref=\"P(int)\"/> is applied to mix the internal state, and the buffer position is reset to zero.\n    /// <br/><br/>\n    /// If the buffer has not yet reached 8 bytes, the method simply adds the input byte to the buffer and waits for further input.\n    /// </remarks>\n    public void Update(byte input)\n    {\n        // Add the input byte to the buffer.\n        buffer[bufferPosition] = input;\n\n        // If the buffer is not full (less than 8 bytes), increment the buffer position and return early.\n        if (++bufferPosition != 8)\n        {\n            return; // Wait for more input to fill the buffer before processing.\n        }\n\n        // Once the buffer is full (8 bytes), convert the buffer to a 64-bit integer (big-endian) and XOR it with the state.\n        x0 ^= ByteEncodingUtils.BigEndianToUint64(buffer, 0);\n\n        // Apply the permutation function to mix the state.\n        P(asconPbRounds);\n\n        // Reset the buffer position for the next block of input.\n        bufferPosition = 0;\n    }\n\n    /// <summary>\n    /// Updates the cryptographic state by processing a segment of input data from a byte array, starting at a specified offset and length.\n    /// </summary>\n    /// <param name=\"input\">The byte array containing the input data to be processed.</param>\n    /// <param name=\"inOff\">The offset in the input array where processing should begin.</param>\n    /// <param name=\"inLen\">The number of bytes from the input array to process.</param>\n    /// <remarks>\n    /// This method ensures that the input data is valid by checking the array length, starting from the provided offset,\n    /// and making sure it is long enough to accommodate the specified length. It then processes the data by converting\n    /// the relevant section of the byte array to a <see cref=\"ReadOnlySpan{T}\"/> and delegating the actual block update to\n    /// the <see cref=\"BlockUpdate(ReadOnlySpan{byte})\"/> method for further processing.\n    /// </remarks>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown if the input data is too short, starting from <paramref name=\"inOff\"/> and for the length <paramref name=\"inLen\"/>.\n    /// </exception>\n    public void BlockUpdate(byte[] input, int inOff, int inLen)\n    {\n        // Validate the input data to ensure there is enough data to process from the specified offset and length.\n        ValidationUtils.CheckDataLength(input, inOff, inLen, \"input buffer too short\");\n\n        // Convert the input byte array into a ReadOnlySpan<byte> and delegate the processing to the span-based method.\n        BlockUpdate(input.AsSpan(inOff, inLen));\n    }\n\n    /// <summary>\n    /// Processes the input data by updating the internal cryptographic state, handling both partial and full blocks.\n    /// </summary>\n    /// <param name=\"input\">A read-only span of bytes representing the input data to be processed.</param>\n    /// <remarks>\n    /// This method processes the input data in chunks of 8 bytes. It manages the internal buffer to accumulate data\n    /// until there are enough bytes to process a full 8-byte block. When the buffer is full or enough input is provided,\n    /// it XORs the buffered data with the internal state variable <c>x0</c> and applies the permutation function\n    /// <see cref=\"P\"/> to update the cryptographic state.\n    /// <br/><br/>\n    /// If the input contains more than 8 bytes, the method continues to process full 8-byte blocks in a loop until\n    /// the input is exhausted. Any remaining bytes (less than 8) are stored in the internal buffer for future processing.\n    /// </remarks>\n    public void BlockUpdate(ReadOnlySpan<byte> input)\n    {\n        // Calculate the number of available bytes left in the buffer before it reaches 8 bytes.\n        var available = 8 - bufferPosition;\n\n        // If the input length is smaller than the remaining space in the buffer, copy the input into the buffer.\n        if (input.Length < available)\n        {\n            input.CopyTo(buffer.AsSpan(bufferPosition)); // Copy the small input into the buffer.\n            bufferPosition += input.Length; // Update the buffer position.\n            return; // Return early since we don't have enough data to process a full block.\n        }\n\n        // If there is data in the buffer, but it isn't full, fill it and process the full 8-byte block.\n        if (bufferPosition > 0)\n        {\n            // Copy enough bytes from the input to complete the buffer.\n            input[..available].CopyTo(buffer.AsSpan(bufferPosition));\n\n            // XOR the full buffer with the internal state (x0) and apply the permutation.\n            x0 ^= ByteEncodingUtils.BigEndianToUint64(buffer);\n            P(asconPbRounds); // Apply the permutation rounds.\n\n            // Update the input to exclude the bytes we've already processed from the buffer.\n            input = input[available..];\n        }\n\n        // Process full 8-byte blocks directly from the input.\n        while (input.Length >= 8)\n        {\n            // XOR the next 8-byte block from the input with the internal state and apply the permutation.\n            x0 ^= ByteEncodingUtils.BigEndianToUint64(input);\n            P(asconPbRounds);\n\n            // Move to the next 8-byte chunk in the input.\n            input = input[8..];\n        }\n\n        // Copy any remaining bytes (less than 8) into the buffer to store for future processing.\n        input.CopyTo(buffer);\n        bufferPosition = input.Length; // Update the buffer position to reflect the remaining unprocessed data.\n    }\n\n    /// <summary>\n    /// Finalizes the cryptographic hash computation, absorbing any remaining data, applying the final permutation,\n    /// and writing the resulting hash to the specified position in the provided output byte array.\n    /// </summary>\n    /// <param name=\"output\">The byte array where the final 32-byte hash will be written.</param>\n    /// <param name=\"outOff\">The offset in the output array at which to start writing the hash.</param>\n    /// <returns>The size of the hash (32 bytes).</returns>\n    /// <remarks>\n    /// This method finalizes the hash computation by converting the output array to a <see cref=\"Span{T}\"/> and\n    /// calling the <see cref=\"DoFinal(Span{byte})\"/> method. It provides flexibility in placing the result in an\n    /// existing byte array with a specified offset.\n    /// </remarks>\n    /// <exception cref=\"ArgumentException\">Thrown if the output buffer is too small to hold the resulting hash.</exception>\n    public int DoFinal(byte[] output, int outOff)\n    {\n        // Call the Span-based DoFinal method with the output byte array and offset.\n        return DoFinal(output.AsSpan(outOff));\n    }\n\n    /// <summary>\n    /// Finalizes the cryptographic hash computation, absorbing any remaining data, applying the final permutation, and\n    /// writing the resulting hash to the provided output buffer.\n    /// </summary>\n    /// <param name=\"output\">A span of bytes where the final 32-byte hash will be written.</param>\n    /// <returns>The size of the hash (32 bytes).</returns>\n    /// <remarks>\n    /// This method completes the hash computation by absorbing any remaining input data, applying the final permutation,\n    /// and extracting the state variables to produce the final hash. The method processes the state in 8-byte chunks,\n    /// writing the result into the output buffer in big-endian format. After the final permutation is applied, the internal\n    /// state is reset to prepare for a new hashing session.\n    /// </remarks>\n    /// <exception cref=\"ArgumentException\">Thrown if the output buffer is too small to hold the resulting hash.</exception>\n    public int DoFinal(Span<byte> output)\n    {\n        // Validate that the output buffer is at least 32 bytes in length.\n        ValidationUtils.CheckOutputLength(output, 32, \"output buffer too short\");\n\n        // Absorb any remaining input and apply the final permutation.\n        AbsorbAndFinish();\n\n        // Convert the first part of the state (x0) to big-endian format and write it to the output.\n        ByteEncodingUtils.UInt64ToBigEndian(x0, output);\n\n        // Loop to process the remaining parts of the internal state (x1, x2, etc.).\n        for (var i = 0; i < 3; ++i)\n        {\n            // Move to the next 8-byte segment in the output buffer.\n            output = output[8..];\n\n            // Apply the permutation rounds to mix the state.\n            P(asconPbRounds);\n\n            // Convert the updated state variable (x0) to big-endian format and write it to the output.\n            ByteEncodingUtils.UInt64ToBigEndian(x0, output);\n        }\n\n        // Reset the internal state for the next hash computation.\n        Reset();\n\n        // Return the size of the hash (32 bytes).\n        return 32;\n    }\n\n    /// <summary>\n    /// Computes the cryptographic hash of the input byte array and returns the result as a lowercase hexadecimal string.\n    /// </summary>\n    /// <param name=\"input\">The input byte array to be hashed.</param>\n    /// <returns>A string containing the computed hash in lowercase hexadecimal format.</returns>\n    /// <remarks>\n    /// This method takes a byte array as input, processes it to compute the Ascon hash, and returns the result as a hexadecimal string.\n    /// It internally converts the byte array to a <see cref=\"Span{T}\"/> and delegates the actual hashing to the\n    /// <see cref=\"Digest(Span{byte})\"/> method.\n    /// </remarks>\n    public string Digest(byte[] input)\n    {\n        return Digest(input.AsSpan());\n    }\n\n    /// <summary>\n    /// Computes the cryptographic hash of the input span of bytes and returns the result as a lowercase hexadecimal string.\n    /// </summary>\n    /// <param name=\"input\">A span of bytes representing the input data to be hashed.</param>\n    /// <returns>A string containing the computed hash in lowercase hexadecimal format.</returns>\n    /// <remarks>\n    /// This method processes the input span using the Ascon cryptographic algorithm to compute the hash. It accumulates\n    /// the input, applies the necessary permutations and internal state updates, and finally produces a hash in the form\n    /// of a 32-byte array. The result is then converted into a lowercase hexadecimal string using <see cref=\"BitConverter\"/>.\n    /// </remarks>\n    public string Digest(Span<byte> input)\n    {\n        // Update the internal state with the input data.\n        BlockUpdate(input);\n\n        // Create an array to hold the final hash output (32 bytes).\n        var output = new byte[GetDigestSize()];\n\n        // Finalize the hash computation and store the result in the output array.\n        DoFinal(output, 0);\n\n        // Convert the hash (byte array) to a lowercase hexadecimal string.\n        return BitConverter.ToString(output).Replace(\"-\", string.Empty).ToLowerInvariant();\n    }\n\n    /// <summary>\n    /// Resets the internal state of the Ascon cryptographic hash algorithm to its initial state based on the selected variant.\n    /// </summary>\n    /// <remarks>\n    /// This method clears the internal buffer and resets the buffer position to zero. Depending on the specified\n    /// Ascon variant (<see cref=\"AsconParameters.AsconHash\"/> or <see cref=\"AsconParameters.AsconHashA\"/>), it also reinitializes\n    /// the internal state variables (<c>x0</c>, <c>x1</c>, <c>x2</c>, <c>x3</c>, <c>x4</c>) to their starting values.\n    /// <br/><br/>\n    /// The reset is necessary to prepare the hash function for a new message. It ensures that previous messages do not\n    /// affect the new one and that the internal state is consistent with the algorithm’s specification for the selected variant.\n    /// </remarks>\n    public void Reset()\n    {\n        // Clear the buffer to remove any leftover data from previous operations.\n        Array.Clear(buffer, 0, buffer.Length);\n\n        // Reset the buffer position to zero to start processing fresh input.\n        bufferPosition = 0;\n\n        // Initialize the internal state variables (x0, x1, x2, x3, x4) based on the selected Ascon variant.\n        switch (asconParameters)\n        {\n            // If using the AsconHashA variant, set the specific initial state values for x0 through x4.\n            case AsconParameters.AsconHashA:\n                x0 = 92044056785660070UL;\n                x1 = 8326807761760157607UL;\n                x2 = 3371194088139667532UL;\n                x3 = 15489749720654559101UL;\n                x4 = 11618234402860862855UL;\n                break;\n\n            // If using the AsconHash variant, set the specific initial state values for x0 through x4.\n            case AsconParameters.AsconHash:\n                x0 = 17191252062196199485UL;\n                x1 = 10066134719181819906UL;\n                x2 = 13009371945472744034UL;\n                x3 = 4834782570098516968UL;\n                x4 = 3787428097924915520UL;\n                break;\n\n            // If an unknown Ascon variant is encountered, throw an exception.\n            default:\n                throw new InvalidOperationException();\n        }\n    }\n\n    /// <summary>\n    /// Finalizes the absorption phase of the cryptographic hash by padding the buffer and applying the final permutation round.\n    /// </summary>\n    /// <remarks>\n    /// This method is called when the input data has been fully absorbed into the internal state, and it needs to be finalized.\n    /// The buffer is padded with a specific value (0x80) to signify the end of the data, and the remaining portion of the buffer is\n    /// XORed with the internal state variable <c>x0</c>. After padding, the final permutation round is applied using 12 rounds of\n    /// the permutation function <see cref=\"P(int)\"/>. This ensures the internal state is fully mixed and the cryptographic hash\n    /// is securely finalized.\n    /// </remarks>\n    private void AbsorbAndFinish()\n    {\n        // Pad the buffer with 0x80 to indicate the end of the data.\n        buffer[bufferPosition] = 0x80;\n\n        // XOR the buffer (after padding) with the internal state x0, but only the relevant portion of the buffer is considered.\n        // The (56 - (bufferPosition << 3)) shifts ensure that only the unprocessed part of the buffer is XORed into x0.\n        x0 ^= ByteEncodingUtils.BigEndianToUint64(buffer, 0) & (ulong.MaxValue << (56 - (bufferPosition << 3)));\n\n        // Apply 12 rounds of the permutation function to fully mix and finalize the internal state.\n        P(12);\n    }\n\n    /// <summary>\n    /// Executes the cryptographic permutation function by applying a sequence of rounds that transform the internal state variables.\n    /// </summary>\n    /// <param name=\"numberOfRounds\">\n    /// The number of rounds to execute. If set to 12, additional rounds are performed with specific constants to enhance the security of the transformation.\n    /// </param>\n    /// <remarks>\n    /// In the Ascon cryptographic algorithm, the permutation function <c>P</c> transforms the internal state over multiple rounds.\n    /// This method applies a set of round constants, each of which alters the state variables (<c>x0</c>, <c>x1</c>, <c>x2</c>, <c>x3</c>, <c>x4</c>) differently,\n    /// ensuring that the transformation introduces non-linearity and diffusion, which are essential for cryptographic security.\n    /// <br/><br/>\n    /// When <paramref name=\"numberOfRounds\"/> is set to 12, the method first applies four unique round constants.\n    /// Afterward, it applies a fixed set of six additional constants regardless of the number of rounds.\n    /// </remarks>\n    private void P(int numberOfRounds)\n    {\n        if (numberOfRounds == 12)\n        {\n            Round(0xf0UL);\n            Round(0xe1UL);\n            Round(0xd2UL);\n            Round(0xc3UL);\n        }\n\n        Round(0xb4UL);\n        Round(0xa5UL);\n\n        Round(0x96UL);\n        Round(0x87UL);\n        Round(0x78UL);\n        Round(0x69UL);\n        Round(0x5aUL);\n        Round(0x4bUL);\n    }\n\n    /// <summary>\n    /// Executes a single round of the cryptographic permutation function, transforming the internal state\n    /// variables <c>x0</c>, <c>x1</c>, <c>x2</c>, <c>x3</c>, and <c>x4</c> using XOR, AND, and NOT operations, along with circular bit rotations.\n    /// This function is designed to introduce diffusion and non-linearity into the state for cryptographic security.\n    /// </summary>\n    /// <param name=\"circles\">\n    /// A 64-bit unsigned integer constant that influences the round's transformation. Each round uses a unique value of this constant\n    /// to ensure that the transformation applied to the state differs for each round.\n    /// </param>\n    /// <remarks>\n    /// The <c>Round</c> function uses a series of bitwise operations (XOR, AND, NOT) and circular bit rotations to mix\n    /// the internal state. Each transformation step introduces non-linearity and ensures that small changes in the input or state\n    /// variables propagate widely across the internal state, enhancing the security of the cryptographic process.\n    /// <br/><br/>\n    /// The round constant (<paramref name=\"circles\"/>) plays a crucial role in altering the state at each round, ensuring\n    /// that each round contributes uniquely to the overall cryptographic transformation. Circular rotations are applied using\n    /// <see cref=\"LongUtils.RotateRight(ulong, int)\"/> to spread bits throughout the 64-bit word.\n    /// </remarks>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private void Round(ulong circles)\n    {\n        // Step 1: Perform XOR and AND operations to mix inputs and state variables\n        var t0 = x0 ^ x1 ^ x2 ^ x3 ^ circles ^ (x1 & (x0 ^ x2 ^ x4 ^ circles));\n        var t1 = x0 ^ x2 ^ x3 ^ x4 ^ circles ^ ((x1 ^ x2 ^ circles) & (x1 ^ x3));\n        var t2 = x1 ^ x2 ^ x4 ^ circles ^ (x3 & x4);\n        var t3 = x0 ^ x1 ^ x2 ^ circles ^ (~x0 & (x3 ^ x4));\n        var t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);\n\n        // Step 2: Apply circular right shifts and update the internal state variables\n        x0 = t0 ^ LongUtils.RotateRight(t0, 19) ^ LongUtils.RotateRight(t0, 28);\n        x1 = t1 ^ LongUtils.RotateRight(t1, 39) ^ LongUtils.RotateRight(t1, 61);\n        x2 = ~(t2 ^ LongUtils.RotateRight(t2, 1) ^ LongUtils.RotateRight(t2, 6));\n        x3 = t3 ^ LongUtils.RotateRight(t3, 10) ^ LongUtils.RotateRight(t3, 17);\n        x4 = t4 ^ LongUtils.RotateRight(t4, 7) ^ LongUtils.RotateRight(t4, 41);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Digests/IDigest.cs",
    "content": "namespace Algorithms.Crypto.Digests;\n\n/// <summary>\n/// Interface for message digest algorithms, providing methods to update, finalize, and reset the digest state.\n/// </summary>\npublic interface IDigest\n{\n    /// <summary>\n    /// Gets the name of the digest algorithm (e.g., \"SHA-256\").\n    /// </summary>\n    string AlgorithmName { get; }\n\n    /// <summary>\n    /// Gets the size of the digest in bytes (e.g., 32 bytes for SHA-256).\n    /// </summary>\n    /// <returns>The size of the digest in bytes.</returns>\n    int GetDigestSize();\n\n    /// <summary>\n    /// Gets the byte length of the internal buffer used by the digest.\n    /// </summary>\n    /// <returns>The byte length of the internal buffer.</returns>\n    int GetByteLength();\n\n    /// <summary>\n    /// Updates the digest with a single byte of input data.\n    /// </summary>\n    /// <param name=\"input\">The byte to add to the digest.</param>\n    void Update(byte input);\n\n    /// <summary>\n    /// Updates the digest with a portion of a byte array.\n    /// </summary>\n    /// <param name=\"input\">The byte array containing the input data.</param>\n    /// <param name=\"inOff\">The offset within the array to start reading from.</param>\n    /// <param name=\"inLen\">The length of data to read from the array.</param>\n    void BlockUpdate(byte[] input, int inOff, int inLen);\n\n    /// <summary>\n    /// Updates the digest with a portion of input data from a <see cref=\"ReadOnlySpan{T}\"/> of bytes.\n    /// </summary>\n    /// <param name=\"input\">The <see cref=\"ReadOnlySpan{T}\"/> containing the input data.</param>\n    void BlockUpdate(ReadOnlySpan<byte> input);\n\n    /// <summary>\n    /// Completes the digest calculation and stores the result in the specified byte array.\n    /// </summary>\n    /// <param name=\"output\">The byte array to store the final digest.</param>\n    /// <param name=\"outOff\">The offset within the array to start writing the digest.</param>\n    /// <returns>The number of bytes written to the output array.</returns>\n    int DoFinal(byte[] output, int outOff);\n\n    /// <summary>\n    /// Completes the digest calculation and stores the result in the specified <see cref=\"Span{T}\"/> of bytes.\n    /// </summary>\n    /// <param name=\"output\">The <see cref=\"Span{T}\"/> to store the final digest.</param>\n    /// <returns>The number of bytes written to the output span.</returns>\n    int DoFinal(Span<byte> output);\n\n    string Digest(byte[] input);\n\n    string Digest(Span<byte> input);\n\n    /// <summary>\n    /// Resets the digest to its initial state, clearing all data accumulated so far.\n    /// </summary>\n    void Reset();\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Digests/Md2Digest.cs",
    "content": "namespace Algorithms.Crypto.Digests;\n\n/// <summary>\n/// MD2 is a cryptographic hash function that takes an input message and produces a 128-bit output, also called a message\n/// digest or a hash.\n/// <para>\n/// A hash function has two main properties: it is easy to compute the hash from the input, but it is hard to find the\n/// input from the hash or to find two different inputs that produce the same hash.\n/// </para>\n/// <para>\n/// MD2 works by first padding the input message to a multiple of 16 bytes and adding a 16-byte checksum to it. Then, it\n/// uses a 48-byte auxiliary block and a 256-byte S-table (a fixed permutation of the numbers 0 to 255) to process the\n/// message in 16-byte blocks.\n/// </para>\n/// <para>\n/// For each block, it updates the auxiliary block by XORing it with the message block and then applying the S-table 18\n/// times. After all blocks are processed, the first 16 bytes of the auxiliary block become the hash value.\n/// </para>\n/// </summary>\npublic class Md2Digest\n{\n    // The S-table is a set of constants generated by shuffling the integers 0 through 255 using a variant of\n    // Durstenfeld's algorithm with a pseudorandom number generator based on decimal digits of pi.\n    private static readonly byte[] STable =\n    [\n        41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19,\n        98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202,\n        30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18,\n        190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122,\n        169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33,\n        128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3,\n        255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198,\n        79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241,\n        69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2,\n        27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,\n        85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38,\n        44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82,\n        106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74,\n        120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57,\n        242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10,\n        49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20,\n    ];\n\n    // The X buffer is a 48-byte auxiliary block used to compute the message digest.\n    private readonly byte[] xBuffer = new byte[48];\n\n    // The M buffer is a 16-byte auxiliary block that keeps 16 byte blocks from the input data.\n    private readonly byte[] mBuffer = new byte[16];\n\n    // The checksum buffer\n    private readonly byte[] checkSum = new byte[16];\n\n    private int xBufferOffset;\n    private int mBufferOffset;\n\n    /// <summary>\n    /// Computes the MD2 hash of the input byte array.\n    /// </summary>\n    /// <param name=\"input\">The input byte array to be hashed.</param>\n    /// <returns>The MD2 hash as a byte array.</returns>\n    public byte[] Digest(byte[] input)\n    {\n        Update(input, 0, input.Length);\n\n        // Pad the input to a multiple of 16 bytes.\n        var paddingByte = (byte)(mBuffer.Length - mBufferOffset);\n\n        for (var i = mBufferOffset; i < mBuffer.Length; i++)\n        {\n            mBuffer[i] = paddingByte;\n        }\n\n        // Process the checksum of the padded input.\n        ProcessCheckSum(mBuffer);\n\n        // Process the first block of the padded input.\n        ProcessBlock(mBuffer);\n\n        // Process the second block of the padded input, which is the checksum.\n        ProcessBlock(checkSum);\n\n        // Copy the first 16 bytes of the auxiliary block to the output.\n        var digest = new byte[16];\n\n        xBuffer.AsSpan(xBufferOffset, 16).CopyTo(digest);\n\n        // Reset the internal state for reuse.\n        Reset();\n        return digest;\n    }\n\n    /// <summary>\n    /// Resets the engine to its initial state.\n    /// </summary>\n    private void Reset()\n    {\n        xBufferOffset = 0;\n        for (var i = 0; i != xBuffer.Length; i++)\n        {\n            xBuffer[i] = 0;\n        }\n\n        mBufferOffset = 0;\n        for (var i = 0; i != mBuffer.Length; i++)\n        {\n            mBuffer[i] = 0;\n        }\n\n        for (var i = 0; i != checkSum.Length; i++)\n        {\n            checkSum[i] = 0;\n        }\n    }\n\n    /// <summary>\n    /// Performs the compression step of MD2 hash algorithm.\n    /// </summary>\n    /// <param name=\"block\">The 16 bytes block to be compressed.</param>\n    /// <remarks>\n    /// the compression step is designed to achieve diffusion and confusion, two properties that make it hard to reverse\n    /// or analyze the hash function. Diffusion means that changing one bit of the input affects many bits of the output,\n    /// and confusion means that there is no apparent relation between the input and the output.\n    /// </remarks>\n    private void ProcessBlock(byte[] block)\n    {\n        // Copying and XORing: The input block is copied to the second and third parts of the internal state, while XORing\n        // the input block with the first part of the internal state.\n        // By copying the input block to the second and third parts of the internal state, the compression step ensures\n        // that each input block contributes to the final output digest.\n        // By XORing the input block with the first part of the internal state, the compression step introduces a non-linear\n        // transformation that depends on both the input and the previous state. This makes it difficult to deduce the input\n        // or the state from the output, or vice versa.\n        for (var i = 0; i < 16; i++)\n        {\n            xBuffer[i + 16] = block[i];\n            xBuffer[i + 32] = (byte)(block[i] ^ xBuffer[i]);\n        }\n\n        var tmp = 0;\n\n        // Mixing: The internal state is mixed using the substitution table for 18 rounds. Each round consists of looping\n        // over the 48 bytes of the internal state and updating each byte by XORing it with a value from the substitution table.\n        // The mixing process ensures that each byte of the internal state is affected by every byte of the input block and\n        // every byte of the substitution table. This creates a high degree of diffusion and confusion, which makes it hard\n        // to find collisions or preimages for the hash function.\n        for (var j = 0; j < 18; j++)\n        {\n            for (var k = 0; k < 48; k++)\n            {\n                tmp = xBuffer[k] ^= STable[tmp];\n                tmp &= 0xff;\n            }\n\n            tmp = (tmp + j) % 256;\n        }\n    }\n\n    /// <summary>\n    /// Performs the checksum step of MD2 hash algorithm.\n    /// </summary>\n    /// <param name=\"block\">The 16 bytes block to calculate the checksum.</param>\n    /// <remarks>\n    /// The checksum step ensures that changing any bit of the input message will change about half of the bits of the\n    /// checksum, making it harder to find collisions or preimages.\n    /// </remarks>\n    private void ProcessCheckSum(byte[] block)\n    {\n        // Assign the last element of checksum to the variable last. This is the initial value of the checksum.\n        var last = checkSum[15];\n        for (var i = 0; i < 16; i++)\n        {\n            // Compute the XOR of the current element of the mBuffer array and the last value, and uses it as an index\n            // to access an element of STable. This is a substitution operation that maps each byte to another byte using\n            // the STable.\n            var map = STable[(mBuffer[i] ^ last) & 0xff];\n\n            // Compute the XOR of the current element of checkSum and the substituted byte, and stores it back to the\n            // checksum. This is a mixing operation that updates the checksum value with the input data.\n            checkSum[i] ^= map;\n\n            // Assign the updated element of checksum to last. This is to keep track of the last checksum value for the\n            // next iteration.\n            last = checkSum[i];\n        }\n    }\n\n    /// <summary>\n    /// Update the message digest with a single byte.\n    /// </summary>\n    /// <param name=\"input\">The input byte to digest.</param>\n    private void Update(byte input)\n    {\n        mBuffer[mBufferOffset++] = input;\n    }\n\n    /// <summary>\n    /// Update the message digest with a block of bytes.\n    /// </summary>\n    /// <param name=\"input\">The byte array containing the data.</param>\n    /// <param name=\"inputOffset\">The offset into the byte array where the data starts.</param>\n    /// <param name=\"length\">The length of the data.</param>\n    private void Update(byte[] input, int inputOffset, int length)\n    {\n        // process whole words\n        while (length >= 16)\n        {\n            Array.Copy(input, inputOffset, mBuffer, 0, 16);\n            ProcessCheckSum(mBuffer);\n            ProcessBlock(mBuffer);\n\n            length -= 16;\n            inputOffset += 16;\n        }\n\n        while (length > 0)\n        {\n            Update(input[inputOffset]);\n            inputOffset++;\n            length--;\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Exceptions/CryptoException.cs",
    "content": "namespace Algorithms.Crypto.Exceptions;\n\n/// <summary>\n/// Represents errors that occur during cryptographic operations.\n/// </summary>\npublic class CryptoException : Exception\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CryptoException\"/> class.\n    /// </summary>\n    public CryptoException()\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CryptoException\"/> class with a specified error message.\n    /// </summary>\n    /// <param name=\"message\">The message that describes the error.</param>\n    public CryptoException(string message)\n        : base(message)\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CryptoException\"/> class with a specified error message\n    /// and a reference to the inner exception that is the cause of this exception.\n    /// </summary>\n    /// <param name=\"message\">The message that describes the error.</param>\n    /// <param name=\"inner\">The exception that is the cause of the current exception.</param>\n    public CryptoException(string message, Exception inner)\n        : base(message, inner)\n    {\n    }\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Exceptions/DataLengthException.cs",
    "content": "namespace Algorithms.Crypto.Exceptions;\n\n/// <summary>\n/// Represents errors that occur when the length of data in a cryptographic operation is invalid or incorrect.\n/// </summary>\npublic class DataLengthException : CryptoException\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"DataLengthException\"/> class.\n    /// </summary>\n    public DataLengthException()\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"DataLengthException\"/> class with a specified error message.\n    /// </summary>\n    /// <param name=\"message\">The message that describes the error.</param>\n    public DataLengthException(string message)\n        : base(message)\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"DataLengthException\"/> class with a specified error message\n    /// and a reference to the inner exception that is the cause of this exception.\n    /// </summary>\n    /// <param name=\"message\">The message that describes the error.</param>\n    /// <param name=\"inner\">The exception that is the cause of the current exception.</param>\n    public DataLengthException(string message, Exception inner)\n        : base(message, inner)\n    {\n    }\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Exceptions/OutputLengthException.cs",
    "content": "namespace Algorithms.Crypto.Exceptions;\n\n/// <summary>\n/// Represents an exception that is thrown when the output buffer length is insufficient for a cryptographic operation.\n/// </summary>\n/// <remarks>\n/// The <see cref=\"OutputLengthException\"/> is a specific subclass of <see cref=\"DataLengthException\"/>. It is used in cryptographic\n/// operations to signal that the provided output buffer does not have enough space to store the required output. This exception is\n/// typically thrown when encryption, hashing, or other cryptographic operations require more space than what has been allocated in\n/// the output buffer.\n/// <br />\n/// This exception provides constructors for creating the exception with a custom message, an inner exception, or both. By inheriting\n/// from <see cref=\"DataLengthException\"/>, it can be handled similarly in cases where both input and output length issues may arise.\n/// </remarks>\npublic class OutputLengthException : DataLengthException\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"OutputLengthException\"/> class.\n    /// </summary>\n    /// <remarks>\n    /// This constructor initializes a new instance of the <see cref=\"OutputLengthException\"/> class without any additional message or inner exception.\n    /// It is commonly used when a generic output length issue needs to be raised without specific details.\n    /// </remarks>\n    public OutputLengthException()\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"OutputLengthException\"/> class with a specified error message.\n    /// </summary>\n    /// <param name=\"message\">The message that describes the error.</param>\n    /// <remarks>\n    /// This constructor allows for a custom error message to be provided, giving more detail about the specific issue with the output length.\n    /// </remarks>\n    public OutputLengthException(string message)\n        : base(message)\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"OutputLengthException\"/> class with a specified error message\n    /// and a reference to the inner exception that is the cause of this exception.\n    /// </summary>\n    /// <param name=\"message\">The message that describes the error.</param>\n    /// <param name=\"inner\">The exception that is the cause of the current exception.</param>\n    /// <remarks>\n    /// This constructor allows for both a custom message and an inner exception, which can be useful for propagating\n    /// the underlying cause of the error. For example, if the output buffer length is too short due to incorrect calculations,\n    /// the root cause (e.g., an <see cref=\"ArgumentException\"/>) can be passed in as the inner exception.\n    /// </remarks>\n    public OutputLengthException(string message, Exception inner)\n        : base(message, inner)\n    {\n    }\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Paddings/IBlockCipherPadding.cs",
    "content": "﻿namespace Algorithms.Crypto.Paddings;\n\n/// <summary>\n/// A common interface that all block cipher padding schemes should follow.\n/// </summary>\npublic interface IBlockCipherPadding\n{\n    /// <summary>\n    /// Adds padding bytes to the end of the given block of the data and returns the number of bytes that were added.\n    /// </summary>\n    /// <param name=\"inputData\">The input data array that needs padding.</param>\n    /// <param name=\"inputOffset\">The offset in the input array where the padding should start.</param>\n    /// <returns>The number of bytes added.</returns>\n    /// <remarks>\n    /// This method expects that the input parameter <paramref name=\"inputData\"/> contains the last block of plain text\n    /// that needs to be padded. This means that the value of <paramref name=\"inputData\"/> has to have the same value as\n    /// the last block of plain text. The reason for this is that some modes such as the <see cref=\"TbcPadding\"/> base the\n    /// padding value on the last byte of the plain text.\n    /// </remarks>\n    public int AddPadding(byte[] inputData, int inputOffset);\n\n    /// <summary>\n    /// Removes the padding bytes from the given block of data and returns the original data as a new array.\n    /// </summary>\n    /// <param name=\"inputData\">The input data array containing the padding.</param>\n    /// <returns>The input data without the padding as a new byte array.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown when the input data has invalid padding.</exception>\n    public byte[] RemovePadding(byte[] inputData);\n\n    /// <summary>\n    /// Gets the number of padding bytes in the input data.\n    /// </summary>\n    /// <param name=\"input\">The input data array that has padding.</param>\n    /// <returns>The number of padding bytes in the input data.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown when the input data has invalid padding.</exception>\n    public int GetPaddingCount(byte[] input);\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Paddings/Iso10126D2Padding.cs",
    "content": "﻿namespace Algorithms.Crypto.Paddings;\n\n/// <summary>\n/// <para>\n/// This class implements the ISO10126d2 padding scheme, which is a standard way of padding data to fit a certain block\n/// size.\n/// </para>\n/// <para>\n/// ISO10126d2 padding adds N-1 random bytes and one byte of value N to the end of the data, where N is the number of\n/// bytes needed to reach the block size. For example, if the block size is 16 bytes, and the data is 10 bytes long, then\n/// 5 random bytes and a byte with value 6 will be added to the end of data. This way the padded data will be 16 bytes\n/// long and can be encrypted or decrypted by a block cipher algorithm.\n/// </para>\n/// <para>\n/// The padding can easily be removed after decryption by looking at the last byte and discarding that many bytes from\n/// the end of the data.\n/// </para>\n/// </summary>\npublic class Iso10126D2Padding : IBlockCipherPadding\n{\n    /// <summary>\n    /// Adds random padding to the input data array to make it a multiple of the block size according to the\n    /// ISO10126d2 standard.\n    /// </summary>\n    /// <param name=\"inputData\">The input data array that needs to be padded.</param>\n    /// <param name=\"inputOffset\">The offset in the input data array where the padding should start.</param>\n    /// <returns>The number of bytes added as padding.</returns>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown when there is not enough space in the input array for padding.\n    /// </exception>\n    public int AddPadding(byte[] inputData, int inputOffset)\n    {\n        // Calculate how many bytes need to be added to reach the next multiple of block size.\n        var code = (byte)(inputData.Length - inputOffset);\n\n        if (code == 0 || inputOffset + code > inputData.Length)\n        {\n            throw new ArgumentException(\"Not enough space in input array for padding\");\n        }\n\n        // Add the padding.\n        while (inputOffset < (inputData.Length - 1))\n        {\n            inputData[inputOffset] = (byte)RandomNumberGenerator.GetInt32(255);\n            inputOffset++;\n        }\n\n        // Set the last byte of the array to the size of the padding added.\n        inputData[inputOffset] = code;\n\n        return code;\n    }\n\n    /// <summary>\n    /// Removes the padding from the input data array and returns the original data.\n    /// </summary>\n    /// <param name=\"inputData\">\n    /// The input data with ISO10126d2 padding. Must not be null and must have a valid length and padding.\n    /// </param>\n    /// <returns>\n    /// The input data without the padding as a new byte array.\n    /// </returns>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown when the padding length is invalid.\n    /// </exception>\n    public byte[] RemovePadding(byte[] inputData)\n    {\n        // Get the size of the padding from the last byte of the input data.\n        var paddingLength = inputData[^1];\n\n        // Check if the padding size is valid.\n        if (paddingLength < 1 || paddingLength > inputData.Length)\n        {\n            throw new ArgumentException(\"Invalid padding length\");\n        }\n\n        // Create a new array to hold the original data.\n        var output = new byte[inputData.Length - paddingLength];\n\n        // Copy the original data into the new array.\n        Array.Copy(inputData, 0, output, 0, output.Length);\n\n        return output;\n    }\n\n    /// <summary>\n    /// Gets the number of padding bytes from the input data array.\n    /// </summary>\n    /// <param name=\"input\">The input data array that has been padded.</param>\n    /// <returns>The number of padding bytes.</returns>\n    /// <exception cref=\"ArgumentNullException\">Thrown when the input is null.</exception>\n    /// <exception cref=\"ArgumentException\">Thrown when the padding block is corrupted.</exception>\n    public int GetPaddingCount(byte[] input)\n    {\n        if (input == null)\n        {\n            throw new ArgumentNullException(nameof(input), \"Input cannot be null\");\n        }\n\n        // Get the last byte of the input data as the padding value.\n        var lastByte = input[^1];\n        var paddingCount = lastByte & 0xFF;\n\n        // Calculate the index where the padding starts.\n        var paddingStartIndex = input.Length - paddingCount;\n        var paddingCheckFailed = 0;\n\n        // The paddingCheckFailed will be non-zero under the following circumstances:\n        // 1. When paddingStartIndex is negative: This happens when paddingCount (the last byte of the input array) is\n        // greater than the length of the input array. In other words, the padding count is claiming that there are more\n        // padding bytes than there are bytes in the array, which is not a valid scenario.\n        // 2. When paddingCount - 1 is negative: This happens when paddingCount is zero or less. Since paddingCount\n        // represents the number of padding bytes and is derived from the last byte of the input array, it should always\n        // be a positive number. If it's zero or less, it means that either there's no padding, or an invalid negative\n        // padding count has shomehow encoded into the last byte of the input array.\n        paddingCheckFailed = (paddingStartIndex | (paddingCount - 1)) >> 31;\n        if (paddingCheckFailed != 0)\n        {\n            throw new ArgumentException(\"Padding block is corrupted\");\n        }\n\n        return paddingCount;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Paddings/Iso7816D4Padding.cs",
    "content": "﻿namespace Algorithms.Crypto.Paddings;\n\n/// <summary>\n/// <para>\n/// ISO 7816-4 padding is a padding scheme that is defined in the ISO/IEC 7816-4 documentation.\n/// </para>\n/// <para>\n/// It is used for adding data to the end of a message that needs to be encrypted or decrypted by a block cipher.\n/// </para>\n/// ISO 7816-4 padding works as follows:\n/// <para>\n/// The first byte of the padding is 0x80, which is the hexadecimal representation of the binary value 10000000. This\n/// byte indicates the start of the padding.\n/// </para>\n/// <para>\n/// All other bytes of the padding are 0x00, which is the hexadecimal representation of the binary value 00000000. These\n/// bytes fill up the remaining space in the last block.\n/// </para>\n/// <para>\n/// The padding can be of any size, from 1 byte to the block size. For example, if the block size is 8 bytes and the\n/// message has 5 bytes, then 3 bytes of padding are needed. The padding would be <c>0x80 0x00 0x00</c>.\n/// </para>\n/// <para>\n/// ISO 7816-4 padding is also known as bit padding,because it simply places a single 1 bit after the plaintext, followed\n/// by 0 valued bits up to the block size. It works for both byte-oriented and bit-oriented protocols, as it does not\n/// depend on any specific character encoding or representation.\n/// </para>\n/// </summary>\npublic class Iso7816D4Padding : IBlockCipherPadding\n{\n    /// <summary>\n    /// Adds padding to the input data according to the ISO 7816-4 standard.\n    /// </summary>\n    /// <param name=\"inputData\">The input data array that needs padding.</param>\n    /// <param name=\"inputOffset\">The offset in the input data array where the padding should start.</param>\n    /// <returns>The number of bytes added as padding.</returns>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown when there is not enough space in the input array for padding or when the input offset is invalid.\n    /// </exception>\n    public int AddPadding(byte[] inputData, int inputOffset)\n    {\n        // Calculate the number of padding bytes based on the input data length and offset.\n        var code = (byte)(inputData.Length - inputOffset);\n\n        // Check if the padding bytes are valid and fit in the input array.\n        if (code == 0 || inputOffset + code > inputData.Length)\n        {\n            throw new ArgumentException(\"Not enough space in input array for padding\");\n        }\n\n        // Set the first padding byte to 80. This marks the start of padding in the ISO 7816-4 standard.\n        inputData[inputOffset] = 80;\n        inputOffset++;\n\n        // Set the remaining padding bytes to 0.\n        while (inputOffset < inputData.Length)\n        {\n            inputData[inputOffset] = 0;\n            inputOffset++;\n        }\n\n        // Return the number of padding bytes.\n        return code;\n    }\n\n    /// <summary>\n    /// Removes the padding from the input data array and returns the original data.\n    /// </summary>\n    /// <param name=\"inputData\">\n    /// The input data with ISO 7816-4 padding. Must not be null and must have a valid length and padding.\n    /// </param>\n    /// <returns>The input data without the padding as a new byte array.</returns>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown when the input data has invalid padding.\n    /// </exception>\n    public byte[] RemovePadding(byte[] inputData)\n    {\n        // Find the index of the first padding byte by scanning from the end of the input.\n        var paddingIndex = inputData.Length - 1;\n\n        // Skip all the padding bytes that are 0.\n        while (paddingIndex >= 0 && inputData[paddingIndex] == 0)\n        {\n            paddingIndex--;\n        }\n\n        // Check if the first padding byte is 0x80.\n        if (paddingIndex < 0 || inputData[paddingIndex] != 0x80)\n        {\n            throw new ArgumentException(\"Invalid padding\");\n        }\n\n        // Create a new array to store the unpadded data.\n        var unpaddedData = new byte[paddingIndex];\n\n        // Copy the unpadded data from the input data to the new array.\n        Array.Copy(inputData, 0, unpaddedData, 0, paddingIndex);\n\n        // Return the unpadded data array.\n        return unpaddedData;\n    }\n\n    /// <summary>\n    /// Gets the number of padding bytes in the input data according to the ISO 7816-4 standard.\n    /// </summary>\n    /// <param name=\"input\">The input data array that has padding.</param>\n    /// <returns>The number of padding bytes in the input data.</returns>\n    /// <exception cref=\"ArgumentException\"> Thrown when the input data has invalid padding.</exception>\n    public int GetPaddingCount(byte[] input)\n    {\n        // Initialize the index of the first padding byte to -1.\n        var paddingStartIndex = -1;\n\n        // Initialize a mask to indicate if the current byte is still part of the padding.\n        var stillPaddingMask = -1;\n\n        // Initialize the current index to the end of the input data.\n        var currentIndex = input.Length;\n\n        // Loop backwards through the input data.\n        while (--currentIndex >= 0)\n        {\n            // Get the current byte as an unsigned integer.\n            var currentByte = input[currentIndex] & 0xFF;\n\n            // Compute a mask to indicate if the current byte is 0x00.\n            var isZeroMask = (currentByte - 1) >> 31;\n\n            // Compute a mask to indicate if the current byte is 0x80.\n            var isPaddingStartMask = ((currentByte ^ 0x80) - 1) >> 31;\n\n            // Update the index of the first padding byte using bitwise operations.\n            // If the current byte is 0x80 and still part of the padding, set the index to the current index.\n            // Otherwise, keep the previous index.\n            paddingStartIndex ^= (currentIndex ^ paddingStartIndex) & (stillPaddingMask & isPaddingStartMask);\n\n            // Update the mask to indicate if the current byte is still part of the padding using bitwise operations.\n            // If the current byte is 0x00, keep the previous mask.\n            // Otherwise, set the mask to 0.\n            stillPaddingMask &= isZeroMask;\n        }\n\n        // Check if the index of the first padding byte is valid.\n        if (paddingStartIndex < 0)\n        {\n            throw new ArgumentException(\"Pad block corrupted\");\n        }\n\n        // Return the number of padding bytes.\n        return input.Length - paddingStartIndex;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Paddings/Pkcs7Padding.cs",
    "content": "﻿namespace Algorithms.Crypto.Paddings;\n\n/// <summary>\n/// <para>\n/// This class implements the PKCS7 padding scheme, which is a standard way of padding data to fit a certain block size.\n/// </para>\n/// <para>\n/// PKCS7 padding adds N bytes of value N to the end of the data, where N is the number of bytes needed to reach the block size.\n/// For example, if the block size is 16 bytes, and the data is 11 bytes long, then 5 bytes of value 5 will be added to the\n/// end of the data. This way, the padded data will be 16 bytes long and can be encrypted or decrypted by a block cipher algorithm.\n/// </para>\n/// <para>\n/// The padding can be easily removed after decryption by looking at the last byte and subtracting that many bytes from the\n/// end of the data.\n/// </para>\n/// <para>\n/// This class supports any block size from 1 to 255 bytes, and can be used with any encryption algorithm that requires\n/// padding, such as AES.\n/// </para>\n/// </summary>\npublic class Pkcs7Padding : IBlockCipherPadding\n{\n    private readonly int blockSize;\n\n    public Pkcs7Padding(int blockSize)\n    {\n        if (blockSize is < 1 or > 255)\n        {\n            throw new ArgumentOutOfRangeException(nameof(blockSize), $\"Invalid block size: {blockSize}\");\n        }\n\n        this.blockSize = blockSize;\n    }\n\n    /// <summary>\n    /// Adds padding to the end of a byte array according to the PKCS#7 standard.\n    /// </summary>\n    /// <param name=\"input\">The byte array to be padded.</param>\n    /// <param name=\"inputOffset\">The offset from which to start padding.</param>\n    /// <returns>The padding value that was added to each byte.</returns>\n    /// <exception cref=\"ArgumentException\">\n    /// If the input array does not have enough space to add <c>blockSize</c> bytes as padding.\n    /// </exception>\n    /// <remarks>\n    /// The padding value is equal to the number of of bytes that are added to the array.\n    /// For example, if the input array has a length of 16 and the input offset is 10,\n    /// then 6 bytes with the value 6 will be added to the end of the array.\n    /// </remarks>\n    public int AddPadding(byte[] input, int inputOffset)\n    {\n        // Calculate how many bytes need to be added to reach the next multiple of block size.\n        var code = (byte)((blockSize - (input.Length % blockSize)) % blockSize);\n\n        // If no padding is needed, add a full block of padding.\n        if (code == 0)\n        {\n            code = (byte)blockSize;\n        }\n\n        if (inputOffset + code > input.Length)\n        {\n            throw new ArgumentException(\"Not enough space in input array for padding\");\n        }\n\n        // Add the padding\n        for (var i = 0; i < code; i++)\n        {\n            input[inputOffset + i] = code;\n        }\n\n        return code;\n    }\n\n    /// <summary>\n    /// Removes the PKCS7 padding from the given input data.\n    /// </summary>\n    /// <param name=\"input\">The input data with PKCS7 padding. Must not be null and must have a valid length and padding.</param>\n    /// <returns>The input data without the padding as a new byte array.</returns>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown if the input data is null, has an invalid length, or has an invalid padding.\n    /// </exception>\n    public byte[] RemovePadding(byte[] input)\n    {\n        // Check if input length is a multiple of blockSize\n        if (input.Length % blockSize != 0)\n        {\n            throw new ArgumentException(\"Input length must be a multiple of block size\");\n        }\n\n        // Get the padding length from the last byte of input\n        var paddingLength = input[^1];\n\n        // Check if padding length is valid\n        if (paddingLength < 1 || paddingLength > blockSize)\n        {\n            throw new ArgumentException(\"Invalid padding length\");\n        }\n\n        // Check if all padding bytes have the correct value\n        for (var i = 0; i < paddingLength; i++)\n        {\n            if (input[input.Length - 1 - i] != paddingLength)\n            {\n                throw new ArgumentException(\"Invalid padding\");\n            }\n        }\n\n        // Create a new array with the size of input minus the padding length\n        var output = new byte[input.Length - paddingLength];\n\n        // Copy the data without the padding into the output array\n        Array.Copy(input, output, output.Length);\n\n        return output;\n    }\n\n    /// <summary>\n    /// Gets the number of padding bytes in the given input data according to the PKCS7 padding scheme.\n    /// </summary>\n    /// <param name=\"input\">The input data with PKCS7 padding. Must not be null and must have a valid padding.</param>\n    /// <returns>The number of padding bytes in the input data.</returns>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown if the input data is null or has an invalid padding.\n    /// </exception>\n    /// <remarks>\n    /// This method uses bitwise operations to avoid branching.\n    /// </remarks>\n    public int GetPaddingCount(byte[] input)\n    {\n        if (input == null)\n        {\n            throw new ArgumentNullException(nameof(input), \"Input cannot be null\");\n        }\n\n        // Get the last byte of the input data as the padding value.\n        var lastByte = input[^1];\n        var paddingCount = lastByte & 0xFF;\n\n        // Calculate the index where the padding starts\n        var paddingStartIndex = input.Length - paddingCount;\n        var paddingCheckFailed = 0;\n\n        // Check if the padding start index is negative or greater than the input length.\n        // This is done by using bitwise operations to avoid branching.\n        // If the padding start index is negative, then its most significant bit will be 1.\n        // If the padding count is greater than the block size, then its most significant bit will be 1.\n        // By ORing these two cases, we can get a non-zero value rif either of them is true.\n        // By shifting this value right by 31 bits, we can get either 0 or -1 as the result.\n        paddingCheckFailed = (paddingStartIndex | (paddingCount - 1)) >> 31;\n\n        for (var i = 0; i < input.Length; i++)\n        {\n            // Check if each byte matches the padding value.\n            // This is done by using bitwise operations to avoid branching.\n            // If a byte does not match the padding value, then XORing them will give a non-zero value.\n            // If a byte is before the padding start index, then we want to ignore it.\n            // This is done by using bitwise operations to create a mask that is either all zeros or all ones.\n            // If i is less than the padding start index, then subtracting them will give a negative value.\n            // By shifting this value right by 31 bits, we can get either -1 or 0 as the mask.\n            // By negating this mask, we can get either 0 or -1 as the mask.\n            // By ANDing this mask with the XOR result, we can get either 0 or the XOR result as the final result.\n            // By ORing this final result with the previous padding check result, we can accumulate any non-zero values.\n            paddingCheckFailed |= (input[i] ^ lastByte) & ~((i - paddingStartIndex) >> 31);\n        }\n\n        // Check if the padding check failed.\n        if (paddingCheckFailed != 0)\n        {\n            throw new ArgumentException(\"Padding block is corrupted\");\n        }\n\n        // Return the number of padding bytes.\n        return paddingCount;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Paddings/TbcPadding.cs",
    "content": "﻿namespace Algorithms.Crypto.Paddings;\n\n/// <summary>\n/// <para>\n/// Trailing-Bit-Complement padding is a padding scheme that is defined in the ISO/IEC 9797-1 standard.\n/// </para>\n/// <para>\n/// It is used for adding data to the end of a message that needs to be encrypted or decrypted by a block cipher.\n/// </para>\n/// <para>\n/// The padding bytes are either 0x00 or 0xFF, depending on the last bit of the original data. For example, if the last\n/// bit of the original data is 0, then the padding bytes are 0xFF; if the last bit is 1, then the padding bytes are 0x00.\n/// The padding bytes are added at the end of the data block until the desired length is reached.\n/// </para>\n/// </summary>\npublic class TbcPadding : IBlockCipherPadding\n{\n    /// <summary>\n    /// Adds padding to the input array according to the TBC standard.\n    /// </summary>\n    /// <param name=\"input\">The input array to be padded.</param>\n    /// <param name=\"inputOffset\">The offset in the input array where the padding starts.</param>\n    /// <returns>The number of bytes that were added.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown when the input array does not have enough space for padding.</exception>\n    public int AddPadding(byte[] input, int inputOffset)\n    {\n        // Calculate the number of bytes to be padded.\n        var count = input.Length - inputOffset;\n        byte code;\n\n        // Check if the input array has enough space for padding.\n        if (count < 0)\n        {\n            throw new ArgumentException(\"Not enough space in input array for padding\");\n        }\n\n        if (inputOffset > 0)\n        {\n            // Get the last bit of the previous byte.\n            var lastBit = input[inputOffset - 1] & 0x01;\n\n            // Set the padding code to 0xFF if the last bit is 0, or 0x00 if the last bit is 1.\n            code = (byte)(lastBit == 0 ? 0xff : 0x00);\n        }\n        else\n        {\n            // Get the last bit of the last byte in the input array.\n            var lastBit = input[^1] & 0x01;\n\n            // Set the padding code to 0xff if the last bit is 0, or 0x00 if the last bit is 1.\n            code = (byte)(lastBit == 0 ? 0xff : 0x00);\n        }\n\n        while (inputOffset < input.Length)\n        {\n            // Set each byte to the padding code.\n            input[inputOffset] = code;\n            inputOffset++;\n        }\n\n        // Return the number of bytes that were padded.\n        return count;\n    }\n\n    /// <summary>\n    /// Removes the padding from a byte array according to the Trailing-Bit-Complement padding algorithm.\n    /// </summary>\n    /// <param name=\"input\">The byte array to remove the padding from.</param>\n    /// <returns>A new byte array without the padding.</returns>\n    /// <remarks>\n    /// This method assumes that the input array has padded with either 0x00 or 0xFF bytes, depending on the last bit of\n    /// the original data. The method works by finding the last byte that does not match the padding code and copying all\n    /// the bytes up to that point into a new array. If the input array is not padded or has an invalid padding, the\n    /// method may return incorrect results.\n    /// </remarks>\n    public byte[] RemovePadding(byte[] input)\n    {\n        if (input.Length == 0)\n        {\n            return Array.Empty<byte>();\n        }\n\n        // Get the last byte of the input array.\n        var lastByte = input[^1];\n\n        // Determine the byte code\n        var code = (byte)((lastByte & 0x01) == 0 ? 0x00 : 0xff);\n\n        // Start from the end of the array and move towards the front.\n        int i;\n        for (i = input.Length - 1; i >= 0; i--)\n        {\n            // If the current byte does not match the padding code, stop.\n            if (input[i] != code)\n            {\n                break;\n            }\n        }\n\n        // Create a new array of the appropriate length.\n        var unpadded = new byte[i + 1];\n\n        // Copy the unpadded data into the new array.\n        Array.Copy(input, unpadded, i + 1);\n\n        // Return the new array.\n        return unpadded;\n    }\n\n    /// <summary>\n    /// Returns the number of padding bytes in a byte array according to the Trailing-Bit-Complement padding algorithm.\n    /// </summary>\n    /// <param name=\"input\">The byte array to check for padding.</param>\n    /// <returns>The number of padding bytes in the input array.</returns>\n    /// <remarks>\n    /// This method assumes that the input array has been padded with either 0x00 or 0xFF bytes, depending on the last\n    /// bit of the original data. The method works by iterating backwards from the end of the array and counting the\n    /// number of bytes that match the padding code. The method uses bitwise operations to optimize the performance and\n    /// avoid branching. If the input array is not padded or has an invalid padding, the method may return incorrect\n    /// results.\n    /// </remarks>\n    public int GetPaddingCount(byte[] input)\n    {\n        var length = input.Length;\n\n        if (length == 0)\n        {\n            throw new ArgumentException(\"No padding found.\");\n        }\n\n        // Get the value of the last byte as the padding value\n        var paddingValue = input[--length] & 0xFF;\n        var paddingCount = 1; // Start count at 1 for the last byte\n        var countingMask = -1; // Initialize counting mask\n\n        // Check if there is no padding\n        if (paddingValue != 0 && paddingValue != 0xFF)\n        {\n            throw new ArgumentException(\"No padding found\");\n        }\n\n        // Loop backwards through the array\n        for (var i = length - 1; i >= 0; i--)\n        {\n            var currentByte = input[i] & 0xFF;\n\n            // Calculate matchMask. If currentByte equals paddingValue, matchMask will be 0, otherwise -1\n            var matchMask = ((currentByte ^ paddingValue) - 1) >> 31;\n\n            // Update countingMask. Once a non-matching byte is found, countingMask will remain -1\n            countingMask &= matchMask;\n\n            // Increment count only if countingMask is 0 (i.e., currentByte matches paddingValue)\n            paddingCount -= countingMask;\n        }\n\n        return paddingCount;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Paddings/X932Padding.cs",
    "content": "namespace Algorithms.Crypto.Paddings;\n\n/// <summary>\n/// <para>\n/// X9.32 padding is a padding scheme for symmetric encryption algorithms that is based on the ANSI X9.32 standard.\n/// </para>\n/// <para>\n/// It adds bytes with value equal to 0 up to the end of the plaintext. For example if the plaintext is 13 bytes long\n/// and the block size is 16 bytes, then 2 bytes with value 0 will be added as padding. The last byte indicates the\n/// number of padding bytes.\n/// </para>\n/// <para>\n/// If random padding mode is selected then random bytes are added before the padding bytes. For example, if the plaintext\n/// is 13 bytes long, then 2 random bytes will be added as padding. Again the last byte indicates the number of padding\n/// bytes.\n/// </para>\n/// </summary>\n/// <remarks>\n/// Initializes a new instance of the <see cref=\"X932Padding\"/> class with the specified padding mode.\n/// </remarks>\n/// <param name=\"useRandomPadding\">A boolean value that indicates whether to use random bytes as padding or not.</param>\npublic class X932Padding(bool useRandomPadding) : IBlockCipherPadding\n{\n    private readonly bool useRandomPadding = useRandomPadding;\n\n    /// <summary>\n    /// Adds padding to the input data according to the X9.23 padding scheme.\n    /// </summary>\n    /// <param name=\"inputData\">The input data array to be padded.</param>\n    /// <param name=\"inputOffset\">The offset in the input data array where the padding should start.</param>\n    /// <returns>The number of padding bytes added.</returns>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown when the input offset is greater than or equal to the input data length.\n    /// </exception>\n    public int AddPadding(byte[] inputData, int inputOffset)\n    {\n        // Check if the input offset is valid.\n        if (inputOffset >= inputData.Length)\n        {\n            throw new ArgumentException(\"Not enough space in input array for padding\");\n        }\n\n        // Calculate the number of padding bytes needed.\n        var code = (byte)(inputData.Length - inputOffset);\n\n        // Fill the remaining bytes with random or zero bytes\n        while (inputOffset < inputData.Length - 1)\n        {\n            if (!useRandomPadding)\n            {\n                // Use zero bytes if random padding is disabled.\n                inputData[inputOffset] = 0;\n            }\n            else\n            {\n                // Use random bytes if random padding is enabled.\n                inputData[inputOffset] = (byte)RandomNumberGenerator.GetInt32(255);\n            }\n\n            inputOffset++;\n        }\n\n        // Set the last byte to the number of padding bytes.\n        inputData[inputOffset] = code;\n\n        // Return the number of padding bytes.\n        return code;\n    }\n\n    /// <summary>\n    /// Removes padding from the input data according to the X9.23 padding scheme.\n    /// </summary>\n    /// <param name=\"inputData\">The input data array to be unpadded.</param>\n    /// <returns>The unpadded data array.</returns>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown when the input data is empty or has an invalid padding length.\n    /// </exception>\n    public byte[] RemovePadding(byte[] inputData)\n    {\n        // Check if the array is empty.\n        if (inputData.Length == 0)\n        {\n            return Array.Empty<byte>();\n        }\n\n        // Get the padding length from the last byte of the input data.\n        var paddingLength = inputData[^1];\n\n        // Check if the padding length is valid.\n        if (paddingLength < 1 || paddingLength > inputData.Length)\n        {\n            throw new ArgumentException(\"Invalid padding length\");\n        }\n\n        // Create a new array for the output data.\n        var output = new byte[inputData.Length - paddingLength];\n\n        // Copy the input data without the padding bytes to the output array.\n        Array.Copy(inputData, output, output.Length);\n\n        // Return the output array.\n        return output;\n    }\n\n    /// <summary>\n    /// Gets the number of padding bytes in the input data according to the X9.23 padding scheme.\n    /// </summary>\n    /// <param name=\"input\">The input data array to be checked.</param>\n    /// <returns>The number of padding bytes in the input data.</returns>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown when the input data has a corrupted padding block.\n    /// </exception>\n    public int GetPaddingCount(byte[] input)\n    {\n        // Get the last byte of the input data, which is the padding length.\n        var count = input[^1] & 0xFF;\n\n        // Calculate the position of the first padding byte.\n        var position = input.Length - count;\n\n        // Check if the position and count are valid using bitwise operations.\n        // If either of them is negative or zero, the result will be negative.\n        var failed = (position | (count - 1)) >> 31;\n\n        // Throw an exception if the result is negative.\n        if (failed != 0)\n        {\n            throw new ArgumentException(\"Pad block corrupted\");\n        }\n\n        // Return the padding length.\n        return count;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Utils/ByteEncodingUtils.cs",
    "content": "using System.Buffers.Binary;\nusing System.Runtime.CompilerServices;\n\nnamespace Algorithms.Crypto.Utils;\n\n/// <summary>\n/// Provides utility methods for converting between byte arrays and 64-bit unsigned integers using big-endian byte order.\n/// </summary>\n/// <remarks>\n/// The <see cref=\"ByteEncodingUtils\"/> class contains static methods that assist in reading and writing 64-bit unsigned integers\n/// from and to byte arrays or spans in big-endian format. These methods are optimized for cryptographic operations where byte\n/// encoding is critical for consistency and security.\n/// </remarks>\npublic static class ByteEncodingUtils\n{\n    /// <summary>\n    /// Converts an 8-byte segment from a byte array (starting at the specified offset) into a 64-bit unsigned integer using big-endian format.\n    /// </summary>\n    /// <param name=\"byteStream\">The byte array containing the input data.</param>\n    /// <param name=\"offset\">The offset within the byte array to start reading from.</param>\n    /// <returns>A 64-bit unsigned integer representing the big-endian interpretation of the byte array segment.</returns>\n    /// <exception cref=\"ArgumentOutOfRangeException\">Thrown if the specified offset is out of range of the byte array.</exception>\n    /// <remarks>\n    /// This method reads 8 bytes from the specified offset within the byte array and converts them to a 64-bit unsigned integer\n    /// in big-endian format. Big-endian format stores the most significant byte first, followed by the less significant bytes.\n    /// </remarks>\n    public static ulong BigEndianToUint64(byte[] byteStream, int offset)\n    {\n        return BinaryPrimitives.ReadUInt64BigEndian(byteStream.AsSpan(offset));\n    }\n\n    /// <summary>\n    /// Converts a read-only span of bytes into a 64-bit unsigned integer using big-endian format.\n    /// </summary>\n    /// <param name=\"byteStream\">A read-only span containing the input data.</param>\n    /// <returns>A 64-bit unsigned integer representing the big-endian interpretation of the span of bytes.</returns>\n    /// <remarks>\n    /// This method is optimized for performance using the <see cref=\"MethodImplOptions.AggressiveInlining\"/> attribute to encourage\n    /// inlining by the compiler. It reads exactly 8 bytes from the input span and converts them into a 64-bit unsigned integer.\n    /// </remarks>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static ulong BigEndianToUint64(ReadOnlySpan<byte> byteStream)\n    {\n        return BinaryPrimitives.ReadUInt64BigEndian(byteStream);\n    }\n\n    /// <summary>\n    /// Writes a 64-bit unsigned integer to a span of bytes using big-endian format.\n    /// </summary>\n    /// <param name=\"value\">The 64-bit unsigned integer to write.</param>\n    /// <param name=\"byteStream\">The span of bytes where the value will be written.</param>\n    /// <remarks>\n    /// This method writes the 64-bit unsigned integer into the span in big-endian format, where the most significant byte is written first.\n    /// The method is optimized using the <see cref=\"MethodImplOptions.AggressiveInlining\"/> attribute to improve performance in scenarios\n    /// where frequent byte-to-integer conversions are required, such as cryptographic algorithms.\n    /// </remarks>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static void UInt64ToBigEndian(ulong value, Span<byte> byteStream)\n    {\n        BinaryPrimitives.WriteUInt64BigEndian(byteStream, value);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Utils/LongUtils.cs",
    "content": "namespace Algorithms.Crypto.Utils;\n\n/// <summary>\n/// Provides utility methods for performing bitwise rotation operations (left and right) on 64-bit integers.\n/// </summary>\n/// <remarks>\n/// The <see cref=\"LongUtils\"/> class contains methods to rotate 64-bit signed and unsigned integers to the left or right.\n/// These rotations are crucial in various cryptographic algorithms, where circular shifts are used to mix data and\n/// introduce non-linearity. The methods use the underlying <see cref=\"System.Numerics.BitOperations\"/> for efficient,\n/// hardware-supported bitwise rotations.\n/// </remarks>\npublic static class LongUtils\n{\n    /// <summary>\n    /// Rotates the bits of a 64-bit signed integer to the left by a specified number of bits.\n    /// </summary>\n    /// <param name=\"i\">The 64-bit signed integer to rotate.</param>\n    /// <param name=\"distance\">The number of bits to rotate the integer to the left.</param>\n    /// <returns>The result of rotating the integer to the left by the specified distance.</returns>\n    /// <remarks>\n    /// This method uses the underlying <see cref=\"BitOperations.RotateLeft(ulong, int)\"/> method, converting the signed integer to an unsigned integer\n    /// for the rotation, then casting it back to a signed integer. The rotation is performed in a circular manner, where bits shifted\n    /// out of the most significant bit are reintroduced into the least significant bit.\n    /// </remarks>\n    public static long RotateLeft(long i, int distance)\n    {\n        return (long)BitOperations.RotateLeft((ulong)i, distance);\n    }\n\n    /// <summary>\n    /// Rotates the bits of a 64-bit unsigned integer to the left by a specified number of bits.\n    /// </summary>\n    /// <param name=\"i\">The 64-bit unsigned integer to rotate.</param>\n    /// <param name=\"distance\">The number of bits to rotate the integer to the left.</param>\n    /// <returns>The result of rotating the integer to the left by the specified distance.</returns>\n    /// <remarks>\n    /// The rotation is performed circularly, meaning bits shifted out of the most significant bit are reintroduced into\n    /// the least significant bit. This method is optimized for performance using hardware-supported operations through\n    /// <see cref=\"BitOperations.RotateLeft(ulong, int)\"/>.\n    /// </remarks>\n    public static ulong RotateLeft(ulong i, int distance)\n    {\n        return BitOperations.RotateLeft(i, distance);\n    }\n\n    /// <summary>\n    /// Rotates the bits of a 64-bit signed integer to the right by a specified number of bits.\n    /// </summary>\n    /// <param name=\"i\">The 64-bit signed integer to rotate.</param>\n    /// <param name=\"distance\">The number of bits to rotate the integer to the right.</param>\n    /// <returns>The result of rotating the integer to the right by the specified distance.</returns>\n    /// <remarks>\n    /// Similar to the left rotation, this method uses <see cref=\"BitOperations.RotateRight(ulong, int)\"/> to perform the rotation.\n    /// The signed integer is cast to an unsigned integer for the operation and cast back to a signed integer afterward.\n    /// The rotation wraps bits shifted out of the least significant bit into the most significant bit.\n    /// </remarks>\n    public static long RotateRight(long i, int distance)\n    {\n        return (long)BitOperations.RotateRight((ulong)i, distance);\n    }\n\n    /// <summary>\n    /// Rotates the bits of a 64-bit unsigned integer to the right by a specified number of bits.\n    /// </summary>\n    /// <param name=\"i\">The 64-bit unsigned integer to rotate.</param>\n    /// <param name=\"distance\">The number of bits to rotate the integer to the right.</param>\n    /// <returns>The result of rotating the integer to the right by the specified distance.</returns>\n    /// <remarks>\n    /// This method performs the rotation circularly, where bits shifted out of the least significant bit are reintroduced\n    /// into the most significant bit. The operation uses hardware-supported instructions via <see cref=\"BitOperations.RotateRight(ulong, int)\"/>.\n    /// </remarks>\n    public static ulong RotateRight(ulong i, int distance)\n    {\n        return BitOperations.RotateRight(i, distance);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Crypto/Utils/ValidationUtils.cs",
    "content": "using Algorithms.Crypto.Exceptions;\n\nnamespace Algorithms.Crypto.Utils;\n\n/// <summary>\n/// Provides utility methods for validating the lengths of input and output data in cryptographic operations.\n/// </summary>\n/// <remarks>\n/// The <see cref=\"ValidationUtils\"/> class contains static methods to validate the length and position of data buffers used in\n/// cryptographic operations. These methods throw appropriate exceptions such as <see cref=\"DataLengthException\"/> or\n/// <see cref=\"OutputLengthException\"/> when the validation fails. These are critical for ensuring that cryptographic computations\n/// do not run into buffer overflows, underflows, or incorrect input/output buffer lengths.\n/// </remarks>\npublic static class ValidationUtils\n{\n    /// <summary>\n    /// Validates that the specified offset and length fit within the bounds of the given buffer.\n    /// </summary>\n    /// <param name=\"buffer\">The byte array to validate.</param>\n    /// <param name=\"offset\">The offset into the byte array where validation should start.</param>\n    /// <param name=\"length\">The number of bytes to validate from the specified offset.</param>\n    /// <param name=\"message\">The message that describes the error if the exception is thrown.</param>\n    /// <exception cref=\"DataLengthException\">Thrown if the offset and length exceed the bounds of the buffer.</exception>\n    /// <remarks>\n    /// This method ensures that the specified offset and length fit within the bounds of the buffer. If the offset and length\n    /// go out of bounds, a <see cref=\"DataLengthException\"/> is thrown with the provided error message.\n    /// </remarks>\n    public static void CheckDataLength(byte[] buffer, int offset, int length, string message)\n    {\n        if (offset > (buffer.Length - length))\n        {\n            throw new DataLengthException(message);\n        }\n    }\n\n    /// <summary>\n    /// Throws an <see cref=\"OutputLengthException\"/> if the specified condition is true.\n    /// </summary>\n    /// <param name=\"condition\">A boolean condition indicating whether the exception should be thrown.</param>\n    /// <param name=\"message\">The message that describes the error if the exception is thrown.</param>\n    /// <exception cref=\"OutputLengthException\">Thrown if the condition is true.</exception>\n    /// <remarks>\n    /// This method performs a simple conditional check for output length validation. If the condition is true, an\n    /// <see cref=\"OutputLengthException\"/> is thrown with the provided message.\n    /// </remarks>\n    public static void CheckOutputLength(bool condition, string message)\n    {\n        if (condition)\n        {\n            throw new OutputLengthException(message);\n        }\n    }\n\n    /// <summary>\n    /// Validates that the specified offset and length fit within the bounds of the output buffer.\n    /// </summary>\n    /// <param name=\"buffer\">The byte array to validate.</param>\n    /// <param name=\"offset\">The offset into the byte array where validation should start.</param>\n    /// <param name=\"length\">The number of bytes to validate from the specified offset.</param>\n    /// <param name=\"message\">The message that describes the error if the exception is thrown.</param>\n    /// <exception cref=\"OutputLengthException\">Thrown if the offset and length exceed the bounds of the buffer.</exception>\n    /// <remarks>\n    /// This method ensures that the specified offset and length do not exceed the bounds of the output buffer. If the\n    /// validation fails, an <see cref=\"OutputLengthException\"/> is thrown with the provided message.\n    /// </remarks>\n    public static void CheckOutputLength(byte[] buffer, int offset, int length, string message)\n    {\n        if (offset > (buffer.Length - length))\n        {\n            throw new OutputLengthException(message);\n        }\n    }\n\n    /// <summary>\n    /// Validates that the length of the output span does not exceed the specified length.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of elements in the span.</typeparam>\n    /// <param name=\"output\">The span to validate.</param>\n    /// <param name=\"length\">The maximum allowed length for the output span.</param>\n    /// <param name=\"message\">The message that describes the error if the exception is thrown.</param>\n    /// <exception cref=\"OutputLengthException\">Thrown if the length of the output span exceeds the specified length.</exception>\n    /// <remarks>\n    /// This method checks that the span does not exceed the specified length. If the span length exceeds the allowed length,\n    /// an <see cref=\"OutputLengthException\"/> is thrown with the provided error message.\n    /// </remarks>\n    public static void CheckOutputLength<T>(Span<T> output, int length, string message)\n    {\n        if (output.Length > length)\n        {\n            throw new OutputLengthException(message);\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/DataCompression/BurrowsWheelerTransform.cs",
    "content": "namespace Algorithms.DataCompression;\n\n/// <summary>\n///     The Burrows–Wheeler transform (BWT) rearranges a character string into runs of similar characters.\n///     This is useful for compression, since it tends to be easy to compress a string that has runs of repeated\n///     characters.\n///     See <a href=\"https://en.wikipedia.org/wiki/Burrows%E2%80%93Wheeler_transform\">here</a> for more info.\n/// </summary>\npublic class BurrowsWheelerTransform\n{\n    /// <summary>\n    ///     Encodes the input string using BWT and returns encoded string and the index of original string in the sorted\n    ///     rotation matrix.\n    /// </summary>\n    /// <param name=\"s\">Input string.</param>\n    public (string Encoded, int Index) Encode(string s)\n    {\n        if (s.Length == 0)\n        {\n            return (string.Empty, 0);\n        }\n\n        var rotations = GetRotations(s);\n        Array.Sort(rotations, StringComparer.Ordinal);\n        var lastColumn = rotations\n            .Select(x => x[^1])\n            .ToArray();\n        var encoded = new string(lastColumn);\n        return (encoded, Array.IndexOf(rotations, s));\n    }\n\n    /// <summary>\n    ///     Decodes the input string and returns original string.\n    /// </summary>\n    /// <param name=\"s\">Encoded string.</param>\n    /// <param name=\"index\">Index  of original string in the sorted rotation matrix.</param>\n    public string Decode(string s, int index)\n    {\n        if (s.Length == 0)\n        {\n            return string.Empty;\n        }\n\n        var rotations = new string[s.Length];\n\n        for (var i = 0; i < s.Length; i++)\n        {\n            for (var j = 0; j < s.Length; j++)\n            {\n                rotations[j] = s[j] + rotations[j];\n            }\n\n            Array.Sort(rotations, StringComparer.Ordinal);\n        }\n\n        return rotations[index];\n    }\n\n    private string[] GetRotations(string s)\n    {\n        var result = new string[s.Length];\n\n        for (var i = 0; i < s.Length; i++)\n        {\n            result[i] = s.Substring(i) + s.Substring(0, i);\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "Algorithms/DataCompression/HuffmanCompressor.cs",
    "content": "using Algorithms.Sorters.Comparison;\n\nnamespace Algorithms.DataCompression;\n\n/// <summary>\n///     Greedy lossless compression algorithm.\n/// </summary>\npublic class HuffmanCompressor(IComparisonSorter<HuffmanCompressor.ListNode> sorter, Translator translator)\n{\n    // TODO: Use partial sorter\n    private readonly IComparisonSorter<ListNode> sorter = sorter;\n    private readonly Translator translator = translator;\n\n    /// <summary>\n    ///     Given an input string, returns a new compressed string\n    ///     using huffman encoding.\n    /// </summary>\n    /// <param name=\"uncompressedText\">Text message to compress.</param>\n    /// <returns>Compressed string and keys to decompress it.</returns>\n    public (string CompressedText, Dictionary<string, string> DecompressionKeys) Compress(string uncompressedText)\n    {\n        if (string.IsNullOrEmpty(uncompressedText))\n        {\n            return (string.Empty, []);\n        }\n\n        if (uncompressedText.Distinct().Count() == 1)\n        {\n            var dict = new Dictionary<string, string>\n            {\n                [\"1\"] = uncompressedText[0].ToString(),\n            };\n            return (new string('1', uncompressedText.Length), dict);\n        }\n\n        var nodes = GetListNodesFromText(uncompressedText);\n        var tree = GenerateHuffmanTree(nodes);\n        var (compressionKeys, decompressionKeys) = GetKeys(tree);\n        return (translator.Translate(uncompressedText, compressionKeys), decompressionKeys);\n    }\n\n    /// <summary>\n    ///     Finds frequency for each character in the text.\n    /// </summary>\n    /// <returns>Symbol-frequency array.</returns>\n    private static ListNode[] GetListNodesFromText(string text)\n    {\n        var occurenceCounts = new Dictionary<char, int>();\n\n        foreach (var ch in text)\n        {\n            if (!occurenceCounts.ContainsKey(ch))\n            {\n                occurenceCounts.Add(ch, 0);\n            }\n\n            occurenceCounts[ch]++;\n        }\n\n        return occurenceCounts.Select(kvp => new ListNode(kvp.Key, 1d * kvp.Value / text.Length)).ToArray();\n    }\n\n    private (Dictionary<string, string> CompressionKeys, Dictionary<string, string> DecompressionKeys) GetKeys(\n        ListNode tree)\n    {\n        var compressionKeys = new Dictionary<string, string>();\n        var decompressionKeys = new Dictionary<string, string>();\n\n        if (tree.HasData)\n        {\n            compressionKeys.Add(tree.Data.ToString(), string.Empty);\n            decompressionKeys.Add(string.Empty, tree.Data.ToString());\n            return (compressionKeys, decompressionKeys);\n        }\n\n        if (tree.LeftChild is not null)\n        {\n            var (lsck, lsdk) = GetKeys(tree.LeftChild);\n            compressionKeys.AddMany(lsck.Select(kvp => (kvp.Key, \"0\" + kvp.Value)));\n            decompressionKeys.AddMany(lsdk.Select(kvp => (\"0\" + kvp.Key, kvp.Value)));\n        }\n\n        if (tree.RightChild is not null)\n        {\n            var (rsck, rsdk) = GetKeys(tree.RightChild);\n            compressionKeys.AddMany(rsck.Select(kvp => (kvp.Key, \"1\" + kvp.Value)));\n            decompressionKeys.AddMany(rsdk.Select(kvp => (\"1\" + kvp.Key, kvp.Value)));\n\n            return (compressionKeys, decompressionKeys);\n        }\n\n        return (compressionKeys, decompressionKeys);\n    }\n\n    private ListNode GenerateHuffmanTree(ListNode[] nodes)\n    {\n        var comparer = new ListNodeComparer();\n        while (nodes.Length > 1)\n        {\n            sorter.Sort(nodes, comparer);\n\n            var left = nodes[0];\n            var right = nodes[1];\n\n            var newNodes = new ListNode[nodes.Length - 1];\n            Array.Copy(nodes, 2, newNodes, 1, nodes.Length - 2);\n            newNodes[0] = new ListNode(left, right);\n            nodes = newNodes;\n        }\n\n        return nodes[0];\n    }\n\n    /// <summary>\n    ///     Represents tree structure for the algorithm.\n    /// </summary>\n    public class ListNode\n    {\n        public ListNode(char data, double frequency)\n        {\n            HasData = true;\n            Data = data;\n            Frequency = frequency;\n        }\n\n        public ListNode(ListNode leftChild, ListNode rightChild)\n        {\n            LeftChild = leftChild;\n            RightChild = rightChild;\n            Frequency = leftChild.Frequency + rightChild.Frequency;\n        }\n\n        public char Data { get; }\n\n        public bool HasData { get; }\n\n        public double Frequency { get; }\n\n        public ListNode? RightChild { get; }\n\n        public ListNode? LeftChild { get; }\n    }\n\n    public class ListNodeComparer : IComparer<ListNode>\n    {\n        public int Compare(ListNode? x, ListNode? y)\n        {\n            if (x is null || y is null)\n            {\n                return 0;\n            }\n\n            return x.Frequency.CompareTo(y.Frequency);\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/DataCompression/ShannonFanoCompressor.cs",
    "content": "using Algorithms.Knapsack;\n\nnamespace Algorithms.DataCompression;\n\n/// <summary>\n///     Greedy lossless compression algorithm.\n/// </summary>\npublic class ShannonFanoCompressor(\n    IHeuristicKnapsackSolver<(char Symbol, double Frequency)> splitter,\n    Translator translator)\n{\n    private readonly IHeuristicKnapsackSolver<(char Symbol, double Frequency)> splitter = splitter;\n    private readonly Translator translator = translator;\n\n    /// <summary>\n    ///     Given an input string, returns a new compressed string\n    ///     using Shannon-Fano encoding.\n    /// </summary>\n    /// <param name=\"uncompressedText\">Text message to compress.</param>\n    /// <returns>Compressed string and keys to decompress it.</returns>\n    public (string CompressedText, Dictionary<string, string> DecompressionKeys) Compress(string uncompressedText)\n    {\n        if (string.IsNullOrEmpty(uncompressedText))\n        {\n            return (string.Empty, new Dictionary<string, string>());\n        }\n\n        if (uncompressedText.Distinct().Count() == 1)\n        {\n            var dict = new Dictionary<string, string>\n            {\n                { \"1\", uncompressedText[0].ToString() },\n            };\n            return (new string('1', uncompressedText.Length), dict);\n        }\n\n        var node = GetListNodeFromText(uncompressedText);\n        var tree = GenerateShannonFanoTree(node);\n        var (compressionKeys, decompressionKeys) = GetKeys(tree);\n        return (translator.Translate(uncompressedText, compressionKeys), decompressionKeys);\n    }\n\n    private (Dictionary<string, string> CompressionKeys, Dictionary<string, string> DecompressionKeys) GetKeys(\n        ListNode tree)\n    {\n        var compressionKeys = new Dictionary<string, string>();\n        var decompressionKeys = new Dictionary<string, string>();\n\n        if (tree.Data.Length == 1)\n        {\n            compressionKeys.Add(tree.Data[0].Symbol.ToString(), string.Empty);\n            decompressionKeys.Add(string.Empty, tree.Data[0].Symbol.ToString());\n            return (compressionKeys, decompressionKeys);\n        }\n\n        if (tree.LeftChild is not null)\n        {\n            var (lsck, lsdk) = GetKeys(tree.LeftChild);\n            compressionKeys.AddMany(lsck.Select(kvp => (kvp.Key, \"0\" + kvp.Value)));\n            decompressionKeys.AddMany(lsdk.Select(kvp => (\"0\" + kvp.Key, kvp.Value)));\n        }\n\n        if (tree.RightChild is not null)\n        {\n            var (rsck, rsdk) = GetKeys(tree.RightChild);\n            compressionKeys.AddMany(rsck.Select(kvp => (kvp.Key, \"1\" + kvp.Value)));\n            decompressionKeys.AddMany(rsdk.Select(kvp => (\"1\" + kvp.Key, kvp.Value)));\n        }\n\n        return (compressionKeys, decompressionKeys);\n    }\n\n    private ListNode GenerateShannonFanoTree(ListNode node)\n    {\n        if (node.Data.Length == 1)\n        {\n            return node;\n        }\n\n        var left = splitter.Solve(node.Data, 0.5 * node.Data.Sum(x => x.Frequency), x => x.Frequency, _ => 1);\n        var right = node.Data.Except(left).ToArray();\n\n        node.LeftChild = GenerateShannonFanoTree(new ListNode(left));\n        node.RightChild = GenerateShannonFanoTree(new ListNode(right));\n\n        return node;\n    }\n\n    /// <summary>\n    ///     Finds frequency for each character in the text.\n    /// </summary>\n    /// <returns>Symbol-frequency array.</returns>\n    private ListNode GetListNodeFromText(string text)\n    {\n        var occurenceCounts = new Dictionary<char, double>();\n\n        for (var i = 0; i < text.Length; i++)\n        {\n            var ch = text[i];\n            if (!occurenceCounts.ContainsKey(ch))\n            {\n                occurenceCounts.Add(ch, 0);\n            }\n\n            occurenceCounts[ch]++;\n        }\n\n        return new ListNode(occurenceCounts.Select(kvp => (kvp.Key, 1d * kvp.Value / text.Length)).ToArray());\n    }\n\n    /// <summary>\n    ///     Represents tree structure for the algorithm.\n    /// </summary>\n    public class ListNode((char Symbol, double Frequency)[] data)\n    {\n        public (char Symbol, double Frequency)[] Data { get; } = data;\n\n        public ListNode? RightChild { get; set; }\n\n        public ListNode? LeftChild { get; set; }\n    }\n}\n"
  },
  {
    "path": "Algorithms/DataCompression/Translator.cs",
    "content": "namespace Algorithms.DataCompression;\n\n/// <summary>\n///     Provides method for text conversion by key mapping.\n/// </summary>\npublic class Translator\n{\n    /// <summary>\n    ///     Converts the input text according to the translation keys.\n    /// </summary>\n    /// <param name=\"text\">Input text.</param>\n    /// <param name=\"translationKeys\">Translation keys used for text matching.</param>\n    /// <returns>Converted text according to the translation keys.</returns>\n    public string Translate(string text, Dictionary<string, string> translationKeys)\n    {\n        var sb = new StringBuilder();\n\n        var start = 0;\n        for (var i = 0; i < text.Length; i++)\n        {\n            var key = text.Substring(start, i - start + 1);\n            if (translationKeys.ContainsKey(key))\n            {\n                _ = sb.Append(translationKeys[key]);\n                start = i + 1;\n            }\n        }\n\n        return sb.ToString();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Encoders/AutokeyEncorder.cs",
    "content": "namespace Algorithms.Encoders\n{\n    /// <summary>\n    ///     Class for AutoKey encoding strings.\n    /// </summary>\n    public class AutokeyEncorder\n    {\n        /// <summary>\n        ///     Autokey Cipher is a type of polyalphabetic cipher.\n        ///     This works by choosing a key (a word or short phrase),\n        ///     then you append the plaintext to itself to form a longer key.\n        /// </summary>\n        /// <param name=\"plainText\">The string to be appended to the key.</param>\n        /// <param name=\"keyword\">The string to be appended to the plaintext.</param>\n        /// <returns>The Autokey encoded string (All Uppercase).</returns>\n        public string Encode(string plainText, string keyword)\n        {\n            plainText = Regex.Replace(plainText.ToUpper(CultureInfo.InvariantCulture), \"[^A-Z]\", string.Empty);\n            keyword = keyword.ToUpper(CultureInfo.InvariantCulture);\n\n            keyword += plainText;\n\n            StringBuilder cipherText = new StringBuilder();\n\n            for (int i = 0; i < plainText.Length; i++)\n            {\n                char plainCharacter = plainText[i];\n                char keyCharacter = keyword[i];\n\n                int encryptedCharacter = (plainCharacter - 'A' + keyCharacter - 'A') % 26 + 'A';\n                cipherText.Append((char)encryptedCharacter);\n            }\n\n            return cipherText.ToString();\n        }\n\n        /// <summary>\n        ///     Removed the key from the encoded string.\n        /// </summary>\n        /// <param name=\"cipherText\">The encoded string.</param>\n        /// <param name=\"keyword\">The key to be removed from the encoded string.</param>\n        /// <returns>The plaintext (All Uppercase).</returns>\n        public string Decode(string cipherText, string keyword)\n        {\n            cipherText = Regex.Replace(cipherText.ToUpper(CultureInfo.InvariantCulture), \"[^A-Z]\", string.Empty);\n            keyword = keyword.ToUpper(CultureInfo.InvariantCulture);\n\n            StringBuilder plainText = new StringBuilder();\n            StringBuilder extendedKeyword = new StringBuilder(keyword);\n\n            for (int i = 0; i < cipherText.Length; i++)\n            {\n                char cipherCharacter = cipherText[i];\n                char keywordCharacter = extendedKeyword[i];\n\n                int decryptedCharacter = (cipherCharacter - 'A' - (keywordCharacter - 'A') + 26) % 26 + 'A';\n                plainText.Append((char)decryptedCharacter);\n                extendedKeyword.Append((char)decryptedCharacter);\n            }\n\n            return plainText.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Encoders/BlowfishEncoder.cs",
    "content": "namespace Algorithms.Encoders;\n\n/// <summary>\n/// <para>\n/// The Blowfish algorithm is a symmetric-key block cipher, which means it uses the same secret key to encrypt and\n/// decrypt data. It was designed by Bruce Schneier in 1993.\n/// </para>\n/// <para>\n/// The blowfish algorithm works on 64-bit blocks of data, which are divided into two 32-bit halves: left and right.\n/// It uses a variable-length key, from 32 bits to 448 bits, to generate 18 subkeys and four S-boxes, which are arrays\n/// of 256 32-bit words. The subkeys and the S-boxes are key-dependent, meaning that they change according to the secret key.\n/// </para>\n/// <para>\n/// The blowfish algorithm performs 16 rounds of encryption or decryption on each block of data, using a Feistel network\n/// structure. In each round, the left half is XORed with a subkey, then passed through a function F that applies four\n/// S-box lookups and two XOR operations. The output of F is then XORed with the right half. The left and right halves\n/// are swapped at the end of each round, except for the last one. The final output is XORed with two more subkeys to\n/// produce the encrypted or decrypted block.\n/// </para>\n/// <see href=\"https://en.wikipedia.org/wiki/Blowfish_%28cipher%29\">Blowfish on Wikipedia</see>.\n/// </summary>\npublic class BlowfishEncoder\n{\n    // Initialize modVal to 2^32\n    private const ulong ModVal = 4294967296L;\n\n    // Initialize the substitution boxes\n    private readonly string[][] s =\n    [\n        [\n            \"d1310ba6\", \"98dfb5ac\", \"2ffd72db\", \"d01adfb7\", \"b8e1afed\", \"6a267e96\", \"ba7c9045\", \"f12c7f99\",\n            \"24a19947\", \"b3916cf7\", \"0801f2e2\", \"858efc16\", \"636920d8\", \"71574e69\", \"a458fea3\", \"f4933d7e\",\n            \"0d95748f\", \"728eb658\", \"718bcd58\", \"82154aee\", \"7b54a41d\", \"c25a59b5\", \"9c30d539\", \"2af26013\",\n            \"c5d1b023\", \"286085f0\", \"ca417918\", \"b8db38ef\", \"8e79dcb0\", \"603a180e\", \"6c9e0e8b\", \"b01e8a3e\",\n            \"d71577c1\", \"bd314b27\", \"78af2fda\", \"55605c60\", \"e65525f3\", \"aa55ab94\", \"57489862\", \"63e81440\",\n            \"55ca396a\", \"2aab10b6\", \"b4cc5c34\", \"1141e8ce\", \"a15486af\", \"7c72e993\", \"b3ee1411\", \"636fbc2a\",\n            \"2ba9c55d\", \"741831f6\", \"ce5c3e16\", \"9b87931e\", \"afd6ba33\", \"6c24cf5c\", \"7a325381\", \"28958677\",\n            \"3b8f4898\", \"6b4bb9af\", \"c4bfe81b\", \"66282193\", \"61d809cc\", \"fb21a991\", \"487cac60\", \"5dec8032\",\n            \"ef845d5d\", \"e98575b1\", \"dc262302\", \"eb651b88\", \"23893e81\", \"d396acc5\", \"0f6d6ff3\", \"83f44239\",\n            \"2e0b4482\", \"a4842004\", \"69c8f04a\", \"9e1f9b5e\", \"21c66842\", \"f6e96c9a\", \"670c9c61\", \"abd388f0\",\n            \"6a51a0d2\", \"d8542f68\", \"960fa728\", \"ab5133a3\", \"6eef0b6c\", \"137a3be4\", \"ba3bf050\", \"7efb2a98\",\n            \"a1f1651d\", \"39af0176\", \"66ca593e\", \"82430e88\", \"8cee8619\", \"456f9fb4\", \"7d84a5c3\", \"3b8b5ebe\",\n            \"e06f75d8\", \"85c12073\", \"401a449f\", \"56c16aa6\", \"4ed3aa62\", \"363f7706\", \"1bfedf72\", \"429b023d\",\n            \"37d0d724\", \"d00a1248\", \"db0fead3\", \"49f1c09b\", \"075372c9\", \"80991b7b\", \"25d479d8\", \"f6e8def7\",\n            \"e3fe501a\", \"b6794c3b\", \"976ce0bd\", \"04c006ba\", \"c1a94fb6\", \"409f60c4\", \"5e5c9ec2\", \"196a2463\",\n            \"68fb6faf\", \"3e6c53b5\", \"1339b2eb\", \"3b52ec6f\", \"6dfc511f\", \"9b30952c\", \"cc814544\", \"af5ebd09\",\n            \"bee3d004\", \"de334afd\", \"660f2807\", \"192e4bb3\", \"c0cba857\", \"45c8740f\", \"d20b5f39\", \"b9d3fbdb\",\n            \"5579c0bd\", \"1a60320a\", \"d6a100c6\", \"402c7279\", \"679f25fe\", \"fb1fa3cc\", \"8ea5e9f8\", \"db3222f8\",\n            \"3c7516df\", \"fd616b15\", \"2f501ec8\", \"ad0552ab\", \"323db5fa\", \"fd238760\", \"53317b48\", \"3e00df82\",\n            \"9e5c57bb\", \"ca6f8ca0\", \"1a87562e\", \"df1769db\", \"d542a8f6\", \"287effc3\", \"ac6732c6\", \"8c4f5573\",\n            \"695b27b0\", \"bbca58c8\", \"e1ffa35d\", \"b8f011a0\", \"10fa3d98\", \"fd2183b8\", \"4afcb56c\", \"2dd1d35b\",\n            \"9a53e479\", \"b6f84565\", \"d28e49bc\", \"4bfb9790\", \"e1ddf2da\", \"a4cb7e33\", \"62fb1341\", \"cee4c6e8\",\n            \"ef20cada\", \"36774c01\", \"d07e9efe\", \"2bf11fb4\", \"95dbda4d\", \"ae909198\", \"eaad8e71\", \"6b93d5a0\",\n            \"d08ed1d0\", \"afc725e0\", \"8e3c5b2f\", \"8e7594b7\", \"8ff6e2fb\", \"f2122b64\", \"8888b812\", \"900df01c\",\n            \"4fad5ea0\", \"688fc31c\", \"d1cff191\", \"b3a8c1ad\", \"2f2f2218\", \"be0e1777\", \"ea752dfe\", \"8b021fa1\",\n            \"e5a0cc0f\", \"b56f74e8\", \"18acf3d6\", \"ce89e299\", \"b4a84fe0\", \"fd13e0b7\", \"7cc43b81\", \"d2ada8d9\",\n            \"165fa266\", \"80957705\", \"93cc7314\", \"211a1477\", \"e6ad2065\", \"77b5fa86\", \"c75442f5\", \"fb9d35cf\",\n            \"ebcdaf0c\", \"7b3e89a0\", \"d6411bd3\", \"ae1e7e49\", \"00250e2d\", \"2071b35e\", \"226800bb\", \"57b8e0af\",\n            \"2464369b\", \"f009b91e\", \"5563911d\", \"59dfa6aa\", \"78c14389\", \"d95a537f\", \"207d5ba2\", \"02e5b9c5\",\n            \"83260376\", \"6295cfa9\", \"11c81968\", \"4e734a41\", \"b3472dca\", \"7b14a94a\", \"1b510052\", \"9a532915\",\n            \"d60f573f\", \"bc9bc6e4\", \"2b60a476\", \"81e67400\", \"08ba6fb5\", \"571be91f\", \"f296ec6b\", \"2a0dd915\",\n            \"b6636521\", \"e7b9f9b6\", \"ff34052e\", \"c5855664\", \"53b02d5d\", \"a99f8fa1\", \"08ba4799\", \"6e85076a\",\n        ],\n        [\n            \"4b7a70e9\", \"b5b32944\", \"db75092e\", \"c4192623\", \"ad6ea6b0\", \"49a7df7d\", \"9cee60b8\", \"8fedb266\",\n            \"ecaa8c71\", \"699a17ff\", \"5664526c\", \"c2b19ee1\", \"193602a5\", \"75094c29\", \"a0591340\", \"e4183a3e\",\n            \"3f54989a\", \"5b429d65\", \"6b8fe4d6\", \"99f73fd6\", \"a1d29c07\", \"efe830f5\", \"4d2d38e6\", \"f0255dc1\",\n            \"4cdd2086\", \"8470eb26\", \"6382e9c6\", \"021ecc5e\", \"09686b3f\", \"3ebaefc9\", \"3c971814\", \"6b6a70a1\",\n            \"687f3584\", \"52a0e286\", \"b79c5305\", \"aa500737\", \"3e07841c\", \"7fdeae5c\", \"8e7d44ec\", \"5716f2b8\",\n            \"b03ada37\", \"f0500c0d\", \"f01c1f04\", \"0200b3ff\", \"ae0cf51a\", \"3cb574b2\", \"25837a58\", \"dc0921bd\",\n            \"d19113f9\", \"7ca92ff6\", \"94324773\", \"22f54701\", \"3ae5e581\", \"37c2dadc\", \"c8b57634\", \"9af3dda7\",\n            \"a9446146\", \"0fd0030e\", \"ecc8c73e\", \"a4751e41\", \"e238cd99\", \"3bea0e2f\", \"3280bba1\", \"183eb331\",\n            \"4e548b38\", \"4f6db908\", \"6f420d03\", \"f60a04bf\", \"2cb81290\", \"24977c79\", \"5679b072\", \"bcaf89af\",\n            \"de9a771f\", \"d9930810\", \"b38bae12\", \"dccf3f2e\", \"5512721f\", \"2e6b7124\", \"501adde6\", \"9f84cd87\",\n            \"7a584718\", \"7408da17\", \"bc9f9abc\", \"e94b7d8c\", \"ec7aec3a\", \"db851dfa\", \"63094366\", \"c464c3d2\",\n            \"ef1c1847\", \"3215d908\", \"dd433b37\", \"24c2ba16\", \"12a14d43\", \"2a65c451\", \"50940002\", \"133ae4dd\",\n            \"71dff89e\", \"10314e55\", \"81ac77d6\", \"5f11199b\", \"043556f1\", \"d7a3c76b\", \"3c11183b\", \"5924a509\",\n            \"f28fe6ed\", \"97f1fbfa\", \"9ebabf2c\", \"1e153c6e\", \"86e34570\", \"eae96fb1\", \"860e5e0a\", \"5a3e2ab3\",\n            \"771fe71c\", \"4e3d06fa\", \"2965dcb9\", \"99e71d0f\", \"803e89d6\", \"5266c825\", \"2e4cc978\", \"9c10b36a\",\n            \"c6150eba\", \"94e2ea78\", \"a5fc3c53\", \"1e0a2df4\", \"f2f74ea7\", \"361d2b3d\", \"1939260f\", \"19c27960\",\n            \"5223a708\", \"f71312b6\", \"ebadfe6e\", \"eac31f66\", \"e3bc4595\", \"a67bc883\", \"b17f37d1\", \"018cff28\",\n            \"c332ddef\", \"be6c5aa5\", \"65582185\", \"68ab9802\", \"eecea50f\", \"db2f953b\", \"2aef7dad\", \"5b6e2f84\",\n            \"1521b628\", \"29076170\", \"ecdd4775\", \"619f1510\", \"13cca830\", \"eb61bd96\", \"0334fe1e\", \"aa0363cf\",\n            \"b5735c90\", \"4c70a239\", \"d59e9e0b\", \"cbaade14\", \"eecc86bc\", \"60622ca7\", \"9cab5cab\", \"b2f3846e\",\n            \"648b1eaf\", \"19bdf0ca\", \"a02369b9\", \"655abb50\", \"40685a32\", \"3c2ab4b3\", \"319ee9d5\", \"c021b8f7\",\n            \"9b540b19\", \"875fa099\", \"95f7997e\", \"623d7da8\", \"f837889a\", \"97e32d77\", \"11ed935f\", \"16681281\",\n            \"0e358829\", \"c7e61fd6\", \"96dedfa1\", \"7858ba99\", \"57f584a5\", \"1b227263\", \"9b83c3ff\", \"1ac24696\",\n            \"cdb30aeb\", \"532e3054\", \"8fd948e4\", \"6dbc3128\", \"58ebf2ef\", \"34c6ffea\", \"fe28ed61\", \"ee7c3c73\",\n            \"5d4a14d9\", \"e864b7e3\", \"42105d14\", \"203e13e0\", \"45eee2b6\", \"a3aaabea\", \"db6c4f15\", \"facb4fd0\",\n            \"c742f442\", \"ef6abbb5\", \"654f3b1d\", \"41cd2105\", \"d81e799e\", \"86854dc7\", \"e44b476a\", \"3d816250\",\n            \"cf62a1f2\", \"5b8d2646\", \"fc8883a0\", \"c1c7b6a3\", \"7f1524c3\", \"69cb7492\", \"47848a0b\", \"5692b285\",\n            \"095bbf00\", \"ad19489d\", \"1462b174\", \"23820e00\", \"58428d2a\", \"0c55f5ea\", \"1dadf43e\", \"233f7061\",\n            \"3372f092\", \"8d937e41\", \"d65fecf1\", \"6c223bdb\", \"7cde3759\", \"cbee7460\", \"4085f2a7\", \"ce77326e\",\n            \"a6078084\", \"19f8509e\", \"e8efd855\", \"61d99735\", \"a969a7aa\", \"c50c06c2\", \"5a04abfc\", \"800bcadc\",\n            \"9e447a2e\", \"c3453484\", \"fdd56705\", \"0e1e9ec9\", \"db73dbd3\", \"105588cd\", \"675fda79\", \"e3674340\",\n            \"c5c43465\", \"713e38d8\", \"3d28f89e\", \"f16dff20\", \"153e21e7\", \"8fb03d4a\", \"e6e39f2b\", \"db83adf7\",\n        ],\n        [\n            \"e93d5a68\", \"948140f7\", \"f64c261c\", \"94692934\", \"411520f7\", \"7602d4f7\", \"bcf46b2e\", \"d4a20068\",\n            \"d4082471\", \"3320f46a\", \"43b7d4b7\", \"500061af\", \"1e39f62e\", \"97244546\", \"14214f74\", \"bf8b8840\",\n            \"4d95fc1d\", \"96b591af\", \"70f4ddd3\", \"66a02f45\", \"bfbc09ec\", \"03bd9785\", \"7fac6dd0\", \"31cb8504\",\n            \"96eb27b3\", \"55fd3941\", \"da2547e6\", \"abca0a9a\", \"28507825\", \"530429f4\", \"0a2c86da\", \"e9b66dfb\",\n            \"68dc1462\", \"d7486900\", \"680ec0a4\", \"27a18dee\", \"4f3ffea2\", \"e887ad8c\", \"b58ce006\", \"7af4d6b6\",\n            \"aace1e7c\", \"d3375fec\", \"ce78a399\", \"406b2a42\", \"20fe9e35\", \"d9f385b9\", \"ee39d7ab\", \"3b124e8b\",\n            \"1dc9faf7\", \"4b6d1856\", \"26a36631\", \"eae397b2\", \"3a6efa74\", \"dd5b4332\", \"6841e7f7\", \"ca7820fb\",\n            \"fb0af54e\", \"d8feb397\", \"454056ac\", \"ba489527\", \"55533a3a\", \"20838d87\", \"fe6ba9b7\", \"d096954b\",\n            \"55a867bc\", \"a1159a58\", \"cca92963\", \"99e1db33\", \"a62a4a56\", \"3f3125f9\", \"5ef47e1c\", \"9029317c\",\n            \"fdf8e802\", \"04272f70\", \"80bb155c\", \"05282ce3\", \"95c11548\", \"e4c66d22\", \"48c1133f\", \"c70f86dc\",\n            \"07f9c9ee\", \"41041f0f\", \"404779a4\", \"5d886e17\", \"325f51eb\", \"d59bc0d1\", \"f2bcc18f\", \"41113564\",\n            \"257b7834\", \"602a9c60\", \"dff8e8a3\", \"1f636c1b\", \"0e12b4c2\", \"02e1329e\", \"af664fd1\", \"cad18115\",\n            \"6b2395e0\", \"333e92e1\", \"3b240b62\", \"eebeb922\", \"85b2a20e\", \"e6ba0d99\", \"de720c8c\", \"2da2f728\",\n            \"d0127845\", \"95b794fd\", \"647d0862\", \"e7ccf5f0\", \"5449a36f\", \"877d48fa\", \"c39dfd27\", \"f33e8d1e\",\n            \"0a476341\", \"992eff74\", \"3a6f6eab\", \"f4f8fd37\", \"a812dc60\", \"a1ebddf8\", \"991be14c\", \"db6e6b0d\",\n            \"c67b5510\", \"6d672c37\", \"2765d43b\", \"dcd0e804\", \"f1290dc7\", \"cc00ffa3\", \"b5390f92\", \"690fed0b\",\n            \"667b9ffb\", \"cedb7d9c\", \"a091cf0b\", \"d9155ea3\", \"bb132f88\", \"515bad24\", \"7b9479bf\", \"763bd6eb\",\n            \"37392eb3\", \"cc115979\", \"8026e297\", \"f42e312d\", \"6842ada7\", \"c66a2b3b\", \"12754ccc\", \"782ef11c\",\n            \"6a124237\", \"b79251e7\", \"06a1bbe6\", \"4bfb6350\", \"1a6b1018\", \"11caedfa\", \"3d25bdd8\", \"e2e1c3c9\",\n            \"44421659\", \"0a121386\", \"d90cec6e\", \"d5abea2a\", \"64af674e\", \"da86a85f\", \"bebfe988\", \"64e4c3fe\",\n            \"9dbc8057\", \"f0f7c086\", \"60787bf8\", \"6003604d\", \"d1fd8346\", \"f6381fb0\", \"7745ae04\", \"d736fccc\",\n            \"83426b33\", \"f01eab71\", \"b0804187\", \"3c005e5f\", \"77a057be\", \"bde8ae24\", \"55464299\", \"bf582e61\",\n            \"4e58f48f\", \"f2ddfda2\", \"f474ef38\", \"8789bdc2\", \"5366f9c3\", \"c8b38e74\", \"b475f255\", \"46fcd9b9\",\n            \"7aeb2661\", \"8b1ddf84\", \"846a0e79\", \"915f95e2\", \"466e598e\", \"20b45770\", \"8cd55591\", \"c902de4c\",\n            \"b90bace1\", \"bb8205d0\", \"11a86248\", \"7574a99e\", \"b77f19b6\", \"e0a9dc09\", \"662d09a1\", \"c4324633\",\n            \"e85a1f02\", \"09f0be8c\", \"4a99a025\", \"1d6efe10\", \"1ab93d1d\", \"0ba5a4df\", \"a186f20f\", \"2868f169\",\n            \"dcb7da83\", \"573906fe\", \"a1e2ce9b\", \"4fcd7f52\", \"50115e01\", \"a70683fa\", \"a002b5c4\", \"0de6d027\",\n            \"9af88c27\", \"773f8641\", \"c3604c06\", \"61a806b5\", \"f0177a28\", \"c0f586e0\", \"006058aa\", \"30dc7d62\",\n            \"11e69ed7\", \"2338ea63\", \"53c2dd94\", \"c2c21634\", \"bbcbee56\", \"90bcb6de\", \"ebfc7da1\", \"ce591d76\",\n            \"6f05e409\", \"4b7c0188\", \"39720a3d\", \"7c927c24\", \"86e3725f\", \"724d9db9\", \"1ac15bb4\", \"d39eb8fc\",\n            \"ed545578\", \"08fca5b5\", \"d83d7cd3\", \"4dad0fc4\", \"1e50ef5e\", \"b161e6f8\", \"a28514d9\", \"6c51133c\",\n            \"6fd5c7e7\", \"56e14ec4\", \"362abfce\", \"ddc6c837\", \"d79a3234\", \"92638212\", \"670efa8e\", \"406000e0\",\n        ],\n        [\n            \"3a39ce37\", \"d3faf5cf\", \"abc27737\", \"5ac52d1b\", \"5cb0679e\", \"4fa33742\", \"d3822740\", \"99bc9bbe\",\n            \"d5118e9d\", \"bf0f7315\", \"d62d1c7e\", \"c700c47b\", \"b78c1b6b\", \"21a19045\", \"b26eb1be\", \"6a366eb4\",\n            \"5748ab2f\", \"bc946e79\", \"c6a376d2\", \"6549c2c8\", \"530ff8ee\", \"468dde7d\", \"d5730a1d\", \"4cd04dc6\",\n            \"2939bbdb\", \"a9ba4650\", \"ac9526e8\", \"be5ee304\", \"a1fad5f0\", \"6a2d519a\", \"63ef8ce2\", \"9a86ee22\",\n            \"c089c2b8\", \"43242ef6\", \"a51e03aa\", \"9cf2d0a4\", \"83c061ba\", \"9be96a4d\", \"8fe51550\", \"ba645bd6\",\n            \"2826a2f9\", \"a73a3ae1\", \"4ba99586\", \"ef5562e9\", \"c72fefd3\", \"f752f7da\", \"3f046f69\", \"77fa0a59\",\n            \"80e4a915\", \"87b08601\", \"9b09e6ad\", \"3b3ee593\", \"e990fd5a\", \"9e34d797\", \"2cf0b7d9\", \"022b8b51\",\n            \"96d5ac3a\", \"017da67d\", \"d1cf3ed6\", \"7c7d2d28\", \"1f9f25cf\", \"adf2b89b\", \"5ad6b472\", \"5a88f54c\",\n            \"e029ac71\", \"e019a5e6\", \"47b0acfd\", \"ed93fa9b\", \"e8d3c48d\", \"283b57cc\", \"f8d56629\", \"79132e28\",\n            \"785f0191\", \"ed756055\", \"f7960e44\", \"e3d35e8c\", \"15056dd4\", \"88f46dba\", \"03a16125\", \"0564f0bd\",\n            \"c3eb9e15\", \"3c9057a2\", \"97271aec\", \"a93a072a\", \"1b3f6d9b\", \"1e6321f5\", \"f59c66fb\", \"26dcf319\",\n            \"7533d928\", \"b155fdf5\", \"03563482\", \"8aba3cbb\", \"28517711\", \"c20ad9f8\", \"abcc5167\", \"ccad925f\",\n            \"4de81751\", \"3830dc8e\", \"379d5862\", \"9320f991\", \"ea7a90c2\", \"fb3e7bce\", \"5121ce64\", \"774fbe32\",\n            \"a8b6e37e\", \"c3293d46\", \"48de5369\", \"6413e680\", \"a2ae0810\", \"dd6db224\", \"69852dfd\", \"09072166\",\n            \"b39a460a\", \"6445c0dd\", \"586cdecf\", \"1c20c8ae\", \"5bbef7dd\", \"1b588d40\", \"ccd2017f\", \"6bb4e3bb\",\n            \"dda26a7e\", \"3a59ff45\", \"3e350a44\", \"bcb4cdd5\", \"72eacea8\", \"fa6484bb\", \"8d6612ae\", \"bf3c6f47\",\n            \"d29be463\", \"542f5d9e\", \"aec2771b\", \"f64e6370\", \"740e0d8d\", \"e75b1357\", \"f8721671\", \"af537d5d\",\n            \"4040cb08\", \"4eb4e2cc\", \"34d2466a\", \"0115af84\", \"e1b00428\", \"95983a1d\", \"06b89fb4\", \"ce6ea048\",\n            \"6f3f3b82\", \"3520ab82\", \"011a1d4b\", \"277227f8\", \"611560b1\", \"e7933fdc\", \"bb3a792b\", \"344525bd\",\n            \"a08839e1\", \"51ce794b\", \"2f32c9b7\", \"a01fbac9\", \"e01cc87e\", \"bcc7d1f6\", \"cf0111c3\", \"a1e8aac7\",\n            \"1a908749\", \"d44fbd9a\", \"d0dadecb\", \"d50ada38\", \"0339c32a\", \"c6913667\", \"8df9317c\", \"e0b12b4f\",\n            \"f79e59b7\", \"43f5bb3a\", \"f2d519ff\", \"27d9459c\", \"bf97222c\", \"15e6fc2a\", \"0f91fc71\", \"9b941525\",\n            \"fae59361\", \"ceb69ceb\", \"c2a86459\", \"12baa8d1\", \"b6c1075e\", \"e3056a0c\", \"10d25065\", \"cb03a442\",\n            \"e0ec6e0e\", \"1698db3b\", \"4c98a0be\", \"3278e964\", \"9f1f9532\", \"e0d392df\", \"d3a0342b\", \"8971f21e\",\n            \"1b0a7441\", \"4ba3348c\", \"c5be7120\", \"c37632d8\", \"df359f8d\", \"9b992f2e\", \"e60b6f47\", \"0fe3f11d\",\n            \"e54cda54\", \"1edad891\", \"ce6279cf\", \"cd3e7e6f\", \"1618b166\", \"fd2c1d05\", \"848fd2c5\", \"f6fb2299\",\n            \"f523f357\", \"a6327623\", \"93a83531\", \"56cccd02\", \"acf08162\", \"5a75ebb5\", \"6e163697\", \"88d273cc\",\n            \"de966292\", \"81b949d0\", \"4c50901b\", \"71c65614\", \"e6c6c7bd\", \"327a140a\", \"45e1d006\", \"c3f27b9a\",\n            \"c9aa53fd\", \"62a80f00\", \"bb25bfe2\", \"35bdd2f6\", \"71126905\", \"b2040222\", \"b6cbcf7c\", \"cd769c2b\",\n            \"53113ec0\", \"1640e3d3\", \"38abbd60\", \"2547adf0\", \"ba38209c\", \"f746ce76\", \"77afa1c5\", \"20756060\",\n            \"85cbfe4e\", \"8ae88dd8\", \"7aaaf9b0\", \"4cf9aa7e\", \"1948c25c\", \"02fb8a8c\", \"01c36ae4\", \"d6ebe1f9\",\n            \"90d4f869\", \"a65cdea0\", \"3f09252d\", \"c208e69f\", \"b74e6132\", \"ce77e25b\", \"578fdfe3\", \"3ac372e6\",\n        ],\n    ];\n\n    // Initialize the P-array sub-keys\n    private readonly string[] p =\n    [\n        \"243f6a88\", \"85a308d3\", \"13198a2e\", \"03707344\", \"a4093822\", \"299f31d0\", \"082efa98\", \"ec4e6c89\", \"452821e6\",\n        \"38d01377\", \"be5466cf\", \"34e90c6c\", \"c0ac29b7\", \"c97c50dd\", \"3f84d5b5\", \"b5470917\", \"9216d5d9\", \"8979fb1b\",\n    ];\n\n    /// <summary>\n    ///     Generate a key for the encryption algorithm based on the given string parameter.\n    /// </summary>\n    /// <param name=\"key\">The key to generate the subkey from.</param>\n    public void GenerateKey(string key)\n    {\n        var j = 0;\n        for (var i = 0; i < p.Length; i++)\n        {\n            // Perform the key expansion\n            var subKey = key.Substring(j % key.Length, 8);\n            p[i] = Xor(p[i], subKey);\n\n            j += 8;\n        }\n    }\n\n    /// <summary>\n    /// Encrypts a string using the blowfish algorithm.\n    /// </summary>\n    /// <param name=\"plainText\">The string to be encrypted, represented as a hexadecimal string.</param>\n    /// <returns>The encrypted string, represented as a hexadecimal string.</returns>\n    public string Encrypt(string plainText)\n    {\n        // Perform the 16 rounds of the blowfish algorithm on the plainText.\n        for (var i = 0; i < 16; i++)\n        {\n            plainText = Round(i, plainText);\n        }\n\n        // Swap the left and right parts of the plainText.\n        var left = plainText.Substring(8, 8);\n        var right = plainText[..8];\n\n        // XOR the left half with the last subkey of the P-array.\n        left = Xor(left, p[17]);\n\n        // XOR the right half with the second to last subkey from the P-array.\n        right = Xor(right, p[16]);\n\n        // Return the encrypted string as a concatenated string.\n        return left + right;\n    }\n\n    /// <summary>\n    /// Decrypts a string using the blowfish algorithm.\n    /// </summary>\n    /// <param name=\"cipherText\">The string to be decrypted, represented as a hexadecimal string.</param>\n    /// <returns>The decrypted string, represented as a hexadecimal string.</returns>\n    public string Decrypt(string cipherText)\n    {\n        // Perform 16 rounds of the blowfish algorithm on the cipherText in reverse order.\n        for (var i = 17; i > 1; i--)\n        {\n            cipherText = Round(i, cipherText);\n        }\n\n        // Swap the left and right halves of the cipherText.\n        var left = cipherText.Substring(8, 8);\n        var right = cipherText.Substring(0, 8);\n\n        // XOR the left half with the first subkey from the P-array.\n        left = Xor(left, p[0]);\n\n        // XOR the right half with the second subkey from the P-array.\n        right = Xor(right, p[1]);\n\n        // Return the decrypted string as a concatenated string.\n        return left + right;\n    }\n\n    /// <summary>\n    ///     Converts a hexadecimal string to a binary string.\n    /// </summary>\n    /// <param name=\"hex\">The hexadecimal string to convert.</param>\n    /// <returns>A multiple of 4 binary string representing the hexadecimal input.</returns>\n    private string HexadecimalToBinary(string hex)\n    {\n        return hex.Select(t =>\n\n                // Convert each character to an integer using base 16\n                Convert.ToString(Convert.ToInt32(t.ToString(), 16), 2))\n\n            // Pad each binary string with leading zeros to make it 4 bits long\n            .Select(fourBitBinary => fourBitBinary.PadLeft(4, '0'))\n\n            // Concatenate all the binary strings into one\n            .Aggregate(string.Empty, (current, fourBitBinary) => current + fourBitBinary);\n    }\n\n    /// <summary>\n    ///     Converts a binary string to a hexadecimal string.\n    /// </summary>\n    /// <param name=\"binaryInput\">The multiple of 4 binary string to convert.</param>\n    /// <returns>A hexadecimal string representing the binary input.</returns>\n    private string BinaryToHexadecimal(string binaryInput)\n    {\n        return string.Concat(\n            Enumerable.Range(0, binaryInput.Length / 4)\n\n                // Select each group of 4 bits\n                .Select(index => binaryInput.Substring(index * 4, 4))\n\n                // Convert each group to an integer using base 2\n                .Select(fourBitBinary => Convert.ToInt32(fourBitBinary, 2)\n\n                    // Convert each integer to a hexadecimal character using base 16\n                    .ToString(\"x\")));\n    }\n\n    /// <summary>\n    ///     Performs a bitwise XOR operation on two hexadecimal strings and returns the result.\n    /// </summary>\n    /// <param name=\"left\">The first hexadecimal string to XOR.</param>\n    /// <param name=\"right\">The second hexadecimal string to XOR.</param>\n    /// <returns>A hexadecimal string representing the XOR of the inputs.</returns>\n    private string Xor(string left, string right)\n    {\n        // Convert the hexadecimal strings to binary strings using a helper method\n        left = HexadecimalToBinary(left);\n        right = HexadecimalToBinary(right);\n\n        var xor = new StringBuilder();\n\n        // Loop through each bit in the binary strings\n        for (var i = 0; i < left.Length; i++)\n        {\n            // Perform a bitwise XOR operation on the corresponding bits and append the result to xor\n            xor.Append((char)(((left[i] - '0') ^ (right[i] - '0')) + '0'));\n        }\n\n        // Convert the binary string to a hexadecimal string\n        var result = BinaryToHexadecimal(xor.ToString());\n        return result;\n    }\n\n    /// <summary>\n    ///     Adds two hexadecimal strings and returns the result modulo _modVal.\n    /// </summary>\n    /// <param name=\"left\">The first hexadecimal string to add.</param>\n    /// <param name=\"right\">The second hexadecimal string to add.</param>\n    /// <returns>A hexadecimal string representing the sum of the inputs modulo _modVal.</returns>\n    private string AddAndMod(string left, string right)\n    {\n        // Convert the hexadecimal strings to unsigned 64-bit integers using base 16\n        var leftNumber = Convert.ToUInt64(left, 16);\n        var rightNumber = Convert.ToUInt64(right, 16);\n\n        // Add the two integers and calculate the remainder after dividing by _modVal\n        var total = (leftNumber + rightNumber) % ModVal;\n\n        // Convert the result to a hexadecimal string using base 16\n        var result = total.ToString(\"x\");\n\n        // Pad the result with leading zeros to make it 8 characters long\n        result = \"00000000\" + result;\n\n        // Return the last 8 characters of the result\n        return result[^8..];\n    }\n\n    /// <summary>\n    ///     Performs the F function on a 32-bit input and returns a 32-bit output.\n    /// </summary>\n    /// <param name=\"plainText\">The 32-bit hexadecimal input to the F function.</param>\n    /// <returns>The 32-bit hexadecimal output of the F function.</returns>\n    /// <remarks>\n    ///     The F function is a non-linear function that operates on a 32-bit input and produces a 32-bit output. It is used\n    ///     to generate the sub-keys and to perform the encryption and decryption of the data blocks.\n    /// </remarks>\n    private string F(string plainText)\n    {\n        var a = new string[4];\n\n        for (var i = 0; i < 8; i += 2)\n        {\n            var col = Convert.ToUInt64(HexadecimalToBinary(plainText.Substring(i, 2)), 2);\n            a[i / 2] = s[i / 2][col];\n        }\n\n        var answer = AddAndMod(a[0], a[1]);\n        answer = Xor(answer, a[2]);\n        answer = AddAndMod(answer, a[3]);\n        return answer;\n    }\n\n    /// <summary>\n    /// Performs one round of the blowfish encryption on a 64-bit block of data.\n    /// </summary>\n    /// <param name=\"feistelRound\">The round number, from 0 to 15, indicating which subkey from the P-array to use.</param>\n    /// <param name=\"plainText\">The 64-bit block of data to be encrypted or decrypted, represented as a hexadecimal string.</param>\n    /// <returns>The encrypted or decrypted block of data, represented as a hexadecimal string.</returns>\n    private string Round(int feistelRound, string plainText)\n    {\n        // Split the plainText into two 32-bit halves.\n        var left = plainText[..8];\n        var right = plainText.Substring(8, 8);\n\n        // XOR the left half with the subkey from the P-array.\n        left = Xor(left, p[feistelRound]);\n\n        // Apply the F function to the left half.\n        var fOutput = F(left);\n\n        // XOR the output of the F function with the right half.\n        right = Xor(fOutput, right);\n\n        // Swap the left and right halves and return them as a concatenated string.\n        return right + left;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Encoders/CaesarEncoder.cs",
    "content": "namespace Algorithms.Encoders;\n\n/// <summary>\n///     Encodes using caesar cypher.\n/// </summary>\npublic class CaesarEncoder : IEncoder<int>\n{\n    /// <summary>\n    ///     Encodes text using specified key,\n    ///     time complexity: O(n),\n    ///     space complexity: O(n),\n    ///     where n - text length.\n    /// </summary>\n    /// <param name=\"text\">Text to be encoded.</param>\n    /// <param name=\"key\">Key that will be used to encode the text.</param>\n    /// <returns>Encoded text.</returns>\n    public string Encode(string text, int key) => Cipher(text, key);\n\n    /// <summary>\n    ///     Decodes text that was encoded using specified key,\n    ///     time complexity: O(n),\n    ///     space complexity: O(n),\n    ///     where n - text length.\n    /// </summary>\n    /// <param name=\"text\">Text to be decoded.</param>\n    /// <param name=\"key\">Key that was used to encode the text.</param>\n    /// <returns>Decoded text.</returns>\n    public string Decode(string text, int key) => Cipher(text, -key);\n\n    private static string Cipher(string text, int key)\n    {\n        var newText = new StringBuilder(text.Length);\n        for (var i = 0; i < text.Length; i++)\n        {\n            if (!char.IsLetter(text[i]))\n            {\n                _ = newText.Append(text[i]);\n                continue;\n            }\n\n            var letterA = char.IsUpper(text[i]) ? 'A' : 'a';\n            var letterZ = char.IsUpper(text[i]) ? 'Z' : 'z';\n\n            var c = text[i] + key;\n            c -= c > letterZ ? 26 * (1 + (c - letterZ - 1) / 26) : 0;\n            c += c < letterA ? 26 * (1 + (letterA - c - 1) / 26) : 0;\n\n            _ = newText.Append((char)c);\n        }\n\n        return newText.ToString();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Encoders/FeistelCipher.cs",
    "content": "namespace Algorithms.Encoders;\n\n/// <summary>\n///     Encodes using Feistel cipher.\n///     https://en.wikipedia.org/wiki/Feistel_cipher\n///     In cryptography, a Feistel cipher (also known as Luby–Rackoff block cipher)\n///     is a symmetric structure used in the construction of block ciphers,\n///     named after the German-born physicist and cryptographer Horst Feistel\n///     who did pioneering research while working for IBM (USA)\n///     A large proportion of block ciphers use the scheme, including the US DES,\n///     the Soviet/Russian GOST and the more recent Blowfish and Twofish ciphers.\n/// </summary>\npublic class FeistelCipher : IEncoder<uint>\n{\n    // number of rounds to transform data block, each round a new \"round\" key is generated.\n    private const int Rounds = 32;\n\n    /// <summary>\n    ///     Encodes text using specified key,\n    ///     where n - text length.\n    /// </summary>\n    /// <param name=\"text\">Text to be encoded.</param>\n    /// <param name=\"key\">Key that will be used to encode the text.</param>\n    /// <exception cref=\"ArgumentException\">Error: key should be more than 0x00001111 for better encoding, key=0 will throw DivideByZero exception.</exception>\n    /// <returns>Encoded text.</returns>\n    public string Encode(string text, uint key)\n    {\n        List<ulong> blocksListPlain = SplitTextToBlocks(text);\n        StringBuilder encodedText = new();\n\n        foreach (ulong block in blocksListPlain)\n        {\n            uint temp = 0;\n\n            // decompose a block to two subblocks 0x0123456789ABCDEF => 0x01234567 & 0x89ABCDEF\n            uint rightSubblock = (uint)(block & 0x00000000FFFFFFFF);\n            uint leftSubblock = (uint)(block >> 32);\n\n            uint roundKey;\n\n            // Feistel \"network\" itself\n            for (int round = 0; round < Rounds; round++)\n            {\n                roundKey = GetRoundKey(key, round);\n                temp = rightSubblock ^ BlockModification(leftSubblock, roundKey);\n                rightSubblock = leftSubblock;\n                leftSubblock = temp;\n            }\n\n            // compile text string formating the block value to text (hex based), length of the output = 16 byte always\n            ulong encodedBlock = leftSubblock;\n            encodedBlock = (encodedBlock << 32) | rightSubblock;\n            encodedText.Append(string.Format(\"{0:X16}\", encodedBlock));\n        }\n\n        return encodedText.ToString();\n    }\n\n    /// <summary>\n    ///     Decodes text that was encoded using specified key.\n    /// </summary>\n    /// <param name=\"text\">Text to be decoded.</param>\n    /// <param name=\"key\">Key that was used to encode the text.</param>\n    /// <exception cref=\"ArgumentException\">Error: key should be more than 0x00001111 for better encoding, key=0 will throw DivideByZero exception.</exception>\n    /// <exception cref=\"ArgumentException\">Error: The length of text should be divisible by 16 as it the block lenght is 16 bytes.</exception>\n    /// <returns>Decoded text.</returns>\n    public string Decode(string text, uint key)\n    {\n        // The plain text will be padded to fill the size of block (16 bytes)\n        if (text.Length % 16 != 0)\n        {\n            throw new ArgumentException($\"The length of {nameof(key)} should be divisible by 16\");\n        }\n\n        List<ulong> blocksListEncoded = GetBlocksFromEncodedText(text);\n        StringBuilder decodedTextHex = new();\n\n        foreach (ulong block in blocksListEncoded)\n        {\n            uint temp = 0;\n\n            // decompose a block to two subblocks 0x0123456789ABCDEF => 0x01234567 & 0x89ABCDEF\n            uint rightSubblock = (uint)(block & 0x00000000FFFFFFFF);\n            uint leftSubblock = (uint)(block >> 32);\n\n            // Feistel \"network\" - decoding, the order of rounds and operations on the blocks is reverted\n            uint roundKey;\n            for (int round = Rounds - 1; round >= 0; round--)\n            {\n                roundKey = GetRoundKey(key, round);\n                temp = leftSubblock ^ BlockModification(rightSubblock, roundKey);\n                leftSubblock = rightSubblock;\n                rightSubblock = temp;\n            }\n\n            // compose decoded block\n            ulong decodedBlock = leftSubblock;\n            decodedBlock = (decodedBlock << 32) | rightSubblock;\n\n            for (int i = 0; i < 8; i++)\n            {\n                ulong a = (decodedBlock & 0xFF00000000000000) >> 56;\n\n                // it's a trick, the code works with non zero characters, if your text has ASCII code 0x00 it will be skipped.\n                if (a != 0)\n                {\n                    decodedTextHex.Append((char)a);\n                }\n\n                decodedBlock = decodedBlock << 8;\n            }\n        }\n\n        return decodedTextHex.ToString();\n    }\n\n    // Using the size of block = 8 bytes this function splts the text and returns set of 8 bytes (ulong) blocks\n    // the last block is extended up to 8 bytes if the tail of the text is smaller than 8 bytes\n    private static List<ulong> SplitTextToBlocks(string text)\n    {\n        List<ulong> blocksListPlain = [];\n        byte[] textArray = Encoding.ASCII.GetBytes(text);\n        int offset = 8;\n        for (int i = 0; i < text.Length; i += 8)\n        {\n            // text not always has len%16 == 0, that's why the offset should be adjusted for the last part of the text\n            if (i > text.Length - 8)\n            {\n                offset = text.Length - i;\n            }\n\n            string block = Convert.ToHexString(textArray, i, offset);\n            blocksListPlain.Add(Convert.ToUInt64(block, 16));\n        }\n\n        return blocksListPlain;\n    }\n\n    // convert the encoded text to the set of ulong values (blocks for decoding)\n    private static List<ulong> GetBlocksFromEncodedText(string text)\n    {\n        List<ulong> blocksListPlain = [];\n        for (int i = 0; i < text.Length; i += 16)\n        {\n            ulong block = Convert.ToUInt64(text.Substring(i, 16), 16);\n            blocksListPlain.Add(block);\n        }\n\n        return blocksListPlain;\n    }\n\n    // here might be any deterministic math formula\n    private static uint BlockModification(uint block, uint key)\n    {\n        for (int i = 0; i < 32; i++)\n        {\n            // 0x55555555 for the better distribution 0 an 1 in the block\n            block = ((block ^ 0x55555555) * block) % key;\n            block = block ^ key;\n        }\n\n        return block;\n    }\n\n    // There are many ways to generate a round key, any deterministic math formula does work\n    private static uint GetRoundKey(uint key, int round)\n    {\n        // \"round + 2\" - to avoid a situation when pow(key,1) ^ key  = key ^ key = 0\n        uint a = (uint)Math.Pow((double)key, round + 2);\n        return a ^ key;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Encoders/HillEncoder.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Encoders;\n\n/// <summary>\n///     Lester S. Hill's polygraphic substitution cipher,\n///     without representing letters using mod26, using\n///     corresponding \"(char)value\" instead.\n/// </summary>\npublic class HillEncoder : IEncoder<double[,]>\n{\n    private readonly GaussJordanElimination linearEquationSolver;\n\n    public HillEncoder() => linearEquationSolver = new GaussJordanElimination(); // TODO: add DI\n\n    public string Encode(string text, double[,] key)\n    {\n        var preparedText = FillGaps(text);\n        var chunked = ChunkTextToArray(preparedText);\n        var splitted = SplitToCharArray(chunked);\n\n        var ciphered = new double[chunked.Length][];\n\n        for (var i = 0; i < chunked.Length; i++)\n        {\n            var vector = new double[3];\n            Array.Copy(splitted, i * 3, vector, 0, 3);\n            var product = MatrixCipher(vector, key);\n            ciphered[i] = product;\n        }\n\n        var merged = MergeArrayList(ciphered);\n\n        return BuildStringFromArray(merged);\n    }\n\n    public string Decode(string text, double[,] key)\n    {\n        var chunked = ChunkTextToArray(text);\n        var split = SplitToCharArray(chunked);\n\n        var deciphered = new double[chunked.Length][];\n\n        for (var i = 0; i < chunked.Length; i++)\n        {\n            var vector = new double[3];\n            Array.Copy(split, i * 3, vector, 0, 3);\n            var product = MatrixDeCipher(vector, key);\n            deciphered[i] = product;\n        }\n\n        var merged = MergeArrayList(deciphered);\n        var str = BuildStringFromArray(merged);\n\n        return UnFillGaps(str);\n    }\n\n    /// <summary>\n    ///     Converts elements from the array to their corresponding Unicode characters.\n    /// </summary>\n    /// <param name=\"arr\">array of vectors.</param>\n    /// <returns>Message.</returns>\n    private static string BuildStringFromArray(double[] arr) => new(arr.Select(c => (char)c).ToArray());\n\n    /// <summary>\n    ///     Multiplies the key for the given scalar.\n    /// </summary>\n    /// <param name=\"vector\">list of splitted words as numbers.</param>\n    /// <param name=\"key\">Cipher selected key.</param>\n    /// <returns>Ciphered vector.</returns>\n    private static double[] MatrixCipher(double[] vector, double[,] key)\n    {\n        var multiplied = new double[vector.Length];\n\n        for (var i = 0; i < key.GetLength(1); i++)\n        {\n            for (var j = 0; j < key.GetLength(0); j++)\n            {\n                multiplied[i] += key[i, j] * vector[j];\n            }\n        }\n\n        return multiplied;\n    }\n\n    /// <summary>\n    ///     Given a list of vectors, returns a single array of elements.\n    /// </summary>\n    /// <param name=\"list\">List of ciphered arrays.</param>\n    /// <returns>unidimensional list.</returns>\n    private static double[] MergeArrayList(double[][] list)\n    {\n        var merged = new double[list.Length * 3];\n\n        for (var i = 0; i < list.Length; i++)\n        {\n            Array.Copy(list[i], 0, merged, i * 3, list[0].Length);\n        }\n\n        return merged;\n    }\n\n    /// <summary>\n    ///     Splits the input text message as chunks of words.\n    /// </summary>\n    /// <param name=\"chunked\">chunked words list.</param>\n    /// <returns>spliiter char array.</returns>\n    private static char[] SplitToCharArray(string[] chunked)\n    {\n        var splitted = new char[chunked.Length * 3];\n\n        for (var i = 0; i < chunked.Length; i++)\n        {\n            for (var j = 0; j < 3; j++)\n            {\n                splitted[i * 3 + j] = chunked[i].ToCharArray()[j];\n            }\n        }\n\n        return splitted;\n    }\n\n    /// <summary>\n    ///     Chunks the input text message.\n    /// </summary>\n    /// <param name=\"text\">text message.</param>\n    /// <returns>array of words.</returns>\n    private static string[] ChunkTextToArray(string text)\n    {\n        // To split the message into chunks\n        var div = text.Length / 3;\n        var chunks = new string[div];\n\n        for (var i = 0; i < div; i++)\n        {\n            chunks.SetValue(text.Substring(i * 3, 3), i);\n        }\n\n        return chunks;\n    }\n\n    /// <summary>\n    ///     Fills a text message with spaces at the end\n    ///     to enable a simple split by 3-length-word.\n    /// </summary>\n    /// <param name=\"text\">Text Message.</param>\n    /// <returns>Modified text Message.</returns>\n    private static string FillGaps(string text)\n    {\n        var remainder = text.Length % 3;\n        return remainder == 0 ? text : text + new string(' ', 3 - remainder);\n    }\n\n    /// <summary>\n    ///     Removes the extra spaces included on the cipher phase.\n    /// </summary>\n    /// <param name=\"text\">Text message.</param>\n    /// <returns>Deciphered Message.</returns>\n    private static string UnFillGaps(string text) => text.TrimEnd();\n\n    /// <summary>\n    ///     Finds the inverse of the given matrix using a linear equation solver.\n    /// </summary>\n    /// <param name=\"vector\">Splitted words vector.</param>\n    /// <param name=\"key\">Key used for the cipher.</param>\n    /// <returns>TODO.</returns>\n    private double[] MatrixDeCipher(double[] vector, double[,] key)\n    {\n        // To augment the original key with the given vector.\n        var augM = new double[3, 4];\n\n        for (var i = 0; i < key.GetLength(0); i++)\n        {\n            for (var j = 0; j < key.GetLength(1); j++)\n            {\n                augM[i, j] = key[i, j];\n            }\n        }\n\n        for (var k = 0; k < vector.Length; k++)\n        {\n            augM[k, 3] = vector[k];\n        }\n\n        _ = linearEquationSolver.Solve(augM);\n\n        return [augM[0, 3], augM[1, 3], augM[2, 3]];\n    }\n}\n"
  },
  {
    "path": "Algorithms/Encoders/IEncoder.cs",
    "content": "namespace Algorithms.Encoders;\n\n/// <summary>\n///     Encodes and decodes text based on specified key.\n/// </summary>\n/// <typeparam name=\"TKey\">Type of the key.</typeparam>\npublic interface IEncoder<TKey>\n{\n    /// <summary>\n    ///     Encodes text using specified key.\n    /// </summary>\n    /// <param name=\"text\">Text to be encoded.</param>\n    /// <param name=\"key\">Key that will be used to encode the text.</param>\n    /// <returns>Encoded text.</returns>\n    string Encode(string text, TKey key);\n\n    /// <summary>\n    ///     Decodes text that was encoded using specified key.\n    /// </summary>\n    /// <param name=\"text\">Text to be decoded.</param>\n    /// <param name=\"key\">Key that was used to encode the text.</param>\n    /// <returns>Decoded text.</returns>\n    string Decode(string text, TKey key);\n}\n"
  },
  {
    "path": "Algorithms/Encoders/NysiisEncoder.cs",
    "content": "namespace Algorithms.Encoders;\n\n/// <summary>\n///     Class for NYSIIS encoding strings.\n/// </summary>\npublic class NysiisEncoder\n{\n    private static readonly char[] Vowels = ['A', 'E', 'I', 'O', 'U'];\n\n    /// <summary>\n    ///     Encodes a string using the NYSIIS Algorithm.\n    /// </summary>\n    /// <param name=\"text\">The string to encode.</param>\n    /// <returns>The NYSIIS encoded string (all uppercase).</returns>\n    public string Encode(string text)\n    {\n        text = text.ToUpper(CultureInfo.CurrentCulture);\n        text = TrimSpaces(text);\n        text = StartReplace(text);\n        text = EndReplace(text);\n\n        for (var i = 1; i < text.Length; i++)\n        {\n            text = ReplaceStep(text, i);\n        }\n\n        text = RemoveDuplicates(text);\n        return TrimEnd(text);\n    }\n\n    private string TrimSpaces(string text) => text.Replace(\" \", string.Empty);\n\n    private string RemoveDuplicates(string text)\n    {\n        var sb = new StringBuilder();\n        sb.Append(text[0]);\n        foreach (var c in text)\n        {\n            if (sb[^1] != c)\n            {\n                sb.Append(c);\n            }\n        }\n\n        return sb.ToString();\n    }\n\n    private string TrimEnd(string text)\n    {\n        var checks = new (string From, string To)?[]\n        {\n            (\"S\", string.Empty),\n            (\"AY\", \"Y\"),\n            (\"A\", string.Empty),\n        };\n        var replacement = checks.FirstOrDefault(t => text.EndsWith(t!.Value.From));\n        if (replacement is { })\n        {\n            var (from, to) = replacement!.Value;\n            text = Replace(text, text.Length - from.Length, from.Length, to);\n        }\n\n        return text;\n    }\n\n    private string ReplaceStep(string text, int i)\n    {\n        (string From, string To)[] replacements =\n        [\n            (\"EV\", \"AF\"),\n            (\"E\", \"A\"),\n            (\"I\", \"A\"),\n            (\"O\", \"A\"),\n            (\"U\", \"A\"),\n            (\"Q\", \"G\"),\n            (\"Z\", \"S\"),\n            (\"M\", \"N\"),\n            (\"KN\", \"NN\"),\n            (\"K\", \"C\"),\n            (\"SCH\", \"SSS\"),\n            (\"PH\", \"FF\"),\n        ];\n        var replaced = TryReplace(text, i, replacements, out text);\n        if (replaced)\n        {\n            return text;\n        }\n\n        // H[vowel] or [vowel]H -> text[i-1]\n        if (text[i] == 'H')\n        {\n            if (!Vowels.Contains(text[i - 1]))\n            {\n                return ReplaceWithPrevious();\n            }\n\n            if (i < text.Length - 1 && !Vowels.Contains(text[i + 1]))\n            {\n                return ReplaceWithPrevious();\n            }\n        }\n\n        // [vowel]W -> [vowel]\n        if (text[i] == 'W' && Vowels.Contains(text[i - 1]))\n        {\n            return ReplaceWithPrevious();\n        }\n\n        return text;\n\n        string ReplaceWithPrevious() => Replace(text, i, 1, text[i - 1].ToString());\n    }\n\n    private bool TryReplace(string text, int index, (string, string)[] opts, out string result)\n    {\n        for (var i = 0; i < opts.Length; i++)\n        {\n            var check = opts[i].Item1;\n            var repl = opts[i].Item2;\n            if (text.Length >= index + check.Length && text.Substring(index, check.Length) == check)\n            {\n                result = Replace(text, index, check.Length, repl);\n                return true;\n            }\n        }\n\n        result = text;\n        return false;\n    }\n\n    private string StartReplace(string start)\n    {\n        var checks = new (string From, string To)?[]\n        {\n            (\"MAC\", \"MCC\"),\n            (\"KN\", \"NN\"),\n            (\"K\", \"C\"),\n            (\"PH\", \"FF\"),\n            (\"PF\", \"FF\"),\n            (\"SCH\", \"SSS\"),\n        };\n        var replacement = checks.FirstOrDefault(t => start.StartsWith(t!.Value.From));\n        if (replacement is { })\n        {\n            var (from, to) = replacement!.Value;\n            start = Replace(start, 0, from.Length, to);\n        }\n\n        return start;\n    }\n\n    private string EndReplace(string end)\n    {\n        var checks = new (string From, string To)?[]\n        {\n            (\"EE\", \"Y\"),\n            (\"IE\", \"Y\"),\n            (\"DT\", \"D\"),\n            (\"RT\", \"D\"),\n            (\"NT\", \"D\"),\n            (\"ND\", \"D\"),\n        };\n        var replacement = checks.FirstOrDefault(t => end.EndsWith(t!.Value.From));\n        if (replacement is { })\n        {\n            var (from, to) = replacement!.Value;\n            end = Replace(end, end.Length - from.Length, from.Length, to);\n        }\n\n        return end;\n    }\n\n    private string Replace(string text, int index, int length, string substitute) =>\n        text[..index] + substitute + text[(index + length)..];\n}\n"
  },
  {
    "path": "Algorithms/Encoders/SoundexEncoder.cs",
    "content": "namespace Algorithms.Encoders;\n\n/// <summary>\n///     Class for Soundex encoding strings.\n/// </summary>\npublic class SoundexEncoder\n{\n    private static readonly Dictionary<char, int> CharacterMapping = new()\n    {\n        ['a'] = 0,\n        ['e'] = 0,\n        ['i'] = 0,\n        ['o'] = 0,\n        ['u'] = 0,\n        ['y'] = 0,\n        ['h'] = 8,\n        ['w'] = 8,\n        ['b'] = 1,\n        ['f'] = 1,\n        ['p'] = 1,\n        ['v'] = 1,\n        ['c'] = 2,\n        ['g'] = 2,\n        ['j'] = 2,\n        ['k'] = 2,\n        ['q'] = 2,\n        ['s'] = 2,\n        ['x'] = 2,\n        ['z'] = 2,\n        ['d'] = 3,\n        ['t'] = 3,\n        ['l'] = 4,\n        ['m'] = 5,\n        ['n'] = 5,\n        ['r'] = 6,\n    };\n\n    /// <summary>\n    ///     Encodes a string using the Soundex Algorithm.\n    /// </summary>\n    /// <param name=\"text\">The string to encode.</param>\n    /// <returns>The Soundex encoded string (one uppercase character and three digits).</returns>\n    public string Encode(string text)\n    {\n        text = text.ToLowerInvariant();\n        var chars = OmitHAndW(text);\n        IEnumerable<int> numbers = ProduceNumberCoding(chars);\n        numbers = CollapseDoubles(numbers);\n        numbers = OmitVowels(numbers);\n        numbers = CollapseLeadingDigit(numbers, text[0]);\n        numbers = numbers.Take(3);\n        numbers = PadTo3Numbers(numbers);\n        var final = numbers.ToArray();\n        return $\"{text.ToUpperInvariant()[0]}{final[0]}{final[1]}{final[2]}\";\n    }\n\n    private IEnumerable<int> CollapseLeadingDigit(IEnumerable<int> numbers, char c)\n    {\n        using var enumerator = numbers.GetEnumerator();\n        enumerator.MoveNext();\n        if (enumerator.Current == MapToNumber(c))\n        {\n            enumerator.MoveNext();\n        }\n\n        do\n        {\n            yield return enumerator.Current;\n        }\n        while (enumerator.MoveNext());\n    }\n\n    private IEnumerable<int> PadTo3Numbers(IEnumerable<int> numbers)\n    {\n        using var enumerator = numbers.GetEnumerator();\n        for (var i = 0; i < 3; i++)\n        {\n            yield return enumerator.MoveNext()\n                ? enumerator.Current\n                : 0;\n        }\n    }\n\n    private IEnumerable<int> OmitVowels(IEnumerable<int> numbers) => numbers.Where(i => i != 0);\n\n    private IEnumerable<char> OmitHAndW(string text) => text.Where(c => c != 'h' && c != 'w');\n\n    private IEnumerable<int> CollapseDoubles(IEnumerable<int> numbers)\n    {\n        var previous = int.MinValue;\n        foreach (var i in numbers)\n        {\n            if (previous != i)\n            {\n                yield return i;\n                previous = i;\n            }\n        }\n    }\n\n    private IEnumerable<int> ProduceNumberCoding(IEnumerable<char> text) => text.Select(MapToNumber);\n\n    private int MapToNumber(char ch)\n    {\n        return CharacterMapping[ch];\n    }\n}\n"
  },
  {
    "path": "Algorithms/Encoders/VigenereEncoder.cs",
    "content": "namespace Algorithms.Encoders;\n\n/// <summary>\n///     Encodes using vigenere cypher.\n/// </summary>\npublic class VigenereEncoder : IEncoder<string>\n{\n    private readonly CaesarEncoder caesarEncoder = new();\n\n    /// <summary>\n    ///     Encodes text using specified key,\n    ///     time complexity: O(n),\n    ///     space complexity: O(n),\n    ///     where n - text length.\n    /// </summary>\n    /// <param name=\"text\">Text to be encoded.</param>\n    /// <param name=\"key\">Key that will be used to encode the text.</param>\n    /// <returns>Encoded text.</returns>\n    public string Encode(string text, string key) => Cipher(text, key, caesarEncoder.Encode);\n\n    /// <summary>\n    ///     Decodes text that was encoded using specified key,\n    ///     time complexity: O(n),\n    ///     space complexity: O(n),\n    ///     where n - text length.\n    /// </summary>\n    /// <param name=\"text\">Text to be decoded.</param>\n    /// <param name=\"key\">Key that was used to encode the text.</param>\n    /// <returns>Decoded text.</returns>\n    public string Decode(string text, string key) => Cipher(text, key, caesarEncoder.Decode);\n\n    private string Cipher(string text, string key, Func<string, int, string> symbolCipher)\n    {\n        key = AppendKey(key, text.Length);\n        var encodedTextBuilder = new StringBuilder(text.Length);\n        for (var i = 0; i < text.Length; i++)\n        {\n            if (!char.IsLetter(text[i]))\n            {\n                _ = encodedTextBuilder.Append(text[i]);\n                continue;\n            }\n\n            var letterZ = char.IsUpper(key[i]) ? 'Z' : 'z';\n            var encodedSymbol = symbolCipher(text[i].ToString(), letterZ - key[i]);\n            _ = encodedTextBuilder.Append(encodedSymbol);\n        }\n\n        return encodedTextBuilder.ToString();\n    }\n\n    private string AppendKey(string key, int length)\n    {\n        if (string.IsNullOrEmpty(key))\n        {\n            throw new ArgumentOutOfRangeException($\"{nameof(key)} must be non-empty string\");\n        }\n\n        var keyBuilder = new StringBuilder(key, length);\n        while (keyBuilder.Length < length)\n        {\n            _ = keyBuilder.Append(key);\n        }\n\n        return keyBuilder.ToString();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Financial/PresentValue.cs",
    "content": "namespace Algorithms.Financial;\n\n/// <summary>\n/// PresentValue is the value of an expected income stream determined as of the date of valuation.\n/// </summary>\npublic static class PresentValue\n{\n    public static double Calculate(double discountRate, List<double> cashFlows)\n    {\n        if (discountRate < 0)\n        {\n            throw new ArgumentException(\"Discount rate cannot be negative\");\n        }\n\n        if (cashFlows.Count == 0)\n        {\n            throw new ArgumentException(\"Cash flows list cannot be empty\");\n        }\n\n        double presentValue = cashFlows.Select((t, i) => t / Math.Pow(1 + discountRate, i)).Sum();\n\n        return Math.Round(presentValue, 2);\n    }\n}\n"
  },
  {
    "path": "Algorithms/GlobalUsings.cs",
    "content": "// -----------------------------------------------------------------------------\n// Global using directives for the C-Sharp solution.\n// These namespaces are imported globally so they don’t need to be repeatedly declared\n// in individual files, improving readability and reducing boilerplate.\n//\n// Guidelines:\n// - Keep only the most commonly used namespaces here.\n// - Add project-specific namespaces (e.g., Utilities.Extensions) only if they are\n//   required across the majority of files in the project.\n// - Avoid placing rarely used namespaces here to maintain clarity.\n// -----------------------------------------------------------------------------\n\nglobal using System;                        // Core base classes and fundamental types\nglobal using System.Collections.Generic;    // Generic collection types (List, Dictionary, etc.)\nglobal using System.Globalization;          // Culture-related information (dates, numbers, formatting)\nglobal using System.Linq;                   // LINQ query operators for collections\nglobal using System.Numerics;               // Numeric types such as BigInteger and Complex\nglobal using System.Security.Cryptography;  // Cryptographic services (hashing, encryption, random numbers)\nglobal using System.Text;                   // Text encoding, StringBuilder, etc.\nglobal using System.Text.RegularExpressions; // Regular expression support\nglobal using Utilities.Extensions;          // Common extension methods used across the solution\n"
  },
  {
    "path": "Algorithms/Graph/ArticulationPoints.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Algorithms.Graph;\n\n/// <summary>\n/// Finds articulation points (cut vertices) in an undirected graph.\n/// An articulation point is a vertex whose removal increases the number of connected components.\n/// </summary>\npublic static class ArticulationPoints\n{\n    /// <summary>\n    /// Finds all articulation points in an undirected graph.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of vertex.</typeparam>\n    /// <param name=\"vertices\">All vertices in the graph.</param>\n    /// <param name=\"getNeighbors\">Function to get neighbors of a vertex.</param>\n    /// <returns>Set of articulation points.</returns>\n    public static HashSet<T> Find<T>(\n        IEnumerable<T> vertices,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        if (vertices == null)\n        {\n            throw new ArgumentNullException(nameof(vertices));\n        }\n\n        if (getNeighbors == null)\n        {\n            throw new ArgumentNullException(nameof(getNeighbors));\n        }\n\n        var vertexList = vertices.ToList();\n        if (vertexList.Count == 0)\n        {\n            return new HashSet<T>();\n        }\n\n        var articulationPoints = new HashSet<T>();\n        var visited = new HashSet<T>();\n        var discoveryTime = new Dictionary<T, int>();\n        var low = new Dictionary<T, int>();\n        var parent = new Dictionary<T, T?>();\n        var time = 0;\n\n        foreach (var vertex in vertexList)\n        {\n            if (!visited.Contains(vertex))\n            {\n                var state = new DfsState<T>\n                {\n                    Visited = visited,\n                    DiscoveryTime = discoveryTime,\n                    Low = low,\n                    Parent = parent,\n                    ArticulationPoints = articulationPoints,\n                };\n                Dfs(vertex, ref time, state, getNeighbors);\n            }\n        }\n\n        return articulationPoints;\n    }\n\n    /// <summary>\n    /// Checks if a vertex is an articulation point.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of vertex.</typeparam>\n    /// <param name=\"vertex\">Vertex to check.</param>\n    /// <param name=\"vertices\">All vertices in the graph.</param>\n    /// <param name=\"getNeighbors\">Function to get neighbors of a vertex.</param>\n    /// <returns>True if vertex is an articulation point.</returns>\n    public static bool IsArticulationPoint<T>(\n        T vertex,\n        IEnumerable<T> vertices,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        var articulationPoints = Find(vertices, getNeighbors);\n        return articulationPoints.Contains(vertex);\n    }\n\n    /// <summary>\n    /// Counts the number of articulation points in the graph.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of vertex.</typeparam>\n    /// <param name=\"vertices\">All vertices in the graph.</param>\n    /// <param name=\"getNeighbors\">Function to get neighbors of a vertex.</param>\n    /// <returns>Number of articulation points.</returns>\n    public static int Count<T>(\n        IEnumerable<T> vertices,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        return Find(vertices, getNeighbors).Count;\n    }\n\n    private static void Dfs<T>(\n        T u,\n        ref int time,\n        DfsState<T> state,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        state.Visited.Add(u);\n        state.DiscoveryTime[u] = time;\n        state.Low[u] = time;\n        time++;\n\n        int children = 0;\n\n        foreach (var v in getNeighbors(u))\n        {\n            if (!state.Visited.Contains(v))\n            {\n                children++;\n                state.Parent[v] = u;\n                Dfs(v, ref time, state, getNeighbors);\n\n                state.Low[u] = Math.Min(state.Low[u], state.Low[v]);\n\n                // Check if u is an articulation point\n                bool isRoot = !state.Parent.ContainsKey(u);\n                if (isRoot && children > 1)\n                {\n                    state.ArticulationPoints.Add(u);\n                }\n\n                bool isNonRootArticulation = state.Parent.ContainsKey(u) && state.Low[v] >= state.DiscoveryTime[u];\n                if (isNonRootArticulation)\n                {\n                    state.ArticulationPoints.Add(u);\n                }\n            }\n            else if (!EqualityComparer<T>.Default.Equals(v, state.Parent.GetValueOrDefault(u)))\n            {\n                // Back edge: update low value\n                state.Low[u] = Math.Min(state.Low[u], state.DiscoveryTime[v]);\n            }\n            else\n            {\n                // Edge to parent: no action needed\n            }\n        }\n    }\n\n    /// <summary>\n    /// Encapsulates the state for DFS traversal in articulation point detection.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of vertex.</typeparam>\n    private sealed class DfsState<T>\n        where T : notnull\n    {\n        /// <summary>\n        /// Gets set of visited vertices.\n        /// </summary>\n        public required HashSet<T> Visited { get; init; }\n\n        /// <summary>\n        /// Gets discovery time for each vertex.\n        /// </summary>\n        public required Dictionary<T, int> DiscoveryTime { get; init; }\n\n        /// <summary>\n        /// Gets lowest discovery time reachable from each vertex.\n        /// </summary>\n        public required Dictionary<T, int> Low { get; init; }\n\n        /// <summary>\n        /// Gets parent vertex in DFS tree.\n        /// </summary>\n        public required Dictionary<T, T?> Parent { get; init; }\n\n        /// <summary>\n        /// Gets set of detected articulation points.\n        /// </summary>\n        public required HashSet<T> ArticulationPoints { get; init; }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/BellmanFord.cs",
    "content": "using DataStructures.Graph;\n\nnamespace Algorithms.Graph;\n\n/// <summary>\n/// Bellman-Ford algorithm on directed weighted graph.\n/// </summary>\n/// <typeparam name=\"T\">Generic type of data in the graph.</typeparam>\npublic class BellmanFord<T>(DirectedWeightedGraph<T> graph, Dictionary<Vertex<T>, double> distances, Dictionary<Vertex<T>, Vertex<T>?> predecessors)\n{\n    private readonly DirectedWeightedGraph<T> graph = graph;\n    private readonly Dictionary<Vertex<T>, double> distances = distances;\n    private readonly Dictionary<Vertex<T>, Vertex<T>?> predecessors = predecessors;\n\n    /// <summary>\n    /// Runs the Bellman-Ford algorithm to find the shortest distances from the source vertex to all other vertices.\n    /// </summary>\n    /// <param name=\"sourceVertex\">Source vertex for shortest path calculation.</param>\n    /// <returns>\n    /// A dictionary containing the shortest distances from the source vertex to all other vertices.\n    /// If a vertex is unreachable from the source, it will have a value of double.PositiveInfinity.\n    /// </returns>\n    public Dictionary<Vertex<T>, double> Run(Vertex<T> sourceVertex)\n    {\n        InitializeDistances(sourceVertex);\n        RelaxEdges();\n        CheckForNegativeCycles();\n        return distances;\n    }\n\n    private void InitializeDistances(Vertex<T> sourceVertex)\n    {\n        foreach (var vertex in graph.Vertices)\n        {\n            if (vertex != null)\n            {\n                distances[vertex] = double.PositiveInfinity;\n                predecessors[vertex] = null;\n            }\n        }\n\n        distances[sourceVertex] = 0;\n    }\n\n    private void RelaxEdges()\n    {\n        int vertexCount = graph.Count;\n\n        for (int i = 0; i < vertexCount - 1; i++)\n        {\n            foreach (var vertex in graph.Vertices)\n            {\n                if (vertex != null)\n                {\n                    RelaxEdgesForVertex(vertex);\n                }\n            }\n        }\n    }\n\n    private void RelaxEdgesForVertex(Vertex<T> u)\n    {\n        foreach (var neighbor in graph.GetNeighbors(u))\n        {\n            if (neighbor == null)\n            {\n                continue;\n            }\n\n            var v = neighbor;\n            var weight = graph.AdjacentDistance(u, v);\n\n            if (distances[u] + weight < distances[v])\n            {\n                distances[v] = distances[u] + weight;\n                predecessors[v] = u;\n            }\n        }\n    }\n\n    private void CheckForNegativeCycles()\n    {\n        foreach (var vertex in graph.Vertices)\n        {\n            if (vertex != null)\n            {\n                CheckForNegativeCyclesForVertex(vertex);\n            }\n        }\n    }\n\n    private void CheckForNegativeCyclesForVertex(Vertex<T> u)\n    {\n        foreach (var neighbor in graph.GetNeighbors(u))\n        {\n            if (neighbor == null)\n            {\n                continue;\n            }\n\n            var v = neighbor;\n            var weight = graph.AdjacentDistance(u, v);\n\n            if (distances[u] + weight < distances[v])\n            {\n                throw new InvalidOperationException(\"Graph contains a negative weight cycle.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/BipartiteGraph.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Algorithms.Graph;\n\n/// <summary>\n/// Checks if a graph is bipartite (2-colorable).\n/// A bipartite graph can be divided into two independent sets where no two vertices\n/// within the same set are adjacent.\n/// </summary>\npublic static class BipartiteGraph\n{\n    /// <summary>\n    /// Checks if a graph is bipartite using BFS-based coloring.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of vertex.</typeparam>\n    /// <param name=\"vertices\">All vertices in the graph.</param>\n    /// <param name=\"getNeighbors\">Function to get neighbors of a vertex.</param>\n    /// <returns>True if graph is bipartite, false otherwise.</returns>\n    public static bool IsBipartite<T>(\n        IEnumerable<T> vertices,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        if (vertices == null)\n        {\n            throw new ArgumentNullException(nameof(vertices));\n        }\n\n        if (getNeighbors == null)\n        {\n            throw new ArgumentNullException(nameof(getNeighbors));\n        }\n\n        var vertexList = vertices.ToList();\n        if (vertexList.Count == 0)\n        {\n            return true; // Empty graph is bipartite\n        }\n\n        var colors = new Dictionary<T, int>();\n\n        // Check each connected component\n        foreach (var start in vertexList)\n        {\n            if (colors.ContainsKey(start))\n            {\n                continue; // Already colored\n            }\n\n            if (!BfsColor(start, colors, getNeighbors))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    /// Gets the two partitions of a bipartite graph.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of vertex.</typeparam>\n    /// <param name=\"vertices\">All vertices in the graph.</param>\n    /// <param name=\"getNeighbors\">Function to get neighbors of a vertex.</param>\n    /// <returns>Tuple of two sets representing the partitions, or null if not bipartite.</returns>\n    public static (HashSet<T> SetA, HashSet<T> SetB)? GetPartitions<T>(\n        IEnumerable<T> vertices,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        if (vertices == null)\n        {\n            throw new ArgumentNullException(nameof(vertices));\n        }\n\n        if (getNeighbors == null)\n        {\n            throw new ArgumentNullException(nameof(getNeighbors));\n        }\n\n        var vertexList = vertices.ToList();\n        if (vertexList.Count == 0)\n        {\n            return (new HashSet<T>(), new HashSet<T>());\n        }\n\n        var colors = new Dictionary<T, int>();\n\n        // Color all components\n        foreach (var start in vertexList)\n        {\n            if (colors.ContainsKey(start))\n            {\n                continue;\n            }\n\n            if (!BfsColor(start, colors, getNeighbors))\n            {\n                return null; // Not bipartite\n            }\n        }\n\n        // Split into two sets based on color\n        var setA = new HashSet<T>();\n        var setB = new HashSet<T>();\n\n        foreach (var vertex in vertexList)\n        {\n            if (colors[vertex] == 0)\n            {\n                setA.Add(vertex);\n            }\n            else\n            {\n                setB.Add(vertex);\n            }\n        }\n\n        return (setA, setB);\n    }\n\n    /// <summary>\n    /// Checks if a graph is bipartite using DFS-based coloring.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of vertex.</typeparam>\n    /// <param name=\"vertices\">All vertices in the graph.</param>\n    /// <param name=\"getNeighbors\">Function to get neighbors of a vertex.</param>\n    /// <returns>True if graph is bipartite, false otherwise.</returns>\n    public static bool IsBipartiteDfs<T>(\n        IEnumerable<T> vertices,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        if (vertices == null)\n        {\n            throw new ArgumentNullException(nameof(vertices));\n        }\n\n        if (getNeighbors == null)\n        {\n            throw new ArgumentNullException(nameof(getNeighbors));\n        }\n\n        var vertexList = vertices.ToList();\n        if (vertexList.Count == 0)\n        {\n            return true;\n        }\n\n        var colors = new Dictionary<T, int>();\n\n        foreach (var start in vertexList)\n        {\n            if (colors.ContainsKey(start))\n            {\n                continue;\n            }\n\n            if (!DfsColor(start, 0, colors, getNeighbors))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    private static bool BfsColor<T>(\n        T start,\n        Dictionary<T, int> colors,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        var queue = new Queue<T>();\n        queue.Enqueue(start);\n        colors[start] = 0;\n\n        while (queue.Count > 0)\n        {\n            var current = queue.Dequeue();\n            var currentColor = colors[current];\n            var nextColor = 1 - currentColor;\n\n            foreach (var neighbor in getNeighbors(current))\n            {\n                if (!colors.ContainsKey(neighbor))\n                {\n                    colors[neighbor] = nextColor;\n                    queue.Enqueue(neighbor);\n                }\n                else if (colors[neighbor] == currentColor)\n                {\n                    return false; // Same color as current - not bipartite\n                }\n                else\n                {\n                    // Different color - valid\n                }\n            }\n        }\n\n        return true;\n    }\n\n    private static bool DfsColor<T>(\n        T vertex,\n        int color,\n        Dictionary<T, int> colors,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        colors[vertex] = color;\n        var nextColor = 1 - color;\n\n        foreach (var neighbor in getNeighbors(vertex))\n        {\n            if (!colors.ContainsKey(neighbor))\n            {\n                if (!DfsColor(neighbor, nextColor, colors, getNeighbors))\n                {\n                    return false;\n                }\n            }\n            else if (colors[neighbor] == color)\n            {\n                return false; // Same color - not bipartite\n            }\n            else\n            {\n                // Different color - valid\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/BreadthFirstSearch.cs",
    "content": "using DataStructures.Graph;\n\nnamespace Algorithms.Graph;\n\n/// <summary>\n/// Breadth First Search - algorithm for traversing graph.\n/// Algorithm starts from root node that is selected by the user.\n/// Algorithm explores all nodes at the present depth.\n/// </summary>\n/// <typeparam name=\"T\">Vertex data type.</typeparam>\npublic class BreadthFirstSearch<T> : IGraphSearch<T> where T : IComparable<T>\n{\n    /// <summary>\n    /// Traverses graph from start vertex.\n    /// </summary>\n    /// <param name=\"graph\">Graph instance.</param>\n    /// <param name=\"startVertex\">Vertex that search starts from.</param>\n    /// <param name=\"action\">Action that needs to be executed on each graph vertex.</param>\n    public void VisitAll(IDirectedWeightedGraph<T> graph, Vertex<T> startVertex, Action<Vertex<T>>? action = default)\n    {\n        Bfs(graph, startVertex, action, []);\n    }\n\n    /// <summary>\n    /// Traverses graph from start vertex.\n    /// </summary>\n    /// <param name=\"graph\">Graph instance.</param>\n    /// <param name=\"startVertex\">Vertex that search starts from.</param>\n    /// <param name=\"action\">Action that needs to be executed on each graph vertex.</param>\n    /// <param name=\"visited\">Hash set with visited vertices.</param>\n    private void Bfs(IDirectedWeightedGraph<T> graph, Vertex<T> startVertex, Action<Vertex<T>>? action, HashSet<Vertex<T>> visited)\n    {\n        var queue = new Queue<Vertex<T>>();\n\n        queue.Enqueue(startVertex);\n\n        while (queue.Count > 0)\n        {\n            var currentVertex = queue.Dequeue();\n\n            if (currentVertex == null || visited.Contains(currentVertex))\n            {\n                continue;\n            }\n\n            foreach (var vertex in graph.GetNeighbors(currentVertex))\n            {\n                queue.Enqueue(vertex!);\n            }\n\n            action?.Invoke(currentVertex);\n\n            visited.Add(currentVertex);\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/BreadthFirstTreeTraversal.cs",
    "content": "using DataStructures.BinarySearchTree;\n\nnamespace Algorithms.Graph;\n\n/// <summary>\n///     Breadth first tree traversal traverses through a binary tree\n///     by iterating through each level first.\n///     time complexity: O(n).\n///     space complexity: O(w) where w is the max width of a binary tree.\n/// </summary>\n/// <typeparam name=\"TKey\">Type of key held in binary search tree.</typeparam>\npublic static class BreadthFirstTreeTraversal<TKey>\n{\n    /// <summary>\n    ///     Level Order Traversal returns an array of integers in order\n    ///     of each level of a binary tree. It uses a queue to iterate\n    ///     through each node following breadth first search traversal.\n    /// </summary>\n    /// <param name=\"tree\">Passes the binary tree to traverse.</param>\n    /// <returns>Returns level order traversal.</returns>\n    public static TKey[] LevelOrderTraversal(BinarySearchTree<TKey> tree)\n    {\n        BinarySearchTreeNode<TKey>? root = tree.Root;\n        TKey[] levelOrder = new TKey[tree.Count];\n        if (root is null)\n        {\n            return Array.Empty<TKey>();\n        }\n\n        Queue<BinarySearchTreeNode<TKey>> breadthTraversal = new Queue<BinarySearchTreeNode<TKey>>();\n        breadthTraversal.Enqueue(root);\n        for (int i = 0; i < levelOrder.Length; i++)\n        {\n            BinarySearchTreeNode<TKey> current = breadthTraversal.Dequeue();\n            levelOrder[i] = current.Key;\n            if (current.Left is not null)\n            {\n                breadthTraversal.Enqueue(current.Left);\n            }\n\n            if (current.Right is not null)\n            {\n                breadthTraversal.Enqueue(current.Right);\n            }\n        }\n\n        return levelOrder;\n    }\n\n    /// <summary>\n    ///     Deepest Node return the deepest node in a binary tree. If more\n    ///     than one node is on the deepest level, it is defined as the\n    ///     right-most node of a binary tree. Deepest node uses breadth\n    ///     first traversal to reach the end.\n    /// </summary>\n    /// <param name=\"tree\">Tree passed to find deepest node.</param>\n    /// <returns>Returns the deepest node in the tree.</returns>\n    public static TKey? DeepestNode(BinarySearchTree<TKey> tree)\n    {\n        BinarySearchTreeNode<TKey>? root = tree.Root;\n        if (root is null)\n        {\n            return default(TKey);\n        }\n\n        Queue<BinarySearchTreeNode<TKey>> breadthTraversal = new Queue<BinarySearchTreeNode<TKey>>();\n        breadthTraversal.Enqueue(root);\n        TKey deepest = root.Key;\n        while (breadthTraversal.Count > 0)\n        {\n            BinarySearchTreeNode<TKey> current = breadthTraversal.Dequeue();\n            if (current.Left is not null)\n            {\n                breadthTraversal.Enqueue(current.Left);\n            }\n\n            if (current.Right is not null)\n            {\n                breadthTraversal.Enqueue(current.Right);\n            }\n\n            deepest = current.Key;\n        }\n\n        return deepest;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/Bridges.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Algorithms.Graph;\n\n/// <summary>\n/// Finds bridges (cut edges) in an undirected graph.\n/// A bridge is an edge whose removal increases the number of connected components.\n/// </summary>\npublic static class Bridges\n{\n    /// <summary>\n    /// Finds all bridges in an undirected graph.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of vertex.</typeparam>\n    /// <param name=\"vertices\">All vertices in the graph.</param>\n    /// <param name=\"getNeighbors\">Function to get neighbors of a vertex.</param>\n    /// <returns>Set of bridges as tuples of vertices.</returns>\n    public static HashSet<(T From, T To)> Find<T>(\n        IEnumerable<T> vertices,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        if (vertices == null)\n        {\n            throw new ArgumentNullException(nameof(vertices));\n        }\n\n        if (getNeighbors == null)\n        {\n            throw new ArgumentNullException(nameof(getNeighbors));\n        }\n\n        var vertexList = vertices.ToList();\n        if (vertexList.Count == 0)\n        {\n            return new HashSet<(T, T)>();\n        }\n\n        var bridges = new HashSet<(T, T)>();\n        var visited = new HashSet<T>();\n        var discoveryTime = new Dictionary<T, int>();\n        var low = new Dictionary<T, int>();\n        var parent = new Dictionary<T, T?>();\n        var time = 0;\n\n        foreach (var vertex in vertexList)\n        {\n            if (!visited.Contains(vertex))\n            {\n                var state = new DfsState<T>\n                {\n                    Visited = visited,\n                    DiscoveryTime = discoveryTime,\n                    Low = low,\n                    Parent = parent,\n                    Bridges = bridges,\n                };\n                Dfs(vertex, ref time, state, getNeighbors);\n            }\n        }\n\n        return bridges;\n    }\n\n    /// <summary>\n    /// Checks if an edge is a bridge.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of vertex.</typeparam>\n    /// <param name=\"from\">Source vertex.</param>\n    /// <param name=\"to\">Destination vertex.</param>\n    /// <param name=\"vertices\">All vertices in the graph.</param>\n    /// <param name=\"getNeighbors\">Function to get neighbors of a vertex.</param>\n    /// <returns>True if edge is a bridge.</returns>\n    public static bool IsBridge<T>(\n        T from,\n        T to,\n        IEnumerable<T> vertices,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        var bridges = Find(vertices, getNeighbors);\n        return bridges.Contains((from, to)) || bridges.Contains((to, from));\n    }\n\n    /// <summary>\n    /// Counts the number of bridges in the graph.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of vertex.</typeparam>\n    /// <param name=\"vertices\">All vertices in the graph.</param>\n    /// <param name=\"getNeighbors\">Function to get neighbors of a vertex.</param>\n    /// <returns>Number of bridges.</returns>\n    public static int Count<T>(\n        IEnumerable<T> vertices,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        return Find(vertices, getNeighbors).Count;\n    }\n\n    private static void Dfs<T>(\n        T u,\n        ref int time,\n        DfsState<T> state,\n        Func<T, IEnumerable<T>> getNeighbors) where T : notnull\n    {\n        state.Visited.Add(u);\n        state.DiscoveryTime[u] = time;\n        state.Low[u] = time;\n        time++;\n\n        foreach (var v in getNeighbors(u))\n        {\n            if (!state.Visited.Contains(v))\n            {\n                state.Parent[v] = u;\n                Dfs(v, ref time, state, getNeighbors);\n\n                state.Low[u] = Math.Min(state.Low[u], state.Low[v]);\n\n                // Check if edge u-v is a bridge\n                if (state.Low[v] > state.DiscoveryTime[u])\n                {\n                    state.Bridges.Add((u, v));\n                }\n            }\n            else if (!EqualityComparer<T>.Default.Equals(v, state.Parent.GetValueOrDefault(u)))\n            {\n                // Back edge: update low value\n                state.Low[u] = Math.Min(state.Low[u], state.DiscoveryTime[v]);\n            }\n            else\n            {\n                // Edge to parent: no action needed\n            }\n        }\n    }\n\n    /// <summary>\n    /// Encapsulates the state for DFS traversal in bridge detection.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of vertex.</typeparam>\n    private sealed class DfsState<T>\n        where T : notnull\n    {\n        /// <summary>\n        /// Gets set of visited vertices.\n        /// </summary>\n        public required HashSet<T> Visited { get; init; }\n\n        /// <summary>\n        /// Gets discovery time for each vertex.\n        /// </summary>\n        public required Dictionary<T, int> DiscoveryTime { get; init; }\n\n        /// <summary>\n        /// Gets lowest discovery time reachable from each vertex.\n        /// </summary>\n        public required Dictionary<T, int> Low { get; init; }\n\n        /// <summary>\n        /// Gets parent vertex in DFS tree.\n        /// </summary>\n        public required Dictionary<T, T?> Parent { get; init; }\n\n        /// <summary>\n        /// Gets set of detected bridges.\n        /// </summary>\n        public required HashSet<(T From, T To)> Bridges { get; init; }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/DepthFirstSearch.cs",
    "content": "using DataStructures.Graph;\n\nnamespace Algorithms.Graph;\n\n/// <summary>\n/// Depth First Search - algorithm for traversing graph.\n/// Algorithm starts from root node that is selected by the user.\n/// Algorithm explores as far as possible along each branch before backtracking.\n/// </summary>\n/// <typeparam name=\"T\">Vertex data type.</typeparam>\npublic class DepthFirstSearch<T> : IGraphSearch<T> where T : IComparable<T>\n{\n    /// <summary>\n    /// Traverses graph from start vertex.\n    /// </summary>\n    /// <param name=\"graph\">Graph instance.</param>\n    /// <param name=\"startVertex\">Vertex that search starts from.</param>\n    /// <param name=\"action\">Action that needs to be executed on each graph vertex.</param>\n    public void VisitAll(IDirectedWeightedGraph<T> graph, Vertex<T> startVertex, Action<Vertex<T>>? action = default)\n    {\n        Dfs(graph, startVertex, action, []);\n    }\n\n    /// <summary>\n    /// Traverses graph from start vertex.\n    /// </summary>\n    /// <param name=\"graph\">Graph instance.</param>\n    /// <param name=\"startVertex\">Vertex that search starts from.</param>\n    /// <param name=\"action\">Action that needs to be executed on each graph vertex.</param>\n    /// <param name=\"visited\">Hash set with visited vertices.</param>\n    private void Dfs(IDirectedWeightedGraph<T> graph, Vertex<T> startVertex, Action<Vertex<T>>? action, HashSet<Vertex<T>> visited)\n    {\n        action?.Invoke(startVertex);\n\n        visited.Add(startVertex);\n\n        foreach (var vertex in graph.GetNeighbors(startVertex))\n        {\n            if (vertex == null || visited.Contains(vertex))\n            {\n                continue;\n            }\n\n            Dfs(graph, vertex!, action, visited);\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs",
    "content": "using DataStructures.Graph;\n\nnamespace Algorithms.Graph.Dijkstra;\n\npublic static class DijkstraAlgorithm\n{\n    /// <summary>\n    /// Implementation of the Dijkstra shortest path algorithm for cyclic graphs.\n    /// https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm.\n    /// </summary>\n    /// <param name=\"graph\">Graph instance.</param>\n    /// <param name=\"startVertex\">Starting vertex instance.</param>\n    /// <typeparam name=\"T\">Generic Parameter.</typeparam>\n    /// <returns>List of distances from current vertex to all other vertices.</returns>\n    /// <exception cref=\"InvalidOperationException\">Exception thrown in case when graph is null or start\n    /// vertex does not belong to graph instance.</exception>\n    public static DistanceModel<T>[] GenerateShortestPath<T>(DirectedWeightedGraph<T> graph, Vertex<T> startVertex)\n    {\n        ValidateGraphAndStartVertex(graph, startVertex);\n\n        var visitedVertices = new List<Vertex<T>>();\n\n        var distanceArray = InitializeDistanceArray(graph, startVertex);\n\n        var distanceRecord = new PriorityQueue<DistanceModel<T>, double>();\n\n        distanceRecord.Enqueue(distanceArray[0], distanceArray[0].Distance);\n\n        while (visitedVertices.Count != distanceArray.Length && distanceRecord.Count != 0)\n        {\n            while (visitedVertices.Contains(distanceRecord.Peek().Vertex!))\n            {\n                distanceRecord.Dequeue();\n            }\n\n            var minDistance = distanceRecord.Dequeue();\n\n            var currentPath = minDistance.Distance;\n\n            visitedVertices.Add(minDistance.Vertex!);\n\n            var neighborVertices = graph\n                .GetNeighbors(minDistance.Vertex!)\n                .Where(x => x != null && !visitedVertices.Contains(x))\n                .ToList();\n\n            foreach (var vertex in neighborVertices)\n            {\n                var adjacentDistance = graph.AdjacentDistance(minDistance.Vertex!, vertex!);\n\n                var distance = distanceArray[vertex!.Index];\n\n                var fullDistance = currentPath + adjacentDistance;\n\n                if (distance.Distance > fullDistance)\n                {\n                    distance.Distance = fullDistance;\n                    distance.PreviousVertex = minDistance.Vertex;\n                    distanceRecord.Enqueue(distance, fullDistance);\n                }\n            }\n        }\n\n        return distanceArray;\n    }\n\n    private static DistanceModel<T>[] InitializeDistanceArray<T>(\n        IDirectedWeightedGraph<T> graph,\n        Vertex<T> startVertex)\n    {\n        var distArray = new DistanceModel<T>[graph.Count];\n\n        distArray[startVertex.Index] = new DistanceModel<T>(startVertex, startVertex, 0);\n\n        foreach (var vertex in graph.Vertices.Where(x => x != null && !x.Equals(startVertex)))\n        {\n            distArray[vertex!.Index] = new DistanceModel<T>(vertex, null, double.MaxValue);\n        }\n\n        return distArray;\n    }\n\n    private static void ValidateGraphAndStartVertex<T>(DirectedWeightedGraph<T> graph, Vertex<T> startVertex)\n    {\n        if (graph is null)\n        {\n            throw new ArgumentNullException(nameof(graph));\n        }\n\n        if (startVertex.Graph != null && !startVertex.Graph.Equals(graph))\n        {\n            throw new ArgumentNullException(nameof(graph));\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/Dijkstra/DistanceModel.cs",
    "content": "using DataStructures.Graph;\n\nnamespace Algorithms.Graph.Dijkstra;\n\n/// <summary>\n/// Entity which represents the Dijkstra shortest distance.\n/// Contains: Vertex, Previous Vertex and minimal distance from start vertex.\n/// </summary>\n/// <typeparam name=\"T\">Generic parameter.</typeparam>\npublic class DistanceModel<T>(Vertex<T>? vertex, Vertex<T>? previousVertex, double distance)\n{\n    public Vertex<T>? Vertex { get; } = vertex;\n\n    public Vertex<T>? PreviousVertex { get; set; } = previousVertex;\n\n    public double Distance { get; set; } = distance;\n\n    public override string ToString() =>\n        $\"Vertex: {Vertex} - Distance: {Distance} - Previous: {PreviousVertex}\";\n}\n"
  },
  {
    "path": "Algorithms/Graph/FloydWarshall.cs",
    "content": "using DataStructures.Graph;\n\nnamespace Algorithms.Graph;\n\n/// <summary>\n/// Floyd Warshall algorithm on directed weighted graph.\n/// </summary>\n/// <typeparam name=\"T\">generic type of data in graph.</typeparam>\npublic class FloydWarshall<T>\n{\n    /// <summary>\n    /// runs the algorithm.\n    /// </summary>\n    /// <param name=\"graph\">graph upon which to run.</param>\n    /// <returns>\n    /// a 2D array of shortest paths between any two vertices.\n    /// where there is no path between two vertices - double.PositiveInfinity is placed.\n    /// </returns>\n    public double[,] Run(DirectedWeightedGraph<T> graph)\n    {\n        var distances = SetupDistances(graph);\n        var vertexCount = distances.GetLength(0);\n        for (var k = 0; k < vertexCount; k++)\n        {\n            for (var i = 0; i < vertexCount; i++)\n            {\n                for (var j = 0; j < vertexCount; j++)\n                {\n                    distances[i, j] = distances[i, j] > distances[i, k] + distances[k, j]\n                    ? distances[i, k] + distances[k, j]\n                    : distances[i, j];\n                }\n            }\n        }\n\n        return distances;\n    }\n\n    /// <summary>\n    /// setup adjacency matrix for use by main algorithm run.\n    /// </summary>\n    /// <param name=\"graph\">graph to dissect adjacency matrix from.</param>\n    /// <returns>the adjacency matrix in the format mentioned in Run.</returns>\n    private double[,] SetupDistances(DirectedWeightedGraph<T> graph)\n    {\n        var distances = new double[graph.Count, graph.Count];\n        for (int i = 0; i < distances.GetLength(0); i++)\n        {\n            for (var j = 0; j < distances.GetLength(0); j++)\n            {\n                var dist = graph.AdjacentDistance(graph.Vertices[i]!, graph.Vertices[j]!);\n                distances[i, j] = dist != 0 ? dist : double.PositiveInfinity;\n            }\n        }\n\n        for (var i = 0; i < distances.GetLength(0); i++)\n        {\n            distances[i, i] = 0;\n        }\n\n        return distances;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/IGraphSearch.cs",
    "content": "using DataStructures.Graph;\n\nnamespace Algorithms.Graph;\n\npublic interface IGraphSearch<T>\n{\n    /// <summary>\n    /// Traverses graph from start vertex.\n    /// </summary>\n    /// <param name=\"graph\">Graph instance.</param>\n    /// <param name=\"startVertex\">Vertex that search starts from.</param>\n    /// <param name=\"action\">Action that needs to be executed on each graph vertex.</param>\n    void VisitAll(IDirectedWeightedGraph<T> graph, Vertex<T> startVertex, Action<Vertex<T>>? action = null);\n}\n"
  },
  {
    "path": "Algorithms/Graph/Kosaraju.cs",
    "content": "using DataStructures.Graph;\n\nnamespace Algorithms.Graph;\n\n/// <summary>\n/// Implementation of Kosaraju-Sharir's algorithm (also known as Kosaraju's algorithm) to find the\n/// strongly connected components (SCC) of a directed graph.\n/// See https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm.\n/// </summary>\n/// <typeparam name=\"T\">Vertex data type.</typeparam>\npublic static class Kosaraju<T>\n{\n    /// <summary>\n    /// First DFS for Kosaraju algorithm: traverse the graph creating a reverse order explore list <paramref name=\"reversed\"/>.\n    /// </summary>\n    /// <param name=\"v\">Vertex to explore.</param>\n    /// <param name=\"graph\">Graph instance.</param>\n    /// <param name=\"visited\">List of already visited vertex.</param>\n    /// <param name=\"reversed\">Reversed list of vertex for the second DFS.</param>\n    public static void Visit(Vertex<T> v, IDirectedWeightedGraph<T> graph, HashSet<Vertex<T>> visited, Stack<Vertex<T>> reversed)\n    {\n        if (visited.Contains(v))\n        {\n            return;\n        }\n\n        // Set v as visited\n        visited.Add(v);\n\n        // Push v in the stack.\n        // This can also be done with a List, inserting v at the begining of the list\n        // after visit the neighbors.\n        reversed.Push(v);\n\n        // Visit neighbors\n        foreach (var u in graph.GetNeighbors(v))\n        {\n            Visit(u!, graph, visited, reversed);\n        }\n    }\n\n    /// <summary>\n    /// Second DFS for Kosaraju algorithm. Traverse the graph in reversed order\n    /// assigning a root vertex for every vertex that belong to the same SCC.\n    /// </summary>\n    /// <param name=\"v\">Vertex to assign.</param>\n    /// <param name=\"root\">Root vertext, representative of the SCC.</param>\n    /// <param name=\"graph\">Graph with vertex and edges.</param>\n    /// <param name=\"roots\">\n    /// Dictionary that assigns to each vertex the root of the SCC to which it corresponds.\n    /// </param>\n    public static void Assign(Vertex<T> v, Vertex<T> root, IDirectedWeightedGraph<T> graph, Dictionary<Vertex<T>, Vertex<T>> roots)\n    {\n        // If v already has a representative vertex (root) already assigned, do nothing.\n        if (roots.ContainsKey(v))\n        {\n            return;\n        }\n\n        // Assign the root to the vertex.\n        roots.Add(v, root);\n\n        // Assign the current root vertex to v neighbors.\n        foreach (var u in graph.GetNeighbors(v))\n        {\n            Assign(u!, root, graph, roots);\n        }\n    }\n\n    /// <summary>\n    /// Find the representative vertex of the SCC for each vertex on the graph.\n    /// </summary>\n    /// <param name=\"graph\">Graph to explore.</param>\n    /// <returns>A dictionary that assigns to each vertex a root vertex of the SCC they belong. </returns>\n    public static Dictionary<Vertex<T>, Vertex<T>> GetRepresentatives(IDirectedWeightedGraph<T> graph)\n    {\n        HashSet<Vertex<T>> visited = [];\n        Stack<Vertex<T>> reversedL = new Stack<Vertex<T>>();\n        Dictionary<Vertex<T>, Vertex<T>> representatives = [];\n\n        foreach (var v in graph.Vertices)\n        {\n            if (v != null)\n            {\n                Visit(v, graph, visited, reversedL);\n            }\n        }\n\n        visited.Clear();\n\n        while (reversedL.Count > 0)\n        {\n            Vertex<T> v = reversedL.Pop();\n            Assign(v, v, graph, representatives);\n        }\n\n        return representatives;\n    }\n\n    /// <summary>\n    /// Get the Strongly Connected Components for the graph.\n    /// </summary>\n    /// <param name=\"graph\">Graph to explore.</param>\n    /// <returns>An array of SCC.</returns>\n    public static IEnumerable<Vertex<T>>[] GetScc(IDirectedWeightedGraph<T> graph)\n    {\n        var representatives = GetRepresentatives(graph);\n        Dictionary<Vertex<T>, List<Vertex<T>>> scc = [];\n        foreach (var kv in representatives)\n        {\n            // Assign all vertex (key) that have the seem root (value) to a single list.\n            if (scc.ContainsKey(kv.Value))\n            {\n                scc[kv.Value].Add(kv.Key);\n            }\n            else\n            {\n                scc.Add(kv.Value, [kv.Key]);\n            }\n        }\n\n        return scc.Values.ToArray();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/MinimumSpanningTree/Kruskal.cs",
    "content": "using DataStructures.DisjointSet;\n\nnamespace Algorithms.Graph.MinimumSpanningTree;\n\n/// <summary>\n///     Algorithm to determine the minimum spanning forest of an undirected graph.\n/// </summary>\n/// <remarks>\n///     Kruskal's algorithm is a greedy algorithm that can determine the\n///     minimum spanning tree or minimum spanning forest of any undirected\n///     graph. Unlike Prim's algorithm, Kruskal's algorithm will work on\n///     graphs that are unconnected. This algorithm will always have a\n///     running time of O(E log V) where E is the number of edges and V is\n///     the number of vertices/nodes.\n///     More information: https://en.wikipedia.org/wiki/Kruskal%27s_algorithm .\n///     Pseudocode and analysis: https://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/primAlgor.htm .\n/// </remarks>\npublic static class Kruskal\n{\n    /// <summary>\n    ///     Determine the minimum spanning tree/forest of the given graph.\n    /// </summary>\n    /// <param name=\"adjacencyMatrix\">Adjacency matrix representing the graph.</param>\n    /// <returns>Adjacency matrix of the minimum spanning tree/forest.</returns>\n    public static float[,] Solve(float[,] adjacencyMatrix)\n    {\n        ValidateGraph(adjacencyMatrix);\n\n        var numNodes = adjacencyMatrix.GetLength(0);\n        var set = new DisjointSet<int>();\n        var nodes = new Node<int>[numNodes];\n        var edgeWeightList = new List<float>();\n        var nodeConnectList = new List<(int, int)>();\n\n        // Add nodes to disjoint set\n        for (var i = 0; i < numNodes; i++)\n        {\n            nodes[i] = set.MakeSet(i);\n        }\n\n        // Create lists with edge weights and associated connectivity\n        for (var i = 0; i < numNodes - 1; i++)\n        {\n            for (var j = i + 1; j < numNodes; j++)\n            {\n                if (float.IsFinite(adjacencyMatrix[i, j]))\n                {\n                    edgeWeightList.Add(adjacencyMatrix[i, j]);\n                    nodeConnectList.Add((i, j));\n                }\n            }\n        }\n\n        var edges = Solve(set, nodes, edgeWeightList.ToArray(), nodeConnectList.ToArray());\n\n        // Initialize minimum spanning tree\n        var mst = new float[numNodes, numNodes];\n        for (var i = 0; i < numNodes; i++)\n        {\n            mst[i, i] = float.PositiveInfinity;\n\n            for (var j = i + 1; j < numNodes; j++)\n            {\n                mst[i, j] = float.PositiveInfinity;\n                mst[j, i] = float.PositiveInfinity;\n            }\n        }\n\n        foreach (var (node1, node2) in edges)\n        {\n            mst[node1, node2] = adjacencyMatrix[node1, node2];\n            mst[node2, node1] = adjacencyMatrix[node1, node2];\n        }\n\n        return mst;\n    }\n\n    /// <summary>\n    ///     Determine the minimum spanning tree/forest of the given graph.\n    /// </summary>\n    /// <param name=\"adjacencyList\">Adjacency list representing the graph.</param>\n    /// <returns>Adjacency list of the minimum spanning tree/forest.</returns>\n    public static Dictionary<int, float>[] Solve(Dictionary<int, float>[] adjacencyList)\n    {\n        ValidateGraph(adjacencyList);\n\n        var numNodes = adjacencyList.Length;\n        var set = new DisjointSet<int>();\n        var nodes = new Node<int>[numNodes];\n        var edgeWeightList = new List<float>();\n        var nodeConnectList = new List<(int, int)>();\n\n        // Add nodes to disjoint set and create list of edge weights and associated connectivity\n        for (var i = 0; i < numNodes; i++)\n        {\n            nodes[i] = set.MakeSet(i);\n\n            foreach (var (node, weight) in adjacencyList[i])\n            {\n                edgeWeightList.Add(weight);\n                nodeConnectList.Add((i, node));\n            }\n        }\n\n        var edges = Solve(set, nodes, edgeWeightList.ToArray(), nodeConnectList.ToArray());\n\n        // Create minimum spanning tree\n        var mst = new Dictionary<int, float>[numNodes];\n        for (var i = 0; i < numNodes; i++)\n        {\n            mst[i] = [];\n        }\n\n        foreach (var (node1, node2) in edges)\n        {\n            mst[node1].Add(node2, adjacencyList[node1][node2]);\n            mst[node2].Add(node1, adjacencyList[node1][node2]);\n        }\n\n        return mst;\n    }\n\n    /// <summary>\n    ///     Ensure that the given graph is undirected.\n    /// </summary>\n    /// <param name=\"adj\">Adjacency matrix of graph to check.</param>\n    private static void ValidateGraph(float[,] adj)\n    {\n        if (adj.GetLength(0) != adj.GetLength(1))\n        {\n            throw new ArgumentException(\"Matrix must be square!\");\n        }\n\n        for (var i = 0; i < adj.GetLength(0) - 1; i++)\n        {\n            for (var j = i + 1; j < adj.GetLength(1); j++)\n            {\n                if (Math.Abs(adj[i, j] - adj[j, i]) > 1e-6)\n                {\n                    throw new ArgumentException(\"Matrix must be symmetric!\");\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Ensure that the given graph is undirected.\n    /// </summary>\n    /// <param name=\"adj\">Adjacency list of graph to check.</param>\n    private static void ValidateGraph(Dictionary<int, float>[] adj)\n    {\n        for (var i = 0; i < adj.Length; i++)\n        {\n            foreach (var edge in adj[i])\n            {\n                if (!adj[edge.Key].ContainsKey(i) || Math.Abs(edge.Value - adj[edge.Key][i]) > 1e-6)\n                {\n                    throw new ArgumentException(\"Graph must be undirected!\");\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Determine the minimum spanning tree/forest.\n    /// </summary>\n    /// <param name=\"set\">Disjoint set needed for set operations.</param>\n    /// <param name=\"nodes\">List of nodes in disjoint set associated with each node.</param>\n    /// <param name=\"edgeWeights\">Weights of each edge.</param>\n    /// <param name=\"connections\">Nodes associated with each item in the <paramref name=\"edgeWeights\"/> parameter.</param>\n    /// <returns>Array of edges in the minimum spanning tree/forest.</returns>\n    private static (int, int)[] Solve(DisjointSet<int> set, Node<int>[] nodes, float[] edgeWeights, (int, int)[] connections)\n    {\n        var edges = new List<(int, int)>();\n\n        Array.Sort(edgeWeights, connections);\n\n        foreach (var (node1, node2) in connections)\n        {\n            if (set.FindSet(nodes[node1]) != set.FindSet(nodes[node2]))\n            {\n                set.UnionSet(nodes[node1], nodes[node2]);\n                edges.Add((node1, node2));\n            }\n        }\n\n        return edges.ToArray();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs",
    "content": "namespace Algorithms.Graph.MinimumSpanningTree;\n\n/// <summary>\n///     Class that uses Prim's (Jarnik's algorithm) to determine the minimum\n///     spanning tree (MST) of a given graph. Prim's algorithm is a greedy\n///     algorithm that can determine the MST of a weighted undirected graph\n///     in O(V^2) time where V is the number of nodes/vertices when using an\n///     adjacency matrix representation.\n///     More information: https://en.wikipedia.org/wiki/Prim%27s_algorithm\n///     Pseudocode and runtime analysis: https://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/primAlgor.htm .\n/// </summary>\npublic static class PrimMatrix\n{\n    /// <summary>\n    ///     Determine the minimum spanning tree for a given weighted undirected graph.\n    /// </summary>\n    /// <param name=\"adjacencyMatrix\">Adjacency matrix for graph to find MST of.</param>\n    /// <param name=\"start\">Node to start search from.</param>\n    /// <returns>Adjacency matrix of the found MST.</returns>\n    public static float[,] Solve(float[,] adjacencyMatrix, int start)\n    {\n        ValidateMatrix(adjacencyMatrix);\n\n        var numNodes = adjacencyMatrix.GetLength(0);\n\n        // Create array to represent minimum spanning tree\n        var mst = new float[numNodes, numNodes];\n\n        // Create array to keep track of which nodes are in the MST already\n        var added = new bool[numNodes];\n\n        // Create array to keep track of smallest edge weight for node\n        var key = new float[numNodes];\n\n        // Create array to store parent of node\n        var parent = new int[numNodes];\n\n        for (var i = 0; i < numNodes; i++)\n        {\n            mst[i, i] = float.PositiveInfinity;\n            key[i] = float.PositiveInfinity;\n\n            for (var j = i + 1; j < numNodes; j++)\n            {\n                mst[i, j] = float.PositiveInfinity;\n                mst[j, i] = float.PositiveInfinity;\n            }\n        }\n\n        // Ensures that the starting node is added first\n        key[start] = 0;\n\n        // Keep looping until all nodes are in tree\n        for (var i = 0; i < numNodes - 1; i++)\n        {\n            GetNextNode(adjacencyMatrix, key, added, parent);\n        }\n\n        // Build adjacency matrix for tree\n        for (var i = 0; i < numNodes; i++)\n        {\n            if (i == start)\n            {\n                continue;\n            }\n\n            mst[i, parent[i]] = adjacencyMatrix[i, parent[i]];\n            mst[parent[i], i] = adjacencyMatrix[i, parent[i]];\n        }\n\n        return mst;\n    }\n\n    /// <summary>\n    ///     Ensure that the given adjacency matrix represents a weighted undirected graph.\n    /// </summary>\n    /// <param name=\"adjacencyMatrix\">Adjacency matric to check.</param>\n    private static void ValidateMatrix(float[,] adjacencyMatrix)\n    {\n        // Matrix should be square\n        if (adjacencyMatrix.GetLength(0) != adjacencyMatrix.GetLength(1))\n        {\n            throw new ArgumentException(\"Adjacency matrix must be square!\");\n        }\n\n        // Graph needs to be undirected and connected\n        for (var i = 0; i < adjacencyMatrix.GetLength(0); i++)\n        {\n            var connection = false;\n            for (var j = 0; j < adjacencyMatrix.GetLength(0); j++)\n            {\n                if (Math.Abs(adjacencyMatrix[i, j] - adjacencyMatrix[j, i]) > 1e-6)\n                {\n                    throw new ArgumentException(\"Adjacency matrix must be symmetric!\");\n                }\n\n                if (!connection && float.IsFinite(adjacencyMatrix[i, j]))\n                {\n                    connection = true;\n                }\n            }\n\n            if (!connection)\n            {\n                throw new ArgumentException(\"Graph must be connected!\");\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Determine which node should be added next to the MST.\n    /// </summary>\n    /// <param name=\"adjacencyMatrix\">Adjacency matrix of graph.</param>\n    /// <param name=\"key\">Currently known minimum edge weight connected to each node.</param>\n    /// <param name=\"added\">Whether or not a node has been added to the MST.</param>\n    /// <param name=\"parent\">The node that added the node to the MST. Used for building MST adjacency matrix.</param>\n    private static void GetNextNode(float[,] adjacencyMatrix, float[] key, bool[] added, int[] parent)\n    {\n        var numNodes = adjacencyMatrix.GetLength(0);\n        var minWeight = float.PositiveInfinity;\n\n        var node = -1;\n\n        // Find node with smallest node with known edge weight not in tree. Will always start with starting node\n        for (var i = 0; i < numNodes; i++)\n        {\n            if (!added[i] && key[i] < minWeight)\n            {\n                minWeight = key[i];\n                node = i;\n            }\n        }\n\n        // Add node to mst\n        added[node] = true;\n\n        // Update smallest found edge weights and parent for adjacent nodes\n        for (var i = 0; i < numNodes; i++)\n        {\n            if (!added[i] && adjacencyMatrix[node, i] < key[i])\n            {\n                key[i] = adjacencyMatrix[node, i];\n                parent[i] = node;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/TarjanStronglyConnectedComponents.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Algorithms.Graph;\n\n/// <summary>\n/// Tarjan's algorithm for finding strongly connected components in a directed graph.\n/// Uses depth-first search with a stack to identify SCCs in O(V + E) time.\n/// </summary>\npublic class TarjanStronglyConnectedComponents\n{\n    private readonly List<int>[] graph;\n    private readonly int[] ids;\n    private readonly int[] low;\n    private readonly bool[] onStack;\n    private readonly Stack<int> stack;\n    private readonly List<List<int>> sccs;\n    private int id;\n\n    public TarjanStronglyConnectedComponents(int vertices)\n    {\n        graph = new List<int>[vertices];\n        ids = new int[vertices];\n        low = new int[vertices];\n        onStack = new bool[vertices];\n        stack = new Stack<int>();\n        sccs = new List<List<int>>();\n\n        for (int i = 0; i < vertices; i++)\n        {\n            graph[i] = new List<int>();\n            ids[i] = -1;\n        }\n    }\n\n    /// <summary>\n    /// Adds a directed edge from u to v.\n    /// </summary>\n    public void AddEdge(int u, int v)\n    {\n        if (u < 0 || u >= graph.Length || v < 0 || v >= graph.Length)\n        {\n            throw new ArgumentOutOfRangeException(nameof(u), \"Vertex indices must be within valid range.\");\n        }\n\n        graph[u].Add(v);\n    }\n\n    /// <summary>\n    /// Finds all strongly connected components.\n    /// </summary>\n    /// <returns>List of SCCs, where each SCC is a list of vertex indices.</returns>\n    public List<List<int>> FindSCCs()\n    {\n        for (int i = 0; i < graph.Length; i++)\n        {\n            if (ids[i] == -1)\n            {\n                Dfs(i);\n            }\n        }\n\n        return sccs;\n    }\n\n    /// <summary>\n    /// Gets the number of strongly connected components.\n    /// </summary>\n    public int GetSccCount() => sccs.Count;\n\n    /// <summary>\n    /// Checks if two vertices are in the same SCC.\n    /// </summary>\n    public bool InSameScc(int u, int v)\n    {\n        if (sccs.Count == 0)\n        {\n            FindSCCs();\n        }\n\n        foreach (var scc in sccs)\n        {\n            if (scc.Contains(u) && scc.Contains(v))\n            {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /// <summary>\n    /// Gets the SCC containing the given vertex.\n    /// </summary>\n    public List<int>? GetScc(int vertex)\n    {\n        if (sccs.Count == 0)\n        {\n            FindSCCs();\n        }\n\n        return sccs.FirstOrDefault(scc => scc.Contains(vertex));\n    }\n\n    /// <summary>\n    /// Builds the condensation graph (DAG of SCCs).\n    /// </summary>\n    public List<int>[] BuildCondensationGraph()\n    {\n        if (sccs.Count == 0)\n        {\n            FindSCCs();\n        }\n\n        var sccIndex = new int[graph.Length];\n        for (int i = 0; i < sccs.Count; i++)\n        {\n            foreach (var vertex in sccs[i])\n            {\n                sccIndex[vertex] = i;\n            }\n        }\n\n        var condensation = new List<int>[sccs.Count];\n        for (int i = 0; i < sccs.Count; i++)\n        {\n            condensation[i] = new List<int>();\n        }\n\n        var edges = new HashSet<(int, int)>();\n        for (int u = 0; u < graph.Length; u++)\n        {\n            foreach (var v in graph[u])\n            {\n                int sccU = sccIndex[u];\n                int sccV = sccIndex[v];\n\n                if (sccU != sccV && !edges.Contains((sccU, sccV)))\n                {\n                    condensation[sccU].Add(sccV);\n                    edges.Add((sccU, sccV));\n                }\n            }\n        }\n\n        return condensation;\n    }\n\n    private void Dfs(int at)\n    {\n        stack.Push(at);\n        onStack[at] = true;\n        ids[at] = low[at] = id++;\n\n        foreach (var to in graph[at])\n        {\n            if (ids[to] == -1)\n            {\n                Dfs(to);\n            }\n\n            if (onStack[to])\n            {\n                low[at] = Math.Min(low[at], low[to]);\n            }\n        }\n\n        if (ids[at] == low[at])\n        {\n            var scc = new List<int>();\n            while (true)\n            {\n                int node = stack.Pop();\n                onStack[node] = false;\n                scc.Add(node);\n                if (node == at)\n                {\n                    break;\n                }\n            }\n\n            sccs.Add(scc);\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Graph/TopologicalSort.cs",
    "content": "using DataStructures.Graph;\n\nnamespace Algorithms.Graph;\n\n/// <summary>\n///     Topological Sort is a linear ordering of vertices in a Directed Acyclic Graph (DAG)\n///     such that for every directed edge (u, v), vertex u comes before vertex v in the ordering.\n///\n///     KEY CONCEPTS:\n///     1. Only applicable to Directed Acyclic Graphs (DAGs) - graphs with no cycles.\n///     2. A DAG can have multiple valid topological orderings.\n///     3. Used in dependency resolution, task scheduling, build systems, and course prerequisites.\n///\n///     ALGORITHM APPROACHES:\n///     1. DFS-based (Depth-First Search): Uses post-order traversal and reverses the result.\n///     2. Kahn's Algorithm: Uses in-degree counting and processes vertices with zero in-degree.\n///\n///     TIME COMPLEXITY: O(V + E) where V is vertices and E is edges.\n///     SPACE COMPLEXITY: O(V) for the visited set and result stack.\n///\n///     Reference: \"Introduction to Algorithms\" (CLRS) by Cormen, Leiserson, Rivest, and Stein.\n///     Also covered in \"Algorithm Design Manual\" by Steven Skiena.\n/// </summary>\n/// <typeparam name=\"T\">Vertex data type.</typeparam>\npublic class TopologicalSort<T> where T : IComparable<T>\n{\n    /// <summary>\n    ///     Performs topological sort on a directed acyclic graph using DFS-based approach.\n    ///\n    ///     ALGORITHM STEPS (DFS-based approach):\n    ///     1. Initialize a visited set to track processed vertices.\n    ///     2. Initialize a stack to store the topological ordering.\n    ///     3. For each unvisited vertex in the graph:\n    ///        a) Perform DFS from that vertex.\n    ///        b) After visiting all descendants, push the vertex to the stack.\n    ///     4. The stack now contains vertices in reverse topological order.\n    ///     5. Pop all vertices from the stack to get the topological ordering.\n    ///\n    ///     WHY IT WORKS:\n    ///     - In DFS, we push a vertex to the stack only after visiting all its descendants.\n    ///     - This ensures that all vertices that depend on the current vertex are processed first.\n    ///     - Reversing this order gives us the topological sort.\n    ///\n    ///     EXAMPLE:\n    ///     Graph: A → B → C\n    ///            A → D\n    ///            D → C\n    ///     Valid topological orderings: [A, B, D, C] or [A, D, B, C].\n    ///\n    ///     USE CASES:\n    ///     - Build systems (compile dependencies).\n    ///     - Task scheduling with dependencies.\n    ///     - Course prerequisite ordering.\n    ///     - Package dependency resolution.\n    /// </summary>\n    /// <param name=\"graph\">The directed acyclic graph to sort.</param>\n    /// <returns>A list of vertices in topological order.</returns>\n    /// <exception cref=\"InvalidOperationException\">\n    ///     Thrown when the graph contains a cycle (not a DAG).\n    /// </exception>\n    public List<Vertex<T>> Sort(IDirectedWeightedGraph<T> graph)\n    {\n        // Stack to store vertices in reverse topological order.\n        // We use a stack because DFS naturally gives us reverse topological order.\n        var stack = new Stack<Vertex<T>>();\n\n        // Track visited vertices to avoid reprocessing and detect cycles.\n        var visited = new HashSet<Vertex<T>>();\n\n        // Track vertices currently in the recursion stack to detect cycles.\n        // If we encounter a vertex that's in the recursion stack, we have a cycle.\n        var recursionStack = new HashSet<Vertex<T>>();\n\n        // Process all vertices in the graph.\n        // We need to iterate through all vertices because the graph might be disconnected.\n        for (int i = 0; i < graph.Count; i++)\n        {\n            var vertex = graph.Vertices[i];\n\n            // Skip null vertices (shouldn't happen in a well-formed graph).\n            if (vertex == null)\n            {\n                continue;\n            }\n\n            // If vertex hasn't been visited, perform DFS from it.\n            if (!visited.Contains(vertex))\n            {\n                DfsTopologicalSort(graph, vertex, visited, recursionStack, stack);\n            }\n        }\n\n        // Convert stack to list. The stack contains vertices in reverse topological order,\n        // so we need to reverse it to get the correct topological ordering.\n        var result = new List<Vertex<T>>(stack.Count);\n        while (stack.Count > 0)\n        {\n            result.Add(stack.Pop());\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Performs topological sort using Kahn's Algorithm (BFS-based approach).\n    ///\n    ///     ALGORITHM STEPS (Kahn's Algorithm):\n    ///     1. Calculate in-degree (number of incoming edges) for each vertex.\n    ///     2. Add all vertices with in-degree 0 to a queue.\n    ///     3. While the queue is not empty:\n    ///        a) Remove a vertex from the queue and add it to the result.\n    ///        b) For each neighbor of this vertex:\n    ///           - Decrease its in-degree by 1.\n    ///           - If in-degree becomes 0, add it to the queue.\n    ///     4. If all vertices are processed, return the result.\n    ///     5. If not all vertices are processed, the graph has a cycle.\n    ///\n    ///     WHY IT WORKS:\n    ///     - Vertices with in-degree 0 have no dependencies and can be processed first.\n    ///     - After processing a vertex, we \"remove\" its outgoing edges by decreasing\n    ///       the in-degree of its neighbors.\n    ///     - This gradually reveals more vertices with in-degree 0.\n    ///\n    ///     ADVANTAGES OVER DFS:\n    ///     - More intuitive for understanding dependencies.\n    ///     - Easier to detect cycles (if not all vertices are processed).\n    ///     - Better for parallel processing scenarios.\n    /// </summary>\n    /// <param name=\"graph\">The directed acyclic graph to sort.</param>\n    /// <returns>A list of vertices in topological order.</returns>\n    /// <exception cref=\"InvalidOperationException\">\n    ///     Thrown when the graph contains a cycle (not a DAG).\n    /// </exception>\n    public List<Vertex<T>> SortKahn(IDirectedWeightedGraph<T> graph)\n    {\n        // Calculate in-degree for each vertex.\n        var inDegree = CalculateInDegrees(graph);\n\n        // Queue to process vertices with in-degree 0.\n        var queue = InitializeQueueWithZeroInDegreeVertices(inDegree);\n\n        // Process vertices in topological order.\n        var result = ProcessVerticesInTopologicalOrder(graph, inDegree, queue);\n\n        // Verify all vertices were processed (no cycles).\n        ValidateNoCycles(graph, result);\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Calculates the in-degree for each vertex in the graph.\n    ///     In-degree is the number of incoming edges to a vertex.\n    /// </summary>\n    /// <param name=\"graph\">The graph to analyze.</param>\n    /// <returns>Dictionary mapping each vertex to its in-degree.</returns>\n    private Dictionary<Vertex<T>, int> CalculateInDegrees(IDirectedWeightedGraph<T> graph)\n    {\n        var inDegree = new Dictionary<Vertex<T>, int>();\n\n        // Initialize in-degree for all vertices to 0.\n        for (int i = 0; i < graph.Count; i++)\n        {\n            var vertex = graph.Vertices[i];\n            if (vertex != null)\n            {\n                inDegree[vertex] = 0;\n            }\n        }\n\n        // Calculate actual in-degrees by examining all edges.\n        for (int i = 0; i < graph.Count; i++)\n        {\n            var vertex = graph.Vertices[i];\n            if (vertex != null)\n            {\n                IncrementNeighborInDegrees(graph, vertex, inDegree);\n            }\n        }\n\n        return inDegree;\n    }\n\n    /// <summary>\n    ///     Increments the in-degree for all neighbors of a given vertex.\n    /// </summary>\n    /// <param name=\"graph\">The graph containing the vertices.</param>\n    /// <param name=\"vertex\">The vertex whose neighbors' in-degrees should be incremented.</param>\n    /// <param name=\"inDegree\">Dictionary tracking in-degrees.</param>\n    private void IncrementNeighborInDegrees(\n        IDirectedWeightedGraph<T> graph,\n        Vertex<T> vertex,\n        Dictionary<Vertex<T>, int> inDegree)\n    {\n        foreach (var neighbor in graph.GetNeighbors(vertex))\n        {\n            if (neighbor != null)\n            {\n                inDegree[neighbor]++;\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Initializes a queue with all vertices that have in-degree 0.\n    ///     These vertices have no dependencies and can be processed first.\n    /// </summary>\n    /// <param name=\"inDegree\">Dictionary mapping vertices to their in-degrees.</param>\n    /// <returns>Queue containing all vertices with in-degree 0.</returns>\n    private Queue<Vertex<T>> InitializeQueueWithZeroInDegreeVertices(Dictionary<Vertex<T>, int> inDegree)\n    {\n        var queue = new Queue<Vertex<T>>();\n\n        foreach (var kvp in inDegree)\n        {\n            if (kvp.Value == 0)\n            {\n                queue.Enqueue(kvp.Key);\n            }\n        }\n\n        return queue;\n    }\n\n    /// <summary>\n    ///     Processes vertices in topological order using Kahn's algorithm.\n    ///     Dequeues vertices with in-degree 0 and decreases in-degrees of their neighbors.\n    /// </summary>\n    /// <param name=\"graph\">The graph being sorted.</param>\n    /// <param name=\"inDegree\">Dictionary tracking in-degrees.</param>\n    /// <param name=\"queue\">Queue of vertices with in-degree 0.</param>\n    /// <returns>List of vertices in topological order.</returns>\n    private List<Vertex<T>> ProcessVerticesInTopologicalOrder(\n        IDirectedWeightedGraph<T> graph,\n        Dictionary<Vertex<T>, int> inDegree,\n        Queue<Vertex<T>> queue)\n    {\n        var result = new List<Vertex<T>>();\n\n        while (queue.Count > 0)\n        {\n            var vertex = queue.Dequeue();\n            result.Add(vertex);\n\n            ProcessNeighbors(graph, vertex, inDegree, queue);\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Processes neighbors of a vertex by decreasing their in-degrees.\n    ///     If a neighbor's in-degree becomes 0, it's added to the queue.\n    /// </summary>\n    /// <param name=\"graph\">The graph being sorted.</param>\n    /// <param name=\"vertex\">The vertex whose neighbors are being processed.</param>\n    /// <param name=\"inDegree\">Dictionary tracking in-degrees.</param>\n    /// <param name=\"queue\">Queue of vertices with in-degree 0.</param>\n    private void ProcessNeighbors(\n        IDirectedWeightedGraph<T> graph,\n        Vertex<T> vertex,\n        Dictionary<Vertex<T>, int> inDegree,\n        Queue<Vertex<T>> queue)\n    {\n        foreach (var neighbor in graph.GetNeighbors(vertex))\n        {\n            if (neighbor != null)\n            {\n                inDegree[neighbor]--;\n\n                if (inDegree[neighbor] == 0)\n                {\n                    queue.Enqueue(neighbor);\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Validates that all vertices were processed, ensuring no cycles exist.\n    /// </summary>\n    /// <param name=\"graph\">The graph being sorted.</param>\n    /// <param name=\"result\">The list of processed vertices.</param>\n    /// <exception cref=\"InvalidOperationException\">\n    ///     Thrown when not all vertices were processed (cycle detected).\n    /// </exception>\n    private void ValidateNoCycles(IDirectedWeightedGraph<T> graph, List<Vertex<T>> result)\n    {\n        if (result.Count != graph.Count)\n        {\n            throw new InvalidOperationException(\n                \"Graph contains a cycle. Topological sort is only possible for Directed Acyclic Graphs (DAGs).\");\n        }\n    }\n\n    /// <summary>\n    ///     Helper method for DFS-based topological sort.\n    ///     Recursively visits vertices and adds them to the stack in post-order.\n    ///\n    ///     POST-ORDER TRAVERSAL:\n    ///     - Visit all descendants first.\n    ///     - Then process the current vertex.\n    ///     - This ensures dependencies are processed before dependents.\n    ///\n    ///     CYCLE DETECTION:\n    ///     - We maintain a recursion stack to track the current DFS path.\n    ///     - If we encounter a vertex that's already in the recursion stack,\n    ///       we've found a back edge, indicating a cycle.\n    /// </summary>\n    /// <param name=\"graph\">The graph being sorted.</param>\n    /// <param name=\"vertex\">The current vertex being processed.</param>\n    /// <param name=\"visited\">Set of all visited vertices.</param>\n    /// <param name=\"recursionStack\">Set of vertices in the current DFS path.</param>\n    /// <param name=\"stack\">Stack to store vertices in reverse topological order.</param>\n    /// <exception cref=\"InvalidOperationException\">\n    ///     Thrown when a cycle is detected.\n    /// </exception>\n    private void DfsTopologicalSort(\n        IDirectedWeightedGraph<T> graph,\n        Vertex<T> vertex,\n        HashSet<Vertex<T>> visited,\n        HashSet<Vertex<T>> recursionStack,\n        Stack<Vertex<T>> stack)\n    {\n        // CYCLE DETECTION:\n        // If the vertex is in the recursion stack, we've encountered it again\n        // in the current DFS path, which means there's a cycle.\n        if (recursionStack.Contains(vertex))\n        {\n            throw new InvalidOperationException(\n                $\"Graph contains a cycle involving vertex: {vertex}. \" +\n                \"Topological sort is only possible for Directed Acyclic Graphs (DAGs).\");\n        }\n\n        // If already visited, no need to process again.\n        if (visited.Contains(vertex))\n        {\n            return;\n        }\n\n        // Mark vertex as visited and add to recursion stack.\n        visited.Add(vertex);\n        recursionStack.Add(vertex);\n\n        // Recursively visit all neighbors (descendants).\n        // This ensures all dependencies are processed first.\n        foreach (var neighbor in graph.GetNeighbors(vertex))\n        {\n            if (neighbor != null)\n            {\n                DfsTopologicalSort(graph, neighbor, visited, recursionStack, stack);\n            }\n        }\n\n        // Remove from recursion stack as we're done with this DFS path.\n        recursionStack.Remove(vertex);\n\n        // POST-ORDER: Add vertex to stack after visiting all descendants.\n        // This ensures that all vertices that depend on the current vertex\n        // are already in the stack (deeper in the stack).\n        stack.Push(vertex);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs",
    "content": "namespace Algorithms.Knapsack;\n\n/// <summary>\n///     Branch and bound Knapsack solver.\n/// </summary>\n/// <typeparam name=\"T\">Type of items in knapsack.</typeparam>\npublic class BranchAndBoundKnapsackSolver<T>\n{\n    /// <summary>\n    ///     Returns the knapsack containing the items that maximize value while not exceeding weight capacity.\n    ///     Construct a tree structure with total number of items + 1 levels, each node have two child nodes,\n    ///     starting with a dummy item root, each following levels are associated with 1 items, construct the\n    ///     tree in breadth first order to identify the optimal item set.\n    /// </summary>\n    /// <param name=\"items\">All items to choose from.</param>\n    /// <param name=\"capacity\">The maximum weight capacity of the knapsack to be filled.</param>\n    /// <param name=\"weightSelector\">\n    ///     A function that returns the value of the specified item\n    ///     from the <paramref name=\"items\">items</paramref> list.\n    /// </param>\n    /// <param name=\"valueSelector\">\n    ///     A function that returns the weight of the specified item\n    ///     from the <paramref name=\"items\">items</paramref> list.\n    /// </param>\n    /// <returns>\n    ///     The array of items that provides the maximum value of the\n    ///     knapsack without exceeding the specified weight <paramref name=\"capacity\">capacity</paramref>.\n    /// </returns>\n    public T[] Solve(T[] items, int capacity, Func<T, int> weightSelector, Func<T, double> valueSelector)\n    {\n        // This is required for greedy approach in upper bound calculation to work.\n        items = items.OrderBy(i => valueSelector(i) / weightSelector(i)).ToArray();\n\n        // nodesQueue --> used to construct tree in breadth first order\n        Queue<BranchAndBoundNode> nodesQueue = new();\n\n        // maxCumulativeValue --> maximum value while not exceeding weight capacity.\n        var maxCumulativeValue = 0.0;\n\n        // starting node, associated with a temporary created dummy item\n        BranchAndBoundNode root = new(level: -1, taken: false);\n\n        // lastNodeOfOptimalPat --> last item in the optimal item sets identified by this algorithm\n        BranchAndBoundNode lastNodeOfOptimalPath = root;\n\n        nodesQueue.Enqueue(root);\n\n        while (nodesQueue.Count != 0)\n        {\n            // parent --> parent node which represents the previous item, may or may not be taken into the knapsack\n            BranchAndBoundNode parent = nodesQueue.Dequeue();\n\n            // IF it is the last level, branching cannot be performed\n            if (parent.Level == items.Length - 1)\n            {\n                continue;\n            }\n\n            // create a child node where the associated item is taken into the knapsack\n            var left = new BranchAndBoundNode(parent.Level + 1, true, parent);\n\n            // create a child node where the associated item is not taken into the knapsack\n            var right = new BranchAndBoundNode(parent.Level + 1, false, parent);\n\n            // Since the associated item on current level is taken for the first node,\n            // set the cumulative weight of first node to cumulative weight of parent node + weight of the associated item,\n            // set the cumulative value of first node to cumulative value of parent node + value of current level's item.\n            left.CumulativeWeight = parent.CumulativeWeight + weightSelector(items[left.Level]);\n            left.CumulativeValue = parent.CumulativeValue + valueSelector(items[left.Level]);\n            right.CumulativeWeight = parent.CumulativeWeight;\n            right.CumulativeValue = parent.CumulativeValue;\n\n            // IF cumulative weight is smaller than the weight capacity of the knapsack AND\n            // current cumulative value is larger then the current maxCumulativeValue, update the maxCumulativeValue\n            if (left.CumulativeWeight <= capacity && left.CumulativeValue > maxCumulativeValue)\n            {\n                maxCumulativeValue = left.CumulativeValue;\n                lastNodeOfOptimalPath = left;\n            }\n\n            left.UpperBound = ComputeUpperBound(left, items, capacity, weightSelector, valueSelector);\n            right.UpperBound = ComputeUpperBound(right, items, capacity, weightSelector, valueSelector);\n\n            // IF upperBound of this node is larger than maxCumulativeValue,\n            // the current path is still possible to reach or surpass the maximum value,\n            // add current node to nodesQueue so that nodes below it can be further explored\n            if (left.UpperBound > maxCumulativeValue && left.CumulativeWeight < capacity)\n            {\n                nodesQueue.Enqueue(left);\n            }\n\n            // Cumulative weight is the same as for parent node and < capacity\n            if (right.UpperBound > maxCumulativeValue)\n            {\n                nodesQueue.Enqueue(right);\n            }\n        }\n\n        return GetItemsFromPath(items, lastNodeOfOptimalPath);\n    }\n\n    // determine items taken based on the path\n    private static T[] GetItemsFromPath(T[] items, BranchAndBoundNode lastNodeOfPath)\n    {\n        List<T> takenItems = [];\n\n        // only bogus initial node has no parent\n        for (var current = lastNodeOfPath; current.Parent is not null; current = current.Parent)\n        {\n            if (current.IsTaken)\n            {\n                takenItems.Add(items[current.Level]);\n            }\n        }\n\n        return takenItems.ToArray();\n    }\n\n    /// <summary>\n    ///     Returns the upper bound value of a given node.\n    /// </summary>\n    /// <param name=\"aNode\">The given node.</param>\n    /// <param name=\"items\">All items to choose from.</param>\n    /// <param name=\"capacity\">The maximum weight capacity of the knapsack to be filled.</param>\n    /// <param name=\"weightSelector\">\n    ///     A function that returns the value of the specified item\n    ///     from the <paramref name=\"items\">items</paramref> list.\n    /// </param>\n    /// <param name=\"valueSelector\">\n    ///     A function that returns the weight of the specified item\n    ///     from the <paramref name=\"items\">items</paramref> list.\n    /// </param>\n    /// <returns>\n    ///     upper bound value of the given <paramref name=\"aNode\">node</paramref>.\n    /// </returns>\n    private static double ComputeUpperBound(BranchAndBoundNode aNode, T[] items, int capacity, Func<T, int> weightSelector, Func<T, double> valueSelector)\n    {\n        var upperBound = aNode.CumulativeValue;\n        var availableWeight = capacity - aNode.CumulativeWeight;\n        var nextLevel = aNode.Level + 1;\n\n        while (availableWeight > 0 && nextLevel < items.Length)\n        {\n            if (weightSelector(items[nextLevel]) <= availableWeight)\n            {\n                upperBound += valueSelector(items[nextLevel]);\n                availableWeight -= weightSelector(items[nextLevel]);\n            }\n            else\n            {\n                upperBound += valueSelector(items[nextLevel]) / weightSelector(items[nextLevel]) * availableWeight;\n                availableWeight = 0;\n            }\n\n            nextLevel++;\n        }\n\n        return upperBound;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Knapsack/BranchAndBoundNode.cs",
    "content": "namespace Algorithms.Knapsack;\n\npublic class BranchAndBoundNode(int level, bool taken, BranchAndBoundNode? parent = null)\n{\n    // isTaken --> true = the item where index = level is taken, vice versa\n    public bool IsTaken { get; } = taken;\n\n    // cumulativeWeight --> um of weight of item associated in each nodes starting from root to this node (only item that is taken)\n    public int CumulativeWeight { get; set; }\n\n    // cumulativeValue --> sum of value of item associated in each nodes starting from root to this node (only item that is taken)\n    public double CumulativeValue { get; set; }\n\n    // upperBound --> largest possible value after taking/not taking the item associated to this node (fractional)\n    public double UpperBound { get; set; }\n\n    // level --> level of the node in the tree structure\n    public int Level { get; } = level;\n\n    // parent node\n    public BranchAndBoundNode? Parent { get; } = parent;\n}\n"
  },
  {
    "path": "Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs",
    "content": "namespace Algorithms.Knapsack;\n\n/// <summary>\n///     Dynamic Programming Knapsack solver.\n/// </summary>\n/// <typeparam name=\"T\">Type of items in knapsack.</typeparam>\npublic class DynamicProgrammingKnapsackSolver<T>\n{\n    /// <summary>\n    ///     Returns the knapsack containing the items that\n    ///     maximize value while not exceeding weight capacity.\n    /// </summary>\n    /// <param name=\"items\">The list of items from which we select ones to be in the knapsack.</param>\n    /// <param name=\"capacity\">\n    ///     The maximum weight capacity of the knapsack\n    ///     to be filled. Only integer values of this capacity are tried. If\n    ///     a greater resolution is needed, multiply the\n    ///     weights/capacity by a factor of 10.\n    /// </param>\n    /// <param name=\"weightSelector\">\n    ///     A function that returns the value of the specified item\n    ///     from the <paramref name=\"items\">items</paramref> list.\n    /// </param>\n    /// <param name=\"valueSelector\">\n    ///     A function that returns the weight of the specified item\n    ///     from the <paramref name=\"items\">items</paramref> list.\n    /// </param>\n    /// <returns>\n    ///     The array of items that provides the maximum value of the\n    ///     knapsack without exceeding the specified weight <paramref name=\"capacity\">capacity</paramref>.\n    /// </returns>\n    public T[] Solve(T[] items, int capacity, Func<T, int> weightSelector, Func<T, double> valueSelector)\n    {\n        var cache = Tabulate(items, weightSelector, valueSelector, capacity);\n        return GetOptimalItems(items, weightSelector, cache, capacity);\n    }\n\n    private static T[] GetOptimalItems(T[] items, Func<T, int> weightSelector, double[,] cache, int capacity)\n    {\n        var currentCapacity = capacity;\n\n        var result = new List<T>();\n        for (var i = items.Length - 1; i >= 0; i--)\n        {\n            if (cache[i + 1, currentCapacity] > cache[i, currentCapacity])\n            {\n                var item = items[i];\n                result.Add(item);\n                currentCapacity -= weightSelector(item);\n            }\n        }\n\n        result.Reverse(); // we added items back to front\n        return result.ToArray();\n    }\n\n    private static double[,] Tabulate(\n        T[] items,\n        Func<T, int> weightSelector,\n        Func<T, double> valueSelector,\n        int maxCapacity)\n    {\n        // Store the incremental results in a bottom up manner\n        var n = items.Length;\n        var results = new double[n + 1, maxCapacity + 1];\n        for (var i = 0; i <= n; i++)\n        {\n            for (var w = 0; w <= maxCapacity; w++)\n            {\n                if (i == 0 || w == 0)\n                {\n                    // If we have no items to take, or\n                    // if we have no capacity in our knapsack\n                    // we cannot possibly have any value\n                    results[i, w] = 0;\n                }\n                else if (weightSelector(items[i - 1]) <= w)\n                {\n                    // Decide if it is better to take or not take this item\n                    var iut = items[i - 1]; // iut = Item under test\n                    var vut = valueSelector(iut); // vut = Value of item under test\n                    var wut = weightSelector(iut); // wut = Weight of item under test\n                    var valueIfTaken = vut + results[i - 1, w - wut];\n                    var valueIfNotTaken = results[i - 1, w];\n                    results[i, w] = Math.Max(valueIfTaken, valueIfNotTaken);\n                }\n                else\n                {\n                    // There is not enough room to take this item\n                    results[i, w] = results[i - 1, w];\n                }\n            }\n        }\n\n        return results;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Knapsack/IHeuristicKnapsackSolver.cs",
    "content": "namespace Algorithms.Knapsack;\n\n/// <summary>\n///     Solves knapsack problem using some heuristics\n///     Sum of values of taken items -> max\n///     Sum of weights of taken items. &lt;= capacity.\n/// </summary>\n/// <typeparam name=\"T\">Type of items in knapsack.</typeparam>\npublic interface IHeuristicKnapsackSolver<T>\n{\n    /// <summary>\n    ///     Solves knapsack problem using some heuristics\n    ///     Sum of values of taken items -> max\n    ///     Sum of weights of taken items. &lt;= capacity.\n    /// </summary>\n    /// <param name=\"items\">All items to choose from.</param>\n    /// <param name=\"capacity\">How much weight we can take.</param>\n    /// <param name=\"weightSelector\">Maps item to its weight.</param>\n    /// <param name=\"valueSelector\">Maps item to its value.</param>\n    /// <returns>Items that were chosen.</returns>\n    T[] Solve(T[] items, double capacity, Func<T, double> weightSelector, Func<T, double> valueSelector);\n}\n"
  },
  {
    "path": "Algorithms/Knapsack/IKnapsackSolver.cs",
    "content": "namespace Algorithms.Knapsack;\n\n/// <summary>\n///     Solves knapsack problem:\n///     to maximize sum of values of taken items,\n///     while sum of weights of taken items is less than capacity.\n/// </summary>\n/// <typeparam name=\"T\">Type of items in knapsack.</typeparam>\npublic interface IKnapsackSolver<T> : IHeuristicKnapsackSolver<T>\n{\n}\n"
  },
  {
    "path": "Algorithms/Knapsack/NaiveKnapsackSolver.cs",
    "content": "namespace Algorithms.Knapsack;\n\n/// <summary>\n///     Greedy heurictic solver.\n/// </summary>\n/// <typeparam name=\"T\">Type of items in knapsack.</typeparam>\npublic class NaiveKnapsackSolver<T> : IHeuristicKnapsackSolver<T>\n{\n    /// <summary>\n    ///     Solves the knapsack problem using a naive greedy approach.\n    ///     Items are added in order until capacity is reached.\n    /// </summary>\n    /// <param name=\"items\">Array of items to consider for the knapsack.</param>\n    /// <param name=\"capacity\">Maximum weight capacity of the knapsack.</param>\n    /// <param name=\"weightSelector\">Function to get the weight of an item.</param>\n    /// <param name=\"valueSelector\">Function to get the value of an item.</param>\n    /// <returns>Array of items that fit in the knapsack.</returns>\n    public T[] Solve(T[] items, double capacity, Func<T, double> weightSelector, Func<T, double> valueSelector)\n    {\n        var weight = 0d;\n        var left = new List<T>();\n\n        foreach (var item in items)\n        {\n            var weightDelta = weightSelector(item);\n            if (weight + weightDelta <= capacity)\n            {\n                weight += weightDelta;\n                left.Add(item);\n            }\n        }\n\n        return left.ToArray();\n    }\n}\n"
  },
  {
    "path": "Algorithms/LinearAlgebra/Distances/Chebyshev.cs",
    "content": "namespace Algorithms.LinearAlgebra.Distances;\n\n/// <summary>\n/// Implementation of Chebyshev distance.\n/// It is the maximum absolute difference between the measures in all dimensions of two points.\n/// In other words, it is the maximum distance one has to travel along any coordinate axis to get from one point to another.\n///\n/// It is commonly used in various fields such as chess, warehouse logistics, and more.\n/// </summary>\npublic static class Chebyshev\n{\n    /// <summary>\n    /// Calculate Chebyshev distance for two N-Dimensional points.\n    /// </summary>\n    /// <param name=\"point1\">First N-Dimensional point.</param>\n    /// <param name=\"point2\">Second N-Dimensional point.</param>\n    /// <returns>Calculated Chebyshev distance.</returns>\n    public static double Distance(double[] point1, double[] point2)\n    {\n        if (point1.Length != point2.Length)\n        {\n            throw new ArgumentException(\"Both points should have the same dimensionality\");\n        }\n\n        // distance = max(|x1-y1|, |x2-y2|, ..., |xn-yn|)\n        return point1.Zip(point2, (x1, x2) => Math.Abs(x1 - x2)).Max();\n    }\n}\n"
  },
  {
    "path": "Algorithms/LinearAlgebra/Distances/Euclidean.cs",
    "content": "namespace Algorithms.LinearAlgebra.Distances;\n\n/// <summary>\n/// Implementation for Euclidean distance.\n/// </summary>\npublic static class Euclidean\n{\n    /// <summary>\n    /// Calculate Euclidean distance for two N-Dimensional points.\n    /// </summary>\n    /// <param name=\"point1\">First N-Dimensional point.</param>\n    /// <param name=\"point2\">Second N-Dimensional point.</param>\n    /// <returns>Calculated Euclidean distance.</returns>\n    public static double Distance(double[] point1, double[] point2)\n    {\n        if (point1.Length != point2.Length)\n        {\n            throw new ArgumentException(\"Both points should have the same dimensionality\");\n        }\n\n        // distance = sqrt((x1-y1)^2 + (x2-y2)^2 + ... + (xn-yn)^2)\n        return Math.Sqrt(point1.Zip(point2, (x1, x2) => (x1 - x2) * (x1 - x2)).Sum());\n    }\n}\n"
  },
  {
    "path": "Algorithms/LinearAlgebra/Distances/Manhattan.cs",
    "content": "namespace Algorithms.LinearAlgebra.Distances;\n\n/// <summary>\n/// Implementation fo Manhattan distance.\n/// It is the sum of the lengths of the projections of the line segment between the points onto the coordinate axes.\n/// In other words, it is the sum of absolute difference between the measures in all dimensions of two points.\n///\n/// Its commonly used in regression analysis.\n/// </summary>\npublic static class Manhattan\n{\n    /// <summary>\n    /// Calculate Manhattan distance for two N-Dimensional points.\n    /// </summary>\n    /// <param name=\"point1\">First N-Dimensional point.</param>\n    /// <param name=\"point2\">Second N-Dimensional point.</param>\n    /// <returns>Calculated Manhattan distance.</returns>\n    public static double Distance(double[] point1, double[] point2)\n    {\n        if (point1.Length != point2.Length)\n        {\n            throw new ArgumentException(\"Both points should have the same dimensionality\");\n        }\n\n        // distance = |x1-y1| + |x2-y2| + ... + |xn-yn|\n        return point1.Zip(point2, (x1, x2) => Math.Abs(x1 - x2)).Sum();\n    }\n}\n"
  },
  {
    "path": "Algorithms/LinearAlgebra/Distances/Minkowski.cs",
    "content": "namespace Algorithms.LinearAlgebra.Distances;\n\n/// <summary>\n/// Implementation of Minkowski distance.\n/// It is the sum of the lengths of the projections of the line segment between the points onto the\n/// coordinate axes, raised to the power of the order and then taking the p-th root.\n/// For the case of order = 1, the Minkowski distance degenerates to the Manhattan distance,\n/// for order = 2, the usual Euclidean distance is obtained and for order = infinity, the Chebyshev distance is obtained.\n/// </summary>\npublic static class Minkowski\n{\n    /// <summary>\n    /// Calculate Minkowski distance for two N-Dimensional points.\n    /// </summary>\n    /// <param name=\"point1\">First N-Dimensional point.</param>\n    /// <param name=\"point2\">Second N-Dimensional point.</param>\n    /// <param name=\"order\">Order of the Minkowski distance.</param>\n    /// <returns>Calculated Minkowski distance.</returns>\n    public static double Distance(double[] point1, double[] point2, int order)\n    {\n        if (order < 1)\n        {\n            throw new ArgumentException(\"The order must be greater than or equal to 1.\");\n        }\n\n        if (point1.Length != point2.Length)\n        {\n            throw new ArgumentException(\"Both points should have the same dimensionality\");\n        }\n\n        // distance = (|x1-y1|^p + |x2-y2|^p + ... + |xn-yn|^p)^(1/p)\n        return Math.Pow(point1.Zip(point2, (x1, x2) => Math.Pow(Math.Abs(x1 - x2), order)).Sum(), 1.0 / order);\n    }\n}\n"
  },
  {
    "path": "Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs",
    "content": "namespace Algorithms.LinearAlgebra.Eigenvalue;\n\n/// <summary>\n///     Power iteration method - eigenvalue numeric algorithm, based on recurrent relation:\n///     Li+1 = (A * Li) / || A * Li ||, where Li - eigenvector approximation.\n/// </summary>\npublic static class PowerIteration\n{\n    /// <summary>\n    ///     Returns approximation of the dominant eigenvalue and eigenvector of <paramref name=\"source\" /> matrix.\n    /// </summary>\n    /// <list type=\"bullet\">\n    ///     <item>\n    ///         <description>The algorithm will not converge if the start vector is orthogonal to the eigenvector.</description>\n    ///     </item>\n    ///     <item>\n    ///         <description>The <paramref name=\"source\" /> matrix must be square-shaped.</description>\n    ///     </item>\n    /// </list>\n    /// <param name=\"source\">Source square-shaped matrix.</param>\n    /// <param name=\"startVector\">Start vector.</param>\n    /// <param name=\"error\">Accuracy of the result.</param>\n    /// <returns>Dominant eigenvalue and eigenvector pair.</returns>\n    /// <exception cref=\"ArgumentException\">The <paramref name=\"source\" /> matrix is not square-shaped.</exception>\n    /// <exception cref=\"ArgumentException\">The length of the start vector doesn't equal the size of the source matrix.</exception>\n    public static (double Eigenvalue, double[] Eigenvector) Dominant(\n        double[,] source,\n        double[] startVector,\n        double error = 0.00001)\n    {\n        if (source.GetLength(0) != source.GetLength(1))\n        {\n            throw new ArgumentException(\"The source matrix is not square-shaped.\");\n        }\n\n        if (source.GetLength(0) != startVector.Length)\n        {\n            throw new ArgumentException(\n                \"The length of the start vector doesn't equal the size of the source matrix.\");\n        }\n\n        double eigenNorm;\n        double[] previousEigenVector;\n        double[] currentEigenVector = startVector;\n\n        do\n        {\n            previousEigenVector = currentEigenVector;\n            currentEigenVector = source.Multiply(\n                    previousEigenVector.ToColumnVector())\n                .ToRowVector();\n\n            eigenNorm = currentEigenVector.Magnitude();\n            currentEigenVector = currentEigenVector.Select(x => x / eigenNorm).ToArray();\n        }\n        while (Math.Abs(currentEigenVector.Dot(previousEigenVector)) < 1.0 - error);\n\n        var eigenvalue = source.Multiply(currentEigenVector.ToColumnVector()).ToRowVector().Magnitude();\n\n        return (eigenvalue, Eigenvector: currentEigenVector);\n    }\n\n    /// <summary>\n    ///     Returns approximation of the dominant eigenvalue and eigenvector of <paramref name=\"source\" /> matrix.\n    ///     Random normalized vector is used as the start vector to decrease chance of orthogonality to the eigenvector.\n    /// </summary>\n    /// <list type=\"bullet\">\n    ///     <item>\n    ///         <description>The algorithm will not converge if the start vector is orthogonal to the eigenvector.</description>\n    ///     </item>\n    ///     <item>\n    ///         <description>The <paramref name=\"source\" /> matrix should be square-shaped.</description>\n    ///     </item>\n    /// </list>\n    /// <param name=\"source\">Source square-shaped matrix.</param>\n    /// <param name=\"error\">Accuracy of the result.</param>\n    /// <returns>Dominant eigenvalue and eigenvector pair.</returns>\n    /// <exception cref=\"ArgumentException\">The <paramref name=\"source\" /> matrix is not square-shaped.</exception>\n    /// <exception cref=\"ArgumentException\">The length of the start vector doesn't equal the size of the source matrix.</exception>\n    public static (double Eigenvalue, double[] Eigenvector) Dominant(double[,] source, double error = 0.00001) =>\n        Dominant(source, new Random().NextVector(source.GetLength(1)), error);\n}\n"
  },
  {
    "path": "Algorithms/MachineLearning/KNearestNeighbors.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Algorithms.MachineLearning;\n\n/// <summary>\n/// K-Nearest Neighbors (KNN) classifier implementation.\n/// This algorithm classifies data points based on the majority label of their k nearest neighbors.\n/// </summary>\n/// <typeparam name=\"TLabel\">\n/// The type of the label used for classification. This can be any type that represents the class or category of a sample.\n/// </typeparam>\npublic class KNearestNeighbors<TLabel>\n{\n    private readonly List<(double[] Features, TLabel Label)> trainingData = new();\n    private readonly int k;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"KNearestNeighbors{TLabel}\"/> classifier.\n    /// </summary>\n    /// <param name=\"k\">Number of neighbors to consider for classification.</param>\n    /// <exception cref=\"ArgumentOutOfRangeException\">Thrown if k is less than 1.</exception>\n    public KNearestNeighbors(int k)\n    {\n        if (k < 1)\n        {\n            throw new ArgumentOutOfRangeException(nameof(k), \"k must be at least 1.\");\n        }\n\n        this.k = k;\n    }\n\n    /// <summary>\n    /// Calculates the Euclidean distance between two feature vectors.\n    /// </summary>\n    /// <param name=\"a\">First feature vector.</param>\n    /// <param name=\"b\">Second feature vector.</param>\n    /// <returns>Euclidean distance.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown if vectors are of different lengths.</exception>\n    public static double EuclideanDistance(double[] a, double[] b)\n    {\n        if (a.Length != b.Length)\n        {\n            throw new ArgumentException(\"Feature vectors must be of the same length.\");\n        }\n\n        double sum = 0;\n        for (int i = 0; i < a.Length; i++)\n        {\n            double diff = a[i] - b[i];\n            sum += diff * diff;\n        }\n\n        return Math.Sqrt(sum);\n    }\n\n    /// <summary>\n    /// Adds a training sample to the classifier.\n    /// </summary>\n    /// <param name=\"features\">Feature vector of the sample.</param>\n    /// <param name=\"label\">Label of the sample.</param>\n    public void AddSample(double[] features, TLabel label)\n    {\n        if (features == null)\n        {\n            throw new ArgumentNullException(nameof(features));\n        }\n\n        trainingData.Add((features, label));\n    }\n\n    /// <summary>\n    /// Predicts the label for a given feature vector using the KNN algorithm.\n    /// </summary>\n    /// <param name=\"features\">Feature vector to classify.</param>\n    /// <returns>Predicted label.</returns>\n    /// <exception cref=\"InvalidOperationException\">Thrown if there is no training data.</exception>\n    public TLabel Predict(double[] features)\n    {\n        if (trainingData.Count == 0)\n        {\n            throw new InvalidOperationException(\"No training data available.\");\n        }\n\n        if (features == null)\n        {\n            throw new ArgumentNullException(nameof(features));\n        }\n\n        // Compute distances to all training samples\n        var distances = trainingData\n            .Select(td => (Label: td.Label, Distance: EuclideanDistance(features, td.Features)))\n            .OrderBy(x => x.Distance)\n            .Take(k)\n            .ToList();\n\n        // Majority vote\n        var labelCounts = distances\n            .GroupBy(x => x.Label)\n            .Select(g => new { Label = g.Key, Count = g.Count(), MinDistance = g.Min(item => item.Distance) })\n            .OrderByDescending(x => x.Count)\n            .ThenBy(x => x.MinDistance)\n            .ToList();\n\n        return labelCounts.First().Label;\n    }\n}\n"
  },
  {
    "path": "Algorithms/MachineLearning/LinearRegression.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Algorithms.MachineLearning;\n\n/// <summary>\n/// Implements simple linear regression for one independent variable (univariate).\n/// Linear regression is a supervised learning algorithm used to model the relationship\n/// between a scalar dependent variable (Y) and an independent variable (X).\n/// The model fits a line: Y = a + bX, where 'a' is the intercept and 'b' is the slope.\n/// </summary>\npublic class LinearRegression\n{\n    // Intercept (a) and slope (b) of the fitted line\n    public double Intercept { get; private set; }\n\n    public double Slope { get; private set; }\n\n    public bool IsFitted { get; private set; }\n\n    /// <summary>\n    /// Fits the linear regression model to the provided data.\n    /// </summary>\n    /// <param name=\"x\">List of independent variable values.</param>\n    /// <param name=\"y\">List of dependent variable values.</param>\n    /// <exception cref=\"ArgumentException\">Thrown if input lists are null, empty, or of different lengths.</exception>\n    public void Fit(IList<double> x, IList<double> y)\n    {\n        if (x == null || y == null)\n        {\n            throw new ArgumentException(\"Input data cannot be null.\");\n        }\n\n        if (x.Count == 0 || y.Count == 0)\n        {\n            throw new ArgumentException(\"Input data cannot be empty.\");\n        }\n\n        if (x.Count != y.Count)\n        {\n            throw new ArgumentException(\"Input lists must have the same length.\");\n        }\n\n        // Calculate means\n        double xMean = x.Average();\n        double yMean = y.Average();\n\n        // Calculate slope (b) and intercept (a)\n        double numerator = 0.0;\n        double denominator = 0.0;\n        for (int i = 0; i < x.Count; i++)\n        {\n            numerator += (x[i] - xMean) * (y[i] - yMean);\n            denominator += (x[i] - xMean) * (x[i] - xMean);\n        }\n\n        const double epsilon = 1e-12;\n        if (Math.Abs(denominator) < epsilon)\n        {\n            throw new ArgumentException(\"Variance of X must not be zero.\");\n        }\n\n        Slope = numerator / denominator;\n        Intercept = yMean - Slope * xMean;\n        IsFitted = true;\n    }\n\n    /// <summary>\n    /// Predicts the output value for a given input using the fitted model.\n    /// </summary>\n    /// <param name=\"x\">Input value.</param>\n    /// <returns>Predicted output value.</returns>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the model is not fitted.</exception>\n    public double Predict(double x)\n    {\n        if (!IsFitted)\n        {\n            throw new InvalidOperationException(\"Model must be fitted before prediction.\");\n        }\n\n        return Intercept + Slope * x;\n    }\n\n    /// <summary>\n    /// Predicts output values for a list of inputs using the fitted model.\n    /// </summary>\n    /// <param name=\"xValues\">List of input values.</param>\n    /// <returns>List of predicted output values.</returns>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the model is not fitted.</exception>\n    public IList<double> Predict(IList<double> xValues)\n    {\n        if (!IsFitted)\n        {\n            throw new InvalidOperationException(\"Model must be fitted before prediction.\");\n        }\n\n        return xValues.Select(Predict).ToList();\n    }\n}\n"
  },
  {
    "path": "Algorithms/MachineLearning/LogisticRegression.cs",
    "content": "using System;\nusing System.Linq;\n\nnamespace Algorithms.MachineLearning;\n\n/// <summary>\n/// Logistic Regression for binary classification.\n/// </summary>\npublic class LogisticRegression\n{\n    private double[] weights = [];\n    private double bias;\n\n    public int FeatureCount => weights.Length;\n\n    /// <summary>\n    /// Fit the model using gradient descent.\n    /// </summary>\n    /// <param name=\"x\">2D array of features (samples x features).</param>\n    /// <param name=\"y\">Array of labels (0 or 1).</param>\n    /// <param name=\"epochs\">Number of iterations.</param>\n    /// <param name=\"learningRate\">Step size.</param>\n    public void Fit(double[][] x, int[] y, int epochs = 1000, double learningRate = 0.01)\n    {\n        if (x.Length == 0 || x[0].Length == 0)\n        {\n            throw new ArgumentException(\"Input features cannot be empty.\");\n        }\n\n        if (x.Length != y.Length)\n        {\n            throw new ArgumentException(\"Number of samples and labels must match.\");\n        }\n\n        int nSamples = x.Length;\n        int nFeatures = x[0].Length;\n        weights = new double[nFeatures];\n        bias = 0;\n\n        for (int epoch = 0; epoch < epochs; epoch++)\n        {\n            double[] dw = new double[nFeatures];\n            double db = 0;\n            for (int i = 0; i < nSamples; i++)\n            {\n                double linear = Dot(x[i], weights) + bias;\n                double pred = Sigmoid(linear);\n                double error = pred - y[i];\n                for (int j = 0; j < nFeatures; j++)\n                {\n                    dw[j] += error * x[i][j];\n                }\n\n                db += error;\n            }\n\n            for (int j = 0; j < nFeatures; j++)\n            {\n                weights[j] -= learningRate * dw[j] / nSamples;\n            }\n\n            bias -= learningRate * db / nSamples;\n        }\n    }\n\n    /// <summary>\n    /// Predict probability for a single sample.\n    /// </summary>\n    public double PredictProbability(double[] x)\n    {\n        if (x.Length != weights.Length)\n        {\n            throw new ArgumentException(\"Feature count mismatch.\");\n        }\n\n        return Sigmoid(Dot(x, weights) + bias);\n    }\n\n    /// <summary>\n    /// Predict class label (0 or 1) for a single sample.\n    /// </summary>\n    public int Predict(double[] x) => PredictProbability(x) >= 0.5 ? 1 : 0;\n\n    private static double Sigmoid(double z) => 1.0 / (1.0 + Math.Exp(-z));\n\n    private static double Dot(double[] a, double[] b) => a.Zip(b).Sum(pair => pair.First * pair.Second);\n}\n"
  },
  {
    "path": "Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs",
    "content": "namespace Algorithms.ModularArithmetic;\n\n/// <summary>\n/// Chinese Remainder Theorem: https://en.wikipedia.org/wiki/Chinese_remainder_theorem.\n/// </summary>\npublic static class ChineseRemainderTheorem\n{\n    /// <summary>\n    ///     The Chinese Remainder Theorem is used to compute x for given set of pairs of integers (a_i, n_i) with:\n    ///     <list type=\"bullet\">\n    ///         <item>x = a_0 mod n_0</item>\n    ///         <item>x = a_1 mod n_1</item>\n    ///         <item>...</item>\n    ///         <item>x = a_k mod n_k</item>\n    ///     </list>\n    ///     for 0 &lt;= i &lt; k, for some positive integer k. Additional requirements are:\n    ///     <list type=\"bullet\">\n    ///         <item>n_i > 1 for 0 &lt;= i &lt; k</item>\n    ///         <item>n_i and n_j are coprime, for all 0 &lt;= i &lt; j &lt; k</item>\n    ///         <item>0 &lt;= a_i &lt; n_i, for all 0 &lt;= i &lt; k</item>\n    ///         <item>0 &lt;= x &lt; n_0 * n_1 * ... * n_(k-1)</item>\n    ///     </list>\n    /// </summary>\n    /// <param name=\"listOfAs\">An ordered list of a_0, a_1, ..., a_k.</param>\n    /// <param name=\"listOfNs\">An ordered list of n_0, n_1, ..., n_k.</param>\n    /// <returns>The value x.</returns>\n    /// <exception cref=\"ArgumentException\">If any of the requirements is not fulfilled.</exception>\n    public static long Compute(List<long> listOfAs, List<long> listOfNs)\n    {\n        // Check the requirements for this algorithm:\n        CheckRequirements(listOfAs, listOfNs);\n\n        // For performance-reasons compute the product of all n_i as prodN, because we're going to need access to (prodN / n_i) for all i:\n        var prodN = 1L;\n        foreach (var n in listOfNs)\n        {\n            prodN *= n;\n        }\n\n        var result = 0L;\n        for (var i = 0; i < listOfNs.Count; i++)\n        {\n            var a_i = listOfAs[i];\n            var n_i = listOfNs[i];\n            var modulus_i = prodN / n_i;\n\n            var bezout_modulus_i = ExtendedEuclideanAlgorithm.Compute(n_i, modulus_i).BezoutB;\n            result += a_i * bezout_modulus_i * modulus_i;\n        }\n\n        // Make sure, result is in [0, prodN).\n        result %= prodN;\n        if (result < 0)\n        {\n            result += prodN;\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     The Chinese Remainder Theorem is used to compute x for given set of pairs of integers (a_i, n_i) with:\n    ///     <list type=\"bullet\">\n    ///         <item>x = a_0 mod n_0</item>\n    ///         <item>x = a_1 mod n_1</item>\n    ///         <item>...</item>\n    ///         <item>x = a_k mod n_k</item>\n    ///     </list>\n    ///     for 0 &lt;= i &lt; k, for some positive integer k. Additional requirements are:\n    ///     <list type=\"bullet\">\n    ///         <item>n_i > 1 for 0 &lt;= i &lt; k</item>\n    ///         <item>n_i and n_j are coprime, for all 0 &lt;= i &lt; j &lt; k</item>\n    ///         <item>0 &lt;= a_i &lt; n_i, for all 0 &lt;= i &lt; k</item>\n    ///         <item>0 &lt;= x &lt; n_0 * n_1 * ... * n_(k-1)</item>\n    ///     </list>\n    /// </summary>\n    /// <param name=\"listOfAs\">An ordered list of a_0, a_1, ..., a_k.</param>\n    /// <param name=\"listOfNs\">An ordered list of n_0, n_1, ..., n_k.</param>\n    /// <returns>The value x.</returns>\n    /// <exception cref=\"ArgumentException\">If any of the requirements is not fulfilled.</exception>\n    public static BigInteger Compute(List<BigInteger> listOfAs, List<BigInteger> listOfNs)\n    {\n        // Check the requirements for this algorithm:\n        CheckRequirements(listOfAs, listOfNs);\n\n        // For performance-reasons compute the product of all n_i as prodN, because we're going to need access to (prodN / n_i) for all i:\n        var prodN = BigInteger.One;\n        foreach (var n in listOfNs)\n        {\n            prodN *= n;\n        }\n\n        var result = BigInteger.Zero;\n        for (var i = 0; i < listOfNs.Count; i++)\n        {\n            var a_i = listOfAs[i];\n            var n_i = listOfNs[i];\n            var modulus_i = prodN / n_i;\n\n            var bezout_modulus_i = ExtendedEuclideanAlgorithm.Compute(n_i, modulus_i).BezoutB;\n            result += a_i * bezout_modulus_i * modulus_i;\n        }\n\n        // Make sure, result is in [0, prodN).\n        result %= prodN;\n        if (result < 0)\n        {\n            result += prodN;\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    /// Checks the requirements for the algorithm and throws an ArgumentException if they are not being met.\n    /// </summary>\n    /// <param name=\"listOfAs\">An ordered list of a_0, a_1, ..., a_k.</param>\n    /// <param name=\"listOfNs\">An ordered list of n_0, n_1, ..., n_k.</param>\n    /// <exception cref=\"ArgumentException\">If any of the requirements is not fulfilled.</exception>\n    private static void CheckRequirements(List<long> listOfAs, List<long> listOfNs)\n    {\n        if (listOfAs == null || listOfNs == null || listOfAs.Count != listOfNs.Count)\n        {\n            throw new ArgumentException(\"The parameters 'listOfAs' and 'listOfNs' must not be null and have to be of equal length!\");\n        }\n\n        if (listOfNs.Any(x => x <= 1))\n        {\n            throw new ArgumentException($\"The value {listOfNs.First(x => x <= 1)} for some n_i is smaller than or equal to 1.\");\n        }\n\n        if (listOfAs.Any(x => x < 0))\n        {\n            throw new ArgumentException($\"The value {listOfAs.First(x => x < 0)} for some a_i is smaller than 0.\");\n        }\n\n        // Check if all pairs of (n_i, n_j) are coprime:\n        for (var i = 0; i < listOfNs.Count; i++)\n        {\n            for (var j = i + 1; j < listOfNs.Count; j++)\n            {\n                long gcd;\n                if ((gcd = ExtendedEuclideanAlgorithm.Compute(listOfNs[i], listOfNs[j]).Gcd) != 1L)\n                {\n                    throw new ArgumentException($\"The GCD of n_{i} = {listOfNs[i]} and n_{j} = {listOfNs[j]} equals {gcd} and thus these values aren't coprime.\");\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Checks the requirements for the algorithm and throws an ArgumentException if they are not being met.\n    /// </summary>\n    /// <param name=\"listOfAs\">An ordered list of a_0, a_1, ..., a_k.</param>\n    /// <param name=\"listOfNs\">An ordered list of n_0, n_1, ..., n_k.</param>\n    /// <exception cref=\"ArgumentException\">If any of the requirements is not fulfilled.</exception>\n    private static void CheckRequirements(List<BigInteger> listOfAs, List<BigInteger> listOfNs)\n    {\n        if (listOfAs == null || listOfNs == null || listOfAs.Count != listOfNs.Count)\n        {\n            throw new ArgumentException(\"The parameters 'listOfAs' and 'listOfNs' must not be null and have to be of equal length!\");\n        }\n\n        if (listOfNs.Any(x => x <= 1))\n        {\n            throw new ArgumentException($\"The value {listOfNs.First(x => x <= 1)} for some n_i is smaller than or equal to 1.\");\n        }\n\n        if (listOfAs.Any(x => x < 0))\n        {\n            throw new ArgumentException($\"The value {listOfAs.First(x => x < 0)} for some a_i is smaller than 0.\");\n        }\n\n        // Check if all pairs of (n_i, n_j) are coprime:\n        for (var i = 0; i < listOfNs.Count; i++)\n        {\n            for (var j = i + 1; j < listOfNs.Count; j++)\n            {\n                BigInteger gcd;\n                if ((gcd = ExtendedEuclideanAlgorithm.Compute(listOfNs[i], listOfNs[j]).Gcd) != BigInteger.One)\n                {\n                    throw new ArgumentException($\"The GCD of n_{i} = {listOfNs[i]} and n_{j} = {listOfNs[j]} equals {gcd} and thus these values aren't coprime.\");\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs",
    "content": "namespace Algorithms.ModularArithmetic;\n\n/// <summary>\n///     Extended Euclidean algorithm: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm.\n/// </summary>\npublic static class ExtendedEuclideanAlgorithm\n{\n    /// <summary>\n    ///     Computes the greatest common divisor (Gcd) of integers a and b, also the coefficients of Bézout's identity,\n    ///     which are integers x and y such that a*bezoutCoefficientOfA + b*bezoutCoefficientOfB = Gcd(a, b).\n    /// </summary>\n    /// <param name=\"a\">Input number.</param>\n    /// <param name=\"b\">Second input number.</param>\n    /// <returns>A record of ExtendedEuclideanAlgorithmResult containing the bezout coefficients of a and b as well as the Gcd(a,b).</returns>\n    public static ExtendedEuclideanAlgorithmResult<long> Compute(long a, long b)\n    {\n        long quotient;\n        long tmp;\n        var s = 0L;\n        var bezoutOfA = 1L;\n        var r = b;\n        var gcd = a;\n        var bezoutOfB = 0L;\n\n        while (r != 0)\n        {\n            quotient = gcd / r; // integer division\n\n            tmp = gcd;\n            gcd = r;\n            r = tmp - quotient * r;\n\n            tmp = bezoutOfA;\n            bezoutOfA = s;\n            s = tmp - quotient * s;\n        }\n\n        if (b != 0)\n        {\n            bezoutOfB = (gcd - bezoutOfA * a) / b; // integer division\n        }\n\n        return new ExtendedEuclideanAlgorithmResult<long>(bezoutOfA, bezoutOfB, gcd);\n    }\n\n    /// <summary>\n    ///     Computes the greatest common divisor (Gcd) of integers a and b, also the coefficients of Bézout's identity,\n    ///     which are integers x and y such that a*bezoutCoefficientOfA + b*bezoutCoefficientOfB = Gcd(a, b).\n    /// </summary>\n    /// <param name=\"a\">Input number.</param>\n    /// <param name=\"b\">Second input number.</param>\n    /// <returns>A record of ExtendedEuclideanAlgorithmResult containing the bezout coefficients of a and b as well as the Gcd(a,b).</returns>\n    public static ExtendedEuclideanAlgorithmResult<BigInteger> Compute(BigInteger a, BigInteger b)\n    {\n        BigInteger quotient;\n        BigInteger tmp;\n        var s = BigInteger.Zero;\n        var bezoutOfA = BigInteger.One;\n        var r = b;\n        var gcd = a;\n        var bezoutOfB = BigInteger.Zero;\n\n        while (r != 0)\n        {\n            quotient = gcd / r; // integer division\n\n            tmp = gcd;\n            gcd = r;\n            r = tmp - quotient * r;\n\n            tmp = bezoutOfA;\n            bezoutOfA = s;\n            s = tmp - quotient * s;\n        }\n\n        if (b != 0)\n        {\n            bezoutOfB = (gcd - bezoutOfA * a) / b; // integer division\n        }\n\n        return new ExtendedEuclideanAlgorithmResult<BigInteger>(bezoutOfA, bezoutOfB, gcd);\n    }\n\n    /// <summary>\n    /// The result type for the computation of the Extended Euclidean Algorithm.\n    /// </summary>\n    /// <typeparam name=\"T\">The data type of the computation (i.e. long or BigInteger).</typeparam>\n    /// <param name=\"BezoutA\">The bezout coefficient of the parameter a to the computation.</param>\n    /// <param name=\"BezoutB\">The bezout coefficient of the parameter b to the computation.</param>\n    /// <param name=\"Gcd\">The greatest common divisor of the parameters a and b to the computation.</param>\n    public record ExtendedEuclideanAlgorithmResult<T>(T BezoutA, T BezoutB, T Gcd);\n}\n"
  },
  {
    "path": "Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs",
    "content": "namespace Algorithms.ModularArithmetic;\n\n/// <summary>\n/// Modular multiplicative inverse: https://en.wikipedia.org/wiki/Modular_multiplicative_inverse.\n/// </summary>\npublic static class ModularMultiplicativeInverse\n{\n    /// <summary>\n    ///     Computes the modular multiplicative inverse of a in Z/nZ, if there is any (i.e. if a and n are coprime).\n    /// </summary>\n    /// <param name=\"a\">The number a, of which to compute the multiplicative inverse.</param>\n    /// <param name=\"n\">The modulus n.</param>\n    /// <returns>The multiplicative inverse of a in Z/nZ, a value in the interval [0, n).</returns>\n    /// <exception cref=\"ArithmeticException\">If there exists no multiplicative inverse of a in Z/nZ.</exception>\n    public static long Compute(long a, long n)\n    {\n        var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, n);\n\n        // Check if there is an inverse:\n        if (eeaResult.Gcd != 1)\n        {\n            throw new ArithmeticException($\"{a} is not invertible in Z/{n}Z.\");\n        }\n\n        // Make sure, inverseOfA (i.e. the bezout coefficient of a) is in the interval [0, n).\n        var inverseOfA = eeaResult.BezoutA;\n        if (inverseOfA < 0)\n        {\n            inverseOfA += n;\n        }\n\n        return inverseOfA;\n    }\n\n    /// <summary>\n    ///     Computes the modular multiplicative inverse of a in Z/nZ, if there is any (i.e. if a and n are coprime).\n    /// </summary>\n    /// <param name=\"a\">The number a, of which to compute the multiplicative inverse.</param>\n    /// <param name=\"n\">The modulus n.</param>\n    /// <returns>The multiplicative inverse of a in Z/nZ, a value in the interval [0, n).</returns>\n    /// <exception cref=\"ArithmeticException\">If there exists no multiplicative inverse of a in Z/nZ.</exception>\n    public static BigInteger Compute(BigInteger a, BigInteger n)\n    {\n        var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, n);\n\n        // Check if there is an inverse:\n        if (eeaResult.Gcd != 1)\n        {\n            throw new ArithmeticException($\"{a} is not invertible in Z/{n}Z.\");\n        }\n\n        // Make sure, inverseOfA (i.e. the bezout coefficient of a) is in the interval [0, n).\n        var inverseOfA = eeaResult.BezoutA;\n        if (inverseOfA < 0)\n        {\n            inverseOfA += n;\n        }\n\n        return inverseOfA;\n    }\n}\n"
  },
  {
    "path": "Algorithms/NewtonSquareRoot.cs",
    "content": "﻿namespace Algorithms;\n\npublic static class NewtonSquareRoot\n{\n    public static BigInteger Calculate(BigInteger number)\n    {\n        if (number < 0)\n        {\n            throw new ArgumentException(\"Cannot calculate the square root of a negative number.\");\n        }\n\n        if (number == 0)\n        {\n            return BigInteger.Zero;\n        }\n\n        var bitLength = Convert.ToInt32(Math.Ceiling(BigInteger.Log(number, 2)));\n        BigInteger root = BigInteger.One << (bitLength / 2);\n\n        while (!IsSquareRoot(number, root))\n        {\n            root += number / root;\n            root /= 2;\n        }\n\n        return root;\n    }\n\n    private static bool IsSquareRoot(BigInteger number, BigInteger root)\n    {\n        var lowerBound = root * root;\n        return number >= lowerBound && number <= lowerBound + root + root;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Abs.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     Find the absolute value of a number.\n/// </summary>\npublic static class Abs\n{\n    /// <summary>\n    ///    Returns the absolute value of a number.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of number.</typeparam>\n    /// <param name=\"inputNum\">Number to find the absolute value of.</param>\n    /// <returns>Absolute value of the number.</returns>\n    public static T AbsVal<T>(T inputNum) where T : INumber<T>\n    {\n        return T.IsNegative(inputNum) ? -inputNum : inputNum;\n    }\n\n    /// <summary>\n    ///   Returns the number with the smallest absolute value on the input array.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of number.</typeparam>\n    /// <param name=\"inputNums\">Array of numbers to find the smallest absolute.</param>\n    /// <returns>Smallest absolute number.</returns>\n    public static T AbsMin<T>(T[] inputNums) where T : INumber<T>\n    {\n        if (inputNums.Length == 0)\n        {\n            throw new ArgumentException(\"Array is empty.\");\n        }\n\n        var min = inputNums[0];\n        for (var index = 1; index < inputNums.Length; index++)\n        {\n            var current = inputNums[index];\n            if (AbsVal(current).CompareTo(AbsVal(min)) < 0)\n            {\n                min = current;\n            }\n        }\n\n        return min;\n    }\n\n    /// <summary>\n    ///  Returns the number with the largest absolute value on the input array.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of number.</typeparam>\n    /// <param name=\"inputNums\">Array of numbers to find the largest absolute.</param>\n    /// <returns>Largest absolute number.</returns>\n    public static T AbsMax<T>(T[] inputNums) where T : INumber<T>\n    {\n        if (inputNums.Length == 0)\n        {\n            throw new ArgumentException(\"Array is empty.\");\n        }\n\n        var max = inputNums[0];\n        for (var index = 1; index < inputNums.Length; index++)\n        {\n            var current = inputNums[index];\n            if (AbsVal(current).CompareTo(AbsVal(max)) > 0)\n            {\n                max = current;\n            }\n        }\n\n        return max;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/AdditionWithoutArithmetic.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     Add the integers without arithmetic operation.\n/// </summary>\npublic static class AdditionWithoutArithmetic\n{\n    /// <summary>\n    ///    Returns the sum of two integers.\n    /// </summary>\n    /// <param name=\"first\">First number to add.</param>\n    /// <param name=\"second\">Second number to add.</param>\n    /// <returns>Sum of the two numbers.</returns>\n    public static int CalculateAdditionWithoutArithmetic(int first, int second)\n    {\n        while (second != 0)\n        {\n            int c = first & second;      // Carry\n            first ^= second;             // Sum without carry\n            second = c << 1;            // Carry shifted left\n        }\n\n        return first;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/AliquotSumCalculator.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     In number theory, the aliquot sum s(n) of a positive integer n is the sum of all proper divisors\n///     of n, that is, all divisors of n other than n itself. For example, the proper divisors of 15\n///     (that is, the positive divisors of 15 that are not equal to 15) are 1, 3 and 5, so the aliquot\n///     sum of 15 is 9 i.e. (1 + 3 + 5). Wikipedia: https://en.wikipedia.org/wiki/Aliquot_sum.\n/// </summary>\npublic static class AliquotSumCalculator\n{\n    /// <summary>\n    ///     Finds the aliquot sum of an integer number.\n    /// </summary>\n    /// <param name=\"number\">Positive number.</param>\n    /// <returns>The Aliquot Sum.</returns>\n    /// <exception cref=\"ArgumentException\">Error number is not on interval (0.0; int.MaxValue).</exception>\n    public static int CalculateAliquotSum(int number)\n    {\n        if (number < 0)\n        {\n            throw new ArgumentException($\"{nameof(number)} cannot be negative\");\n        }\n\n        var sum = 0;\n        for (int i = 1, limit = number / 2; i <= limit; ++i)\n        {\n            if (number % i == 0)\n            {\n                sum += i;\n            }\n        }\n\n        return sum;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/AmicableNumbersChecker.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n/// Amicable numbers are two different natural numbers related in such a way that the sum of the proper divisors of\n/// each is equal to the other number. That is, σ(a)=b+a and σ(b)=a+b, where σ(n) is equal to the sum of positive divisors of n (see also divisor function).\n/// See <a href=\"https://en.wikipedia.org/wiki/Amicable_numbers\">here</a> for more info.\n/// </summary>\npublic static class AmicableNumbersChecker\n{\n    /// <summary>\n    /// Checks if two numbers are amicable or not.\n    /// </summary>\n    /// <param name=\"x\">First number to check.</param>\n    /// <param name=\"y\">Second number to check.</param>\n    /// <returns>True if they are amicable numbers. False if not.</returns>\n    public static bool AreAmicableNumbers(int x, int y)\n    {\n        return SumOfDivisors(x) == y && SumOfDivisors(y) == x;\n    }\n\n    private static int SumOfDivisors(int number)\n    {\n        var sum = 0; /* sum of its positive divisors */\n        for (var i = 1; i < number; ++i)\n        {\n            if (number % i == 0)\n            {\n                sum += i;\n            }\n        }\n\n        return sum;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/AutomorphicNumber.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n/// Calculates Automorphic numbers. A number is said to be an Automorphic number\n/// if the square of the number will contain the number itself at the end.\n/// </summary>\npublic static class AutomorphicNumber\n{\n    /// <summary>\n    /// Generates a list of automorphic numbers that are between <paramref name=\"lowerBound\"/> and <paramref name=\"upperBound\"/>\n    /// inclusive.\n    /// </summary>\n    /// <param name=\"lowerBound\">The lower bound of the list.</param>\n    /// <param name=\"upperBound\">The upper bound of the list.</param>\n    /// <returns>A list that contains all of the automorphic numbers between <paramref name=\"lowerBound\"/> and <paramref name=\"upperBound\"/> inclusive.</returns>\n    /// <exception cref=\"ArgumentException\">If the <paramref name=\"lowerBound\"/>\n    /// or <paramref name=\"upperBound\"/> is not greater than zero\n    /// or <paramref name=\"upperBound\"/>is lower than the <paramref name=\"lowerBound\"/>.</exception>\n    public static IEnumerable<int> GetAutomorphicNumbers(int lowerBound, int upperBound)\n    {\n        if (lowerBound < 1)\n        {\n            throw new ArgumentException($\"Lower bound must be greater than 0.\");\n        }\n\n        if (upperBound < 1)\n        {\n            throw new ArgumentException($\"Upper bound must be greater than 0.\");\n        }\n\n        if (lowerBound > upperBound)\n        {\n            throw new ArgumentException($\"The lower bound must be less than or equal to the upper bound.\");\n        }\n\n        return Enumerable.Range(lowerBound, upperBound).Where(IsAutomorphic);\n    }\n\n    /// <summary>\n    /// Checks if a given natural number is automorphic or not.\n    /// </summary>\n    /// <param name=\"number\">The number to check.</param>\n    /// <returns>True if the number is automorphic, false otherwise.</returns>\n    /// <exception cref=\"ArgumentException\">If the number is non-positive.</exception>\n    public static bool IsAutomorphic(int number)\n    {\n        if (number < 1)\n        {\n            throw new ArgumentException($\"An automorphic number must always be positive.\");\n        }\n\n        BigInteger square = BigInteger.Pow(number, 2);\n\n        // Extract the last digits of both numbers\n        while (number > 0)\n        {\n            if (number % 10 != square % 10)\n            {\n                return false;\n            }\n\n            number /= 10;\n            square /= 10;\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/BinomialCoefficient.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     The binomial coefficients are the positive integers\n///     that occur as coefficients in the binomial theorem.\n/// </summary>\npublic static class BinomialCoefficient\n{\n    /// <summary>\n    ///     Calculates Binomial coefficients for given input.\n    /// </summary>\n    /// <param name=\"num\">First number.</param>\n    /// <param name=\"k\">Second number.</param>\n    /// <returns>Binimial Coefficients.</returns>\n    public static BigInteger Calculate(BigInteger num, BigInteger k)\n    {\n        if (num < k || k < 0)\n        {\n            throw new ArgumentException(\"num ≥ k ≥ 0\");\n        }\n\n        // Tricks to gain performance:\n        // 1. Because (num over k) equals (num over (num-k)), we can save multiplications and divisions\n        // by replacing k with the minimum of k and (num - k).\n        k = BigInteger.Min(k, num - k);\n\n        // 2. We can simplify the computation of (num! / (k! * (num - k)!)) to ((num * (num - 1) * ... * (num - k + 1) / (k!))\n        // and thus save some multiplications and divisions.\n        var numerator = BigInteger.One;\n        for (var val = num - k + 1; val <= num; val++)\n        {\n            numerator *= val;\n        }\n\n        // 3. Typically multiplication is a lot faster than division, therefore compute the value of k! first (i.e. k - 1 multiplications)\n        // and then divide the numerator by the denominator (i.e. 1 division); instead of performing k - 1 divisions (1 for each factor in k!).\n        var denominator = BigInteger.One;\n        for (var val = k; val > BigInteger.One; val--)\n        {\n            denominator *= val;\n        }\n\n        return numerator / denominator;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Ceil.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     Perform ceiling operation on a number.\n/// </summary>\npublic static class Ceil\n{\n    /// <summary>\n    ///    Returns the smallest integer greater than or equal to the number.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of number.</typeparam>\n    /// <param name=\"inputNum\">Number to find the ceiling of.</param>\n    /// <returns>Ceiling value of the number.</returns>\n    public static T CeilVal<T>(T inputNum) where T : INumber<T>\n    {\n        T intPart = T.CreateChecked(Convert.ToInt32(inputNum));\n\n        return inputNum > intPart ? intPart + T.One : intPart;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Decomposition/LU.cs",
    "content": "namespace Algorithms.Numeric.Decomposition;\n\n/// <summary>\n///     LU-decomposition factors the \"source\" matrix as the product of lower triangular matrix\n///     and upper triangular matrix.\n/// </summary>\npublic static class Lu\n{\n    /// <summary>\n    ///     Performs LU-decomposition on \"source\" matrix.\n    ///     Lower and upper matrices have same shapes as source matrix.\n    ///     Note: Decomposition can be applied only to square matrices.\n    /// </summary>\n    /// <param name=\"source\">Square matrix to decompose.</param>\n    /// <returns>Tuple of lower and upper matrix.</returns>\n    /// <exception cref=\"ArgumentException\">Source matrix is not square shaped.</exception>\n    public static (double[,] L, double[,] U) Decompose(double[,] source)\n    {\n        if (source.GetLength(0) != source.GetLength(1))\n        {\n            throw new ArgumentException(\"Source matrix is not square shaped.\");\n        }\n\n        var pivot = source.GetLength(0);\n        var lower = new double[pivot, pivot];\n        var upper = new double[pivot, pivot];\n\n        for (var i = 0; i < pivot; i++)\n        {\n            for (var k = i; k < pivot; k++)\n            {\n                double sum = 0;\n\n                for (var j = 0; j < i; j++)\n                {\n                    sum += lower[i, j] * upper[j, k];\n                }\n\n                upper[i, k] = source[i, k] - sum;\n            }\n\n            for (var k = i; k < pivot; k++)\n            {\n                if (i == k)\n                {\n                    lower[i, i] = 1;\n                }\n                else\n                {\n                    double sum = 0;\n\n                    for (var j = 0; j < i; j++)\n                    {\n                        sum += lower[k, j] * upper[j, i];\n                    }\n\n                    lower[k, i] = (source[k, i] - sum) / upper[i, i];\n                }\n            }\n        }\n\n        return (L: lower, U: upper);\n    }\n\n    /// <summary>\n    ///     Eliminates linear equations system represented as A*x=b, using LU-decomposition,\n    ///     where A - matrix of equation coefficients, b - vector of absolute terms of equations.\n    /// </summary>\n    /// <param name=\"matrix\">Matrix of equation coefficients.</param>\n    /// <param name=\"coefficients\">Vector of absolute terms of equations.</param>\n    /// <returns>Vector-solution for linear equations system.</returns>\n    /// <exception cref=\"ArgumentException\">Matrix of equation coefficients is not square shaped.</exception>\n    public static double[] Eliminate(double[,] matrix, double[] coefficients)\n    {\n        if (matrix.GetLength(0) != matrix.GetLength(1))\n        {\n            throw new ArgumentException(\"Matrix of equation coefficients is not square shaped.\");\n        }\n\n        var pivot = matrix.GetLength(0);\n        var upperTransform = new double[pivot, 1]; // U * upperTransform = coefficients\n        var solution = new double[pivot]; // L * solution = upperTransform\n        (double[,] l, double[,] u) = Decompose(matrix);\n\n        for (var i = 0; i < pivot; i++)\n        {\n            double pivotPointSum = 0;\n\n            for (var j = 0; j < i; j++)\n            {\n                pivotPointSum += upperTransform[j, 0] * l[i, j];\n            }\n\n            upperTransform[i, 0] = (coefficients[i] - pivotPointSum) / l[i, i];\n        }\n\n        for (var i = pivot - 1; i >= 0; i--)\n        {\n            double pivotPointSum = 0;\n\n            for (var j = i; j < pivot; j++)\n            {\n                pivotPointSum += solution[j] * u[i, j];\n            }\n\n            solution[i] = (upperTransform[i, 0] - pivotPointSum) / u[i, i];\n        }\n\n        return solution;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Decomposition/ThinSVD.cs",
    "content": "namespace Algorithms.Numeric.Decomposition;\n\n/// <summary>\n///     Singular Vector Decomposition decomposes any general matrix into its\n///     singular values and a set of orthonormal bases.\n/// </summary>\npublic static class ThinSvd\n{\n    /// <summary>\n    ///     Computes a random unit vector.\n    /// </summary>\n    /// <param name=\"dimensions\">The dimensions of the required vector.</param>\n    /// <returns>The unit vector.</returns>\n    public static double[] RandomUnitVector(int dimensions)\n    {\n        Random random = new();\n        double[] result = new double[dimensions];\n        for (var i = 0; i < dimensions; i++)\n        {\n            result[i] = 2 * random.NextDouble() - 1;\n        }\n\n        var magnitude = result.Magnitude();\n        result = result.Scale(1 / magnitude);\n        return result;\n    }\n\n    /// <summary>\n    ///     Computes a single singular vector for the given matrix, corresponding to the largest singular value.\n    /// </summary>\n    /// <param name=\"matrix\">The matrix.</param>\n    /// <returns>A singular vector, with dimension equal to number of columns of the matrix.</returns>\n    public static double[] Decompose1D(double[,] matrix) =>\n        Decompose1D(matrix, 1E-5, 100);\n\n    /// <summary>\n    ///     Computes a single singular vector for the given matrix, corresponding to the largest singular value.\n    /// </summary>\n    /// <param name=\"matrix\">The matrix.</param>\n    /// <param name=\"epsilon\">The error margin.</param>\n    /// <param name=\"maxIterations\">The maximum number of iterations.</param>\n    /// <returns>A singular vector, with dimension equal to number of columns of the matrix.</returns>\n    public static double[] Decompose1D(double[,] matrix, double epsilon, int maxIterations)\n    {\n        var n = matrix.GetLength(1);\n        var iterations = 0;\n        double mag;\n        double[] lastIteration;\n        double[] currIteration = RandomUnitVector(n);\n        double[,] b = matrix.Transpose().Multiply(matrix);\n        do\n        {\n            lastIteration = currIteration.Copy();\n            currIteration = b.MultiplyVector(lastIteration);\n            currIteration = currIteration.Scale(100);\n            mag = currIteration.Magnitude();\n            if (mag > epsilon)\n            {\n                currIteration = currIteration.Scale(1 / mag);\n            }\n\n            iterations++;\n        }\n        while (lastIteration.Dot(currIteration) < 1 - epsilon && iterations < maxIterations);\n\n        return currIteration;\n    }\n\n    public static (double[,] U, double[] S, double[,] V) Decompose(double[,] matrix) =>\n        Decompose(matrix, 1E-5, 100);\n\n    /// <summary>\n    ///     Computes the SVD for the given matrix, with singular values arranged from greatest to least.\n    /// </summary>\n    /// <param name=\"matrix\">The matrix.</param>\n    /// <param name=\"epsilon\">The error margin.</param>\n    /// <param name=\"maxIterations\">The maximum number of iterations.</param>\n    /// <returns>The SVD.</returns>\n    public static (double[,] U, double[] S, double[,] V) Decompose(\n        double[,] matrix,\n        double epsilon,\n        int maxIterations)\n    {\n        var m = matrix.GetLength(0);\n        var n = matrix.GetLength(1);\n        var numValues = Math.Min(m, n);\n\n        // sigmas is be a diagonal matrix, hence only a vector is needed\n        double[] sigmas = new double[numValues];\n        double[,] us = new double[m, numValues];\n        double[,] vs = new double[n, numValues];\n\n        // keep track of progress\n        double[,] remaining = matrix.Copy();\n\n        // for each singular value\n        for (var i = 0; i < numValues; i++)\n        {\n            // compute the v singular vector\n            double[] v = Decompose1D(remaining, epsilon, maxIterations);\n            double[] u = matrix.MultiplyVector(v);\n\n            // compute the contribution of this pair of singular vectors\n            double[,] contrib = u.OuterProduct(v);\n\n            // extract the singular value\n            var s = u.Magnitude();\n\n            // v and u should be unit vectors\n            if (s < epsilon)\n            {\n                u = new double[m];\n                v = new double[n];\n            }\n            else\n            {\n                u = u.Scale(1 / s);\n            }\n\n            // save u, v and s into the result\n            for (var j = 0; j < u.Length; j++)\n            {\n                us[j, i] = u[j];\n            }\n\n            for (var j = 0; j < v.Length; j++)\n            {\n                vs[j, i] = v[j];\n            }\n\n            sigmas[i] = s;\n\n            // remove the contribution of this pair and compute the rest\n            remaining = remaining.Subtract(contrib);\n        }\n\n        return (U: us, S: sigmas, V: vs);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/DoubleFactorial.cs",
    "content": "using System.Numerics;\n\nnamespace Algorithms.Numeric;\n\n/// <summary>\n///     The double factorial of a positive integer n, denoted by n!!,\n///     is the product of all integers from 1 up to n that have the same parity (odd or even) as n.\n///     E.g., 5!! = 5 * 3 * 1 = 15, and 6!! = 6 * 4 * 2 = 48.\n/// </summary>\npublic static class DoubleFactorial\n{\n    /// <summary>\n    ///     Calculates the double factorial of a non-negative integer number.\n    /// </summary>\n    /// <param name=\"inputNum\">Non-negative integer input number.</param>\n    /// <returns>Double factorial of the integer input number.</returns>\n    public static BigInteger Calculate(int inputNum)\n    {\n        // Don't calculate double factorial if input is a negative number.\n        if (inputNum < 0)\n        {\n            throw new ArgumentException(\"Double factorial is only defined for non-negative integers (num >= 0).\");\n        }\n\n        // Base cases: 0!! = 1 and 1!! = 1\n        if (inputNum <= 1)\n        {\n            return BigInteger.One;\n        }\n\n        // Initialize result.\n        BigInteger result = BigInteger.One;\n\n        // Start the iteration from the input number and step down by 2.\n        // This handles both odd (n, n-2, ..., 3, 1) and even (n, n-2, ..., 4, 2) cases naturally.\n        BigInteger current = inputNum;\n\n        while (current > BigInteger.Zero)\n        {\n            result *= current;\n\n            // Decrease the current number by 2 for the next factor.\n            current -= 2;\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/EulerMethod.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     In mathematics and computational science, the Euler method (also called forward Euler method)\n///     is a first-order numerical procedure for solving ordinary differential equations (ODEs)\n///     with a given initial value (aka. Cauchy problem). It is the most basic explicit method for numerical integration\n///     of ordinary differential equations. The method proceeds in a series of steps. At each step\n///     the y-value is calculated by evaluating the differential equation at the previous step,\n///     multiplying the result with the step-size and adding it to the last y-value:\n///     y_n+1 = y_n + stepSize * f(x_n, y_n).\n///     (description adapted from https://en.wikipedia.org/wiki/Euler_method )\n///     (see also: https://www.geeksforgeeks.org/euler-method-solving-differential-equation/ ).\n/// </summary>\npublic static class EulerMethod\n{\n    /// <summary>\n    ///     Loops through all the steps until xEnd is reached, adds a point for each step and then\n    ///     returns all the points.\n    /// </summary>\n    /// <param name=\"xStart\">Initial conditions x-value.</param>\n    /// <param name=\"xEnd\">Last x-value.</param>\n    /// <param name=\"stepSize\">Step-size on the x-axis.</param>\n    /// <param name=\"yStart\">Initial conditions y-value.</param>\n    /// <param name=\"yDerivative\">The right hand side of the differential equation.</param>\n    /// <returns>The solution of the Cauchy problem.</returns>\n    public static List<double[]> EulerFull(\n        double xStart,\n        double xEnd,\n        double stepSize,\n        double yStart,\n        Func<double, double, double> yDerivative)\n    {\n        if (xStart >= xEnd)\n        {\n            throw new ArgumentOutOfRangeException(\n                nameof(xEnd),\n                $\"{nameof(xEnd)} should be greater than {nameof(xStart)}\");\n        }\n\n        if (stepSize <= 0)\n        {\n            throw new ArgumentOutOfRangeException(\n                nameof(stepSize),\n                $\"{nameof(stepSize)} should be greater than zero\");\n        }\n\n        List<double[]> points = [];\n        double[] firstPoint = [xStart, yStart];\n        points.Add(firstPoint);\n        var yCurrent = yStart;\n        var xCurrent = xStart;\n\n        while (xCurrent < xEnd)\n        {\n            yCurrent = EulerStep(xCurrent, stepSize, yCurrent, yDerivative);\n            xCurrent += stepSize;\n            double[] point = [xCurrent, yCurrent];\n            points.Add(point);\n        }\n\n        return points;\n    }\n\n    /// <summary>\n    ///     Calculates the next y-value based on the current value of x, y and the stepSize.\n    /// </summary>\n    /// <param name=\"xCurrent\">Current x-value.</param>\n    /// <param name=\"stepSize\">Step-size on the x-axis.</param>\n    /// <param name=\"yCurrent\">Current y-value.</param>\n    /// <param name=\"yDerivative\">The right hand side of the differential equation.</param>\n    /// <returns>The next y-value.</returns>\n    private static double EulerStep(\n        double xCurrent,\n        double stepSize,\n        double yCurrent,\n        Func<double, double, double> yDerivative)\n    {\n        var yNext = yCurrent + stepSize * yDerivative(xCurrent, yCurrent);\n        return yNext;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Factorial.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     The factorial of a positive integer n, denoted by n!,\n///     is the product of all positive integers less than or equal to n.\n/// </summary>\npublic static class Factorial\n{\n    /// <summary>\n    ///     Calculates factorial of a integer number.\n    /// </summary>\n    /// <param name=\"inputNum\">Integer Input number.</param>\n    /// <returns>Factorial of integer input number.</returns>\n    public static BigInteger Calculate(int inputNum)\n    {\n        // Convert integer input to BigInteger\n        BigInteger num = new BigInteger(inputNum);\n\n        // Don't calculate factorial if input is a negative number.\n        if (BigInteger.Compare(num, BigInteger.Zero) < 0)\n        {\n            throw new ArgumentException(\"Only for num >= 0\");\n        }\n\n        // Factorial of numbers greater than 0.\n        BigInteger result = BigInteger.One;\n\n        for (BigInteger i = BigInteger.One; BigInteger.Compare(i, num) <= 0; i = BigInteger.Add(i, BigInteger.One))\n        {\n            result = BigInteger.Multiply(result, i);\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Factorization/IFactorizer.cs",
    "content": "namespace Algorithms.Numeric.Factorization;\n\n/// <summary>\n///     Finds a factor of a given number or returns false if it's prime.\n/// </summary>\npublic interface IFactorizer\n{\n    /// <summary>\n    ///     Finds a factor of a given number or returns false if it's prime.\n    /// </summary>\n    /// <param name=\"n\">Integer to factor.</param>\n    /// <param name=\"factor\">Found factor.</param>\n    /// <returns><see langword=\"true\" /> if factor is found, <see langword=\"false\" /> if <paramref name=\"n\" /> is prime.</returns>\n    bool TryFactor(int n, out int factor);\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs",
    "content": "namespace Algorithms.Numeric.Factorization;\n\n/// <summary>\n///     Factors number using trial division algorithm.\n/// </summary>\npublic class TrialDivisionFactorizer : IFactorizer\n{\n    /// <summary>\n    ///     Finds the smallest non trivial factor (i.e.: 1 &lt; factor &lt;= sqrt(<paramref name=\"n\" />)) of a given number or returns false if it's prime.\n    /// </summary>\n    /// <param name=\"n\">Integer to factor.</param>\n    /// <param name=\"factor\">Found factor.</param>\n    /// <returns><see langword=\"true\" /> if factor is found, <see langword=\"false\" /> if <paramref name=\"n\" /> is prime.</returns>\n    public bool TryFactor(int n, out int factor)\n    {\n        n = Math.Abs(n);\n        factor = Enumerable.Range(2, (int)Math.Sqrt(n) - 1).FirstOrDefault(i => n % i == 0);\n        return factor != 0;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Floor.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     Perform floor operation on a number.\n/// </summary>\npublic static class Floor\n{\n    /// <summary>\n    ///    Returns the largest integer less than or equal to the number.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of number.</typeparam>\n    /// <param name=\"inputNum\">Number to find the floor of.</param>\n    /// <returns>Floor value of the number.</returns>\n    public static T FloorVal<T>(T inputNum) where T : INumber<T>\n    {\n        T intPart = T.CreateChecked(Convert.ToInt32(inputNum));\n\n        return inputNum < intPart ? intPart - T.One : intPart;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/GaussJordanElimination.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     Algorithm used to find the inverse of any matrix that can be inverted.\n/// </summary>\npublic class GaussJordanElimination\n{\n    private int RowCount { get; set; }\n\n    /// <summary>\n    ///     Method to find a linear equation system using gaussian elimination.\n    /// </summary>\n    /// <param name=\"matrix\">The key matrix to solve via algorithm.</param>\n    /// <returns>\n    ///     whether the input matrix has a unique solution or not.\n    ///     and solves on the given matrix.\n    /// </returns>\n    public bool Solve(double[,] matrix)\n    {\n        RowCount = matrix.GetUpperBound(0) + 1;\n\n        if (!CanMatrixBeUsed(matrix))\n        {\n            throw new ArgumentException(\"Please use a n*(n+1) matrix with Length > 0.\");\n        }\n\n        var pivot = PivotMatrix(ref matrix);\n        if (!pivot)\n        {\n            return false;\n        }\n\n        Elimination(ref matrix);\n\n        return ElementaryReduction(ref matrix);\n    }\n\n    /// <summary>\n    ///     To make simple validation of the matrix to be used.\n    /// </summary>\n    /// <param name=\"matrix\">Multidimensional array matrix.</param>\n    /// <returns>\n    ///     True: if algorithm can be use for given matrix;\n    ///     False: Otherwise.\n    /// </returns>\n    private bool CanMatrixBeUsed(double[,] matrix) => matrix?.Length == RowCount * (RowCount + 1) && RowCount > 1;\n\n    /// <summary>\n    ///     To prepare given matrix by pivoting rows.\n    /// </summary>\n    /// <param name=\"matrix\">Input matrix.</param>\n    /// <returns>Matrix.</returns>\n    private bool PivotMatrix(ref double[,] matrix)\n    {\n        for (var col = 0; col + 1 < RowCount; col++)\n        {\n            if (matrix[col, col] == 0)\n            {\n                // To find a non-zero coefficient\n                var rowToSwap = FindNonZeroCoefficient(ref matrix, col);\n\n                if (matrix[rowToSwap, col] != 0)\n                {\n                    var tmp = new double[RowCount + 1];\n                    for (var i = 0; i < RowCount + 1; i++)\n                    {\n                        // To make the swap with the element above.\n                        tmp[i] = matrix[rowToSwap, i];\n                        matrix[rowToSwap, i] = matrix[col, i];\n                        matrix[col, i] = tmp[i];\n                    }\n                }\n                else\n                {\n                    // To return that the matrix doesn't have a unique solution.\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    private int FindNonZeroCoefficient(ref double[,] matrix, int col)\n    {\n        var rowToSwap = col + 1;\n\n        // To find a non-zero coefficient\n        for (; rowToSwap < RowCount; rowToSwap++)\n        {\n            if (matrix[rowToSwap, col] != 0)\n            {\n                return rowToSwap;\n            }\n        }\n\n        return col + 1;\n    }\n\n    /// <summary>\n    ///     Applies REF.\n    /// </summary>\n    /// <param name=\"matrix\">Input matrix.</param>\n    private void Elimination(ref double[,] matrix)\n    {\n        for (var srcRow = 0; srcRow + 1 < RowCount; srcRow++)\n        {\n            for (var destRow = srcRow + 1; destRow < RowCount; destRow++)\n            {\n                var df = matrix[srcRow, srcRow];\n                var sf = matrix[destRow, srcRow];\n\n                for (var i = 0; i < RowCount + 1; i++)\n                {\n                    matrix[destRow, i] = matrix[destRow, i] * df - matrix[srcRow, i] * sf;\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    ///     To continue reducing the matrix using RREF.\n    /// </summary>\n    /// <param name=\"matrix\">Input matrix.</param>\n    /// <returns>True if it has a unique solution; false otherwise.</returns>\n    private bool ElementaryReduction(ref double[,] matrix)\n    {\n        for (var row = RowCount - 1; row >= 0; row--)\n        {\n            var element = matrix[row, row];\n            if (element == 0)\n            {\n                return false;\n            }\n\n            for (var i = 0; i < RowCount + 1; i++)\n            {\n                matrix[row, i] /= element;\n            }\n\n            for (var destRow = 0; destRow < row; destRow++)\n            {\n                matrix[destRow, RowCount] -= matrix[destRow, row] * matrix[row, RowCount];\n                matrix[destRow, row] = 0;\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinder.cs",
    "content": "namespace Algorithms.Numeric.GreatestCommonDivisor;\n\n/// <summary>\n///     Finds greatest common divisor for numbers u and v\n///     using binary algorithm.\n///     Wiki: https://en.wikipedia.org/wiki/Binary_GCD_algorithm.\n/// </summary>\npublic class BinaryGreatestCommonDivisorFinder : IGreatestCommonDivisorFinder\n{\n    public int FindGcd(int u, int v)\n    {\n        // GCD(0, 0) = 0\n        if (u == 0 && v == 0)\n        {\n            return 0;\n        }\n\n        // GCD(0, v) = v; GCD(u, 0) = u\n        if (u == 0 || v == 0)\n        {\n            return u + v;\n        }\n\n        // GCD(-a, -b) = GCD(-a, b) = GCD(a, -b) = GCD(a, b)\n        u = Math.Sign(u) * u;\n        v = Math.Sign(v) * v;\n\n        // Let shift := lg K, where K is the greatest power of 2 dividing both u and v\n        var shift = 0;\n        while (((u | v) & 1) == 0)\n        {\n            u >>= 1;\n            v >>= 1;\n            shift++;\n        }\n\n        while ((u & 1) == 0)\n        {\n            u >>= 1;\n        }\n\n        // From here on, u is always odd\n        do\n        {\n            // Remove all factors of 2 in v as they are not common\n            // v is not zero, so while will terminate\n            while ((v & 1) == 0)\n            {\n                v >>= 1;\n            }\n\n            // Now u and v are both odd. Swap if necessary so u <= v,\n            if (u > v)\n            {\n                var t = v;\n                v = u;\n                u = t;\n            }\n\n            // Here v >= u and v - u is even\n            v -= u;\n        }\n        while (v != 0);\n\n        // Restore common factors of 2\n        return u << shift;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinder.cs",
    "content": "namespace Algorithms.Numeric.GreatestCommonDivisor;\n\n/// <summary>\n///     Euclidean algorithm for finding the greatest common divisor.\n/// </summary>\npublic class EuclideanGreatestCommonDivisorFinder : IGreatestCommonDivisorFinder\n{\n    /// <summary>\n    ///     Finds greatest common divisor for numbers a and b\n    ///     using euclidean algorithm.\n    /// </summary>\n    /// <param name=\"a\">First number.</param>\n    /// <param name=\"b\">Second number.</param>\n    /// <returns>Greatest common divisor.</returns>\n    public int FindGcd(int a, int b)\n    {\n        if (a == 0 && b == 0)\n        {\n            return int.MaxValue;\n        }\n\n        if (a == 0 || b == 0)\n        {\n            return a + b;\n        }\n\n        var aa = a;\n        var bb = b;\n        var cc = aa % bb;\n\n        while (cc != 0)\n        {\n            aa = bb;\n            bb = cc;\n            cc = aa % bb;\n        }\n\n        return bb;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/GreatestCommonDivisor/IGreatestCommonDivisorFinder.cs",
    "content": "namespace Algorithms.Numeric.GreatestCommonDivisor;\n\npublic interface IGreatestCommonDivisorFinder\n{\n    int FindGcd(int a, int b);\n}\n"
  },
  {
    "path": "Algorithms/Numeric/JosephusProblem.cs",
    "content": "﻿namespace Algorithms.Numeric;\n\npublic static class JosephusProblem\n{\n    /// <summary>\n    /// Calculates the winner in the Josephus problem.\n    /// </summary>\n    /// <param name=\"n\">The number of people in the initial circle.</param>\n    /// <param name=\"k\">The count of each step. k-1 people are skipped and the k-th is executed.</param>\n    /// <returns>The 1-indexed position where the player must choose in order to win the game.</returns>\n    public static long FindWinner(long n, long k)\n    {\n        if (k <= 0)\n        {\n            throw new ArgumentException(\"The step cannot be smaller than 1\");\n        }\n\n        if (k > n)\n        {\n            throw new ArgumentException(\"The step cannot be greater than the size of the group\");\n        }\n\n        long winner = 0;\n        for (long stepIndex = 1; stepIndex <= n; ++stepIndex)\n        {\n            winner = (winner + k) % stepIndex;\n        }\n\n        return winner + 1;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/KeithNumberChecker.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///  In number theory, a Keith number or repfigit number is a natural number n in a given number base b with k digits such that\n///  when a sequence is created such that the first k terms are the k digits of n and each subsequent term is the sum of the\n///  previous k terms, n is part of the sequence.\n/// </summary>\npublic static class KeithNumberChecker\n{\n    /// <summary>\n    ///     Checks if a number is a Keith number or not.\n    /// </summary>\n    /// <param name=\"number\">Number to check.</param>\n    /// <returns>True if it is a Keith number; False otherwise.</returns>\n    public static bool IsKeithNumber(int number)\n    {\n        if (number < 0)\n        {\n            throw new ArgumentException($\"{nameof(number)} cannot be negative\");\n        }\n\n        var tempNumber = number;\n\n        var stringNumber = number.ToString();\n\n        var digitsInNumber = stringNumber.Length;\n\n        /* storing the terms of the series */\n        var termsArray = new int[number];\n\n        for (var i = digitsInNumber - 1; i >= 0; i--)\n        {\n            termsArray[i] = tempNumber % 10;\n            tempNumber /= 10;\n        }\n\n        var sum = 0;\n        var k = digitsInNumber;\n        while (sum < number)\n        {\n            sum = 0;\n\n            for (var j = 1; j <= digitsInNumber; j++)\n            {\n                sum += termsArray[k - j];\n            }\n\n            termsArray[k] = sum;\n            k++;\n        }\n\n        return sum == number;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/KrishnamurthyNumberChecker.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n/// A Krishnamurthy number is a number whose sum of the factorial of digits\n/// is equal to the number itself.\n///\n/// For example, 145 is a Krishnamurthy number since: 1! + 4! + 5! = 1 + 24 + 120 = 145.\n/// </summary>\npublic static class KrishnamurthyNumberChecker\n{\n    /// <summary>\n    /// Check if a number is Krishnamurthy number or not.\n    /// </summary>\n    /// <param name=\"n\">The number to check.</param>\n    /// <returns>True if the number is Krishnamurthy, false otherwise.</returns>\n    public static bool IsKMurthyNumber(int n)\n    {\n        int sumOfFactorials = 0;\n        int tmp = n;\n\n        if (n <= 0)\n        {\n            return false;\n        }\n\n        while (n != 0)\n        {\n            int factorial = (int)Factorial.Calculate(n % 10);\n            sumOfFactorials += factorial;\n            n = n / 10;\n        }\n\n        return tmp == sumOfFactorials;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/MillerRabinPrimalityChecker.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n/// https://en.wikipedia.org/wiki/Miller-Rabin_primality_test\n/// The Miller–Rabin primality test or Rabin–Miller primality test is a probabilistic primality test:\n/// an algorithm which determines whether a given number is likely to be prime,\n/// similar to the Fermat primality test and the Solovay–Strassen primality test.\n/// It is of historical significance in the search for a polynomial-time deterministic primality test.\n/// Its probabilistic variant remains widely used in practice, as one of the simplest and fastest tests known.\n/// </summary>\npublic static class MillerRabinPrimalityChecker\n{\n    /// <summary>\n    ///     Run the probabilistic primality test.\n    ///     </summary>\n    /// <param name=\"n\">Number to check.</param>\n    /// <param name=\"rounds\">Number of rounds, the parameter determines the accuracy of the test, recommended value is Log2(n).</param>\n    /// <param name=\"seed\">Seed for random number generator.</param>\n    /// <returns>True if is a highly likely prime number; False otherwise.</returns>\n    /// <exception cref=\"ArgumentException\">Error: number should be more than 3.</exception>\n    public static bool IsProbablyPrimeNumber(BigInteger n, BigInteger rounds, int? seed = null)\n    {\n        Random rand = seed is null\n            ? new()\n            : new(seed.Value);\n        return IsProbablyPrimeNumber(n, rounds, rand);\n    }\n\n    private static bool IsProbablyPrimeNumber(BigInteger n, BigInteger rounds, Random rand)\n    {\n        if (n <= 3)\n        {\n            throw new ArgumentException($\"{nameof(n)} should be more than 3\");\n        }\n\n        // Input #1: n > 3, an odd integer to be tested for primality\n        // Input #2: k, the number of rounds of testing to perform, recommended k = Log2(n)\n        // Output:   false = “composite”\n        //           true  = “probably prime”\n\n        // write n as 2r·d + 1 with d odd(by factoring out powers of 2 from n − 1)\n        BigInteger r = 0;\n        BigInteger d = n - 1;\n        while (d % 2 == 0)\n        {\n            r++;\n            d /= 2;\n        }\n\n        // as there is no native random function for BigInteger we suppose a random int number is sufficient\n        int nMaxValue = (n > int.MaxValue) ? int.MaxValue : (int)n;\n        BigInteger a = rand.Next(2, nMaxValue - 2); // ; pick a random integer a in the range[2, n − 2]\n\n        while (rounds > 0)\n        {\n            rounds--;\n            var x = BigInteger.ModPow(a, d, n);\n            if (x == 1 || x == (n - 1))\n            {\n                continue;\n            }\n\n            BigInteger tempr = r - 1;\n            while (tempr > 0 && (x != n - 1))\n            {\n                tempr--;\n                x = BigInteger.ModPow(x, 2, n);\n            }\n\n            if (x == n - 1)\n            {\n                continue;\n            }\n\n            return false;\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/ModularExponentiation.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     Modular exponentiation is a type of exponentiation performed over a modulus\n///     Modular exponentiation c is: c = b^e mod m where b is base, e is exponent, m is modulus\n///     (Wiki: https://en.wikipedia.org/wiki/Modular_exponentiation).\n/// </summary>\npublic class ModularExponentiation\n{\n    /// <summary>\n    ///     Performs Modular Exponentiation on b, e, m.\n    /// </summary>\n    /// <param name=\"b\">Base.</param>\n    /// <param name=\"e\">Exponent.</param>\n    /// <param name=\"m\">Modulus.</param>\n    /// <returns>Modular Exponential.</returns>\n    public int ModularPow(int b, int e, int m)\n    {\n        // initialize result in variable res\n        int res = 1;\n        if (m == 1)\n        {\n            // 1 divides every number\n            return 0;\n        }\n\n        if (m <= 0)\n        {\n            // exponential not defined in this case\n            throw new ArgumentException(string.Format(\"{0} is not a positive integer\", m));\n        }\n\n        for (int i = 0; i < e; i++)\n        {\n            res = (res * b) % m;\n        }\n\n        return res;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/NarcissisticNumberChecker.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     A Narcissistic number is equal to the sum of the cubes of its digits. For example, 370 is a\n///     Narcissistic number because 3*3*3 + 7*7*7 + 0*0*0 = 370.\n/// </summary>\npublic static class NarcissisticNumberChecker\n{\n    /// <summary>\n    ///     Checks if a number is a Narcissistic number or not.\n    /// </summary>\n    /// <param name=\"number\">Number to check.</param>\n    /// <returns>True if is a Narcissistic number; False otherwise.</returns>\n    public static bool IsNarcissistic(int number)\n    {\n        var sum = 0;\n        var temp = number;\n        var numberOfDigits = 0;\n        while (temp != 0)\n        {\n            numberOfDigits++;\n            temp /= 10;\n        }\n\n        temp = number;\n        while (number > 0)\n        {\n            var remainder = number % 10;\n            var power = (int)Math.Pow(remainder, numberOfDigits);\n\n            sum += power;\n            number /= 10;\n        }\n\n        return sum == temp;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/PerfectCubeChecker.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     A perfect cube is an element of algebraic structure that is equal to the cube of another element.\n/// </summary>\npublic static class PerfectCubeChecker\n{\n    /// <summary>\n    ///     Checks if a number is a perfect cube or not.\n    /// </summary>\n    /// <param name=\"number\">Number to check.</param>\n    /// <returns>True if is a perfect cube; False otherwise.</returns>\n    public static bool IsPerfectCube(int number)\n    {\n        if (number < 0)\n        {\n            number = -number;\n        }\n\n        var cubeRoot = Math.Round(Math.Pow(number, 1.0 / 3.0));\n        return Math.Abs(cubeRoot * cubeRoot * cubeRoot - number) < 1e-6;\n    }\n\n    /// <summary>\n    ///     Checks if a number is a perfect cube or not using binary search.\n    /// </summary>\n    /// <param name=\"number\">Number to check.</param>\n    /// <returns>True if is a perfect cube; False otherwise.</returns>\n    public static bool IsPerfectCubeBinarySearch(int number)\n    {\n        if (number < 0)\n        {\n            number = -number;\n        }\n\n        int left = 0;\n        int right = number;\n        while (left <= right)\n        {\n            int mid = left + (right - left) / 2;\n            int midCubed = mid * mid * mid;\n            if (midCubed == number)\n            {\n                return true;\n            }\n            else if (midCubed < number)\n            {\n                left = mid + 1;\n            }\n            else\n            {\n                right = mid - 1;\n            }\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/PerfectNumberChecker.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     In number theory, a perfect number is a positive integer that is equal to the sum of its positive\n///     divisors, excluding the number itself.For instance, 6 has divisors 1, 2 and 3 (excluding\n///     itself), and 1 + 2 + 3 = 6, so 6 is a perfect number.\n/// </summary>\npublic static class PerfectNumberChecker\n{\n    /// <summary>\n    ///     Checks if a number is a perfect number or not.\n    /// </summary>\n    /// <param name=\"number\">Number to check.</param>\n    /// <returns>True if is a perfect number; False otherwise.</returns>\n    /// <exception cref=\"ArgumentException\">Error number is not on interval (0.0; int.MaxValue).</exception>\n    public static bool IsPerfectNumber(int number)\n    {\n        if (number < 0)\n        {\n            throw new ArgumentException($\"{nameof(number)} cannot be negative\");\n        }\n\n        var sum = 0; /* sum of its positive divisors */\n        for (var i = 1; i < number; ++i)\n        {\n            if (number % i == 0)\n            {\n                sum += i;\n            }\n        }\n\n        return sum == number;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/PerfectSquareChecker.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     A perfect square is an element of algebraic structure that is equal to the square of another element.\n/// </summary>\npublic static class PerfectSquareChecker\n{\n    /// <summary>\n    ///     Checks if a number is a perfect square or not.\n    /// </summary>\n    /// <param name=\"number\">Number too check.</param>\n    /// <returns>True if is a perfect square; False otherwise.</returns>\n    public static bool IsPerfectSquare(int number)\n    {\n        if (number < 0)\n        {\n            return false;\n        }\n\n        var sqrt = (int)Math.Sqrt(number);\n        return sqrt * sqrt == number;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/PrimeChecker.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     A prime number (or a prime) is a natural number greater than 1 that is not a product of two smaller natural numbers.\n/// </summary>\npublic static class PrimeChecker\n{\n    /// <summary>\n    ///     Checks if a number is a prime number or not using optimized trial division.\n    ///     This method avoids checking multiples of 2 and 3, optimizing the loop by checking\n    ///     divisors of the form 6k ± 1 up to the square root of the number.\n    /// </summary>\n    /// <param name=\"number\">The integer number to check.</param>\n    /// <returns>True if the number is prime; False otherwise.</returns>\n    public static bool IsPrime(int number)\n    {\n        // Numbers less than or equal to 1 are not prime.\n        if (number <= 1)\n        {\n            return false;\n        }\n\n        // 2 and 3 are the first two prime numbers.\n        if (number <= 3)\n        {\n            return true;\n        }\n\n        // Check for divisibility by 2 and 3.\n        if (number % 2 == 0 || number % 3 == 0)\n        {\n            return false;\n        }\n\n        // Check for divisibility by numbers of the form 6k ± 1 up to sqrt(number).\n        // The loop increments by 6 to skip known non-prime divisors.\n        for (int i = 5; i <= number / i; i = i + 6)\n        {\n            // Check 6k - 1\n            if (number % i == 0)\n            {\n                return false;\n            }\n\n            // Check 6k + 1\n            if (number % (i + 2) == 0)\n            {\n                return false;\n            }\n        }\n\n        // If no divisors are found, the number is prime.\n        return true;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Pseudoinverse/PseudoInverse.cs",
    "content": "using Algorithms.Numeric.Decomposition;\n\nnamespace Algorithms.Numeric.Pseudoinverse;\n\n/// <summary>\n///     The Moore–Penrose pseudo-inverse A+ of a matrix A,\n///     is a general way to find the solution to the following system of linear equations:\n///     ~b = A ~y. ~b e R^m; ~y e R^n; A e Rm×n.\n///     There are various methods for construction the pseudo-inverse.\n///     This one is based on Singular Value Decomposition (SVD).\n/// </summary>\npublic static class PseudoInverse\n{\n    /// <summary>\n    ///     Return the pseudoinverse of a matrix based on the Moore-Penrose Algorithm.\n    ///     using Singular Value Decomposition (SVD).\n    /// </summary>\n    /// <param name=\"inMat\">Input matrix to find its inverse to.</param>\n    /// <returns>The inverse matrix approximation of the input matrix.</returns>\n    public static double[,] PInv(double[,] inMat)\n    {\n        // To compute the SVD of the matrix to find Sigma.\n        var (u, s, v) = ThinSvd.Decompose(inMat);\n\n        // To take the reciprocal of each non-zero element on the diagonal.\n        var len = s.Length;\n\n        var sigma = new double[len];\n        for (var i = 0; i < len; i++)\n        {\n            sigma[i] = Math.Abs(s[i]) < 0.0001 ? 0 : 1 / s[i];\n        }\n\n        // To construct a diagonal matrix based on the vector result.\n        var diag = sigma.ToDiagonalMatrix();\n\n        // To construct the pseudo-inverse using the computed information above.\n        var matinv = u.Multiply(diag).Multiply(v.Transpose());\n\n        // To Transpose the result matrix.\n        return matinv.Transpose();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Relu.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     Implementation of the Rectified Linear Unit (ReLU) function.\n///     ReLU is defined as: ReLU(x) = max(0, x).\n///     It is commonly used as an activation function in neural networks.\n/// </summary>\npublic static class Relu\n{\n    /// <summary>\n    ///     Compute the Rectified Linear Unit (ReLU) for a single value.\n    /// </summary>\n    /// <param name=\"input\">The input real number.</param>\n    /// <returns>The output real number (>= 0).</returns>\n    public static double Compute(double input)\n    {\n        return Math.Max(0.0, input);\n    }\n\n    /// <summary>\n    ///     Compute the Rectified Linear Unit (ReLU) element-wise for a vector.\n    /// </summary>\n    /// <param name=\"input\">The input vector of real numbers.</param>\n    /// <returns>The output vector where each element is max(0, input[i]).</returns>\n    public static double[] Compute(double[] input)\n    {\n        if (input is null)\n        {\n            throw new ArgumentNullException(nameof(input));\n        }\n\n        if (input.Length == 0)\n        {\n            throw new ArgumentException(\"Array is empty.\");\n        }\n\n        var output = new double[input.Length];\n\n        for (var i = 0; i < input.Length; i++)\n        {\n            output[i] = Math.Max(0.0, input[i]);\n        }\n\n        return output;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/RungeKuttaMethod.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     In numerical analysis, the Runge–Kutta methods are a family of implicit and explicit iterative methods,\n///     used in temporal discretization for the approximate solutions of simultaneous nonlinear equations.\n///     The most widely known member of the Runge–Kutta family is generally referred to as\n///     \"RK4\", the \"classic Runge–Kutta method\" or simply as \"the Runge–Kutta method\".\n///     </summary>\npublic static class RungeKuttaMethod\n{\n    /// <summary>\n    ///     Loops through all the steps until xEnd is reached, adds a point for each step and then\n    ///     returns all the points.\n    /// </summary>\n    /// <param name=\"xStart\">Initial conditions x-value.</param>\n    /// <param name=\"xEnd\">Last x-value.</param>\n    /// <param name=\"stepSize\">Step-size on the x-axis.</param>\n    /// <param name=\"yStart\">Initial conditions y-value.</param>\n    /// <param name=\"function\">The right hand side of the differential equation.</param>\n    /// <returns>The solution of the Cauchy problem.</returns>\n    public static List<double[]> ClassicRungeKuttaMethod(\n        double xStart,\n        double xEnd,\n        double stepSize,\n        double yStart,\n        Func<double, double, double> function)\n    {\n        if (xStart >= xEnd)\n        {\n            throw new ArgumentOutOfRangeException(\n                nameof(xEnd),\n                $\"{nameof(xEnd)} should be greater than {nameof(xStart)}\");\n        }\n\n        if (stepSize <= 0)\n        {\n            throw new ArgumentOutOfRangeException(\n                nameof(stepSize),\n                $\"{nameof(stepSize)} should be greater than zero\");\n        }\n\n        List<double[]> points = [];\n        double[] firstPoint = [xStart, yStart];\n        points.Add(firstPoint);\n\n        var yCurrent = yStart;\n        var xCurrent = xStart;\n\n        while (xCurrent < xEnd)\n        {\n            var k1 = function(xCurrent, yCurrent);\n            var k2 = function(xCurrent + 0.5 * stepSize, yCurrent + 0.5 * stepSize * k1);\n            var k3 = function(xCurrent + 0.5 * stepSize, yCurrent + 0.5 * stepSize * k2);\n            var k4 = function(xCurrent + stepSize, yCurrent + stepSize * k3);\n\n            yCurrent += (1.0 / 6.0) * stepSize * (k1 + 2 * k2 + 2 * k3 + k4);\n            xCurrent += stepSize;\n\n            double[] newPoint = [xCurrent, yCurrent];\n            points.Add(newPoint);\n        }\n\n        return points;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Series/Maclaurin.cs",
    "content": "namespace Algorithms.Numeric.Series;\n\n/// <summary>\n///     Maclaurin series calculates nonlinear functions approximation\n///     starting from point x = 0 in a form of infinite power series:\n///     f(x) = f(0) + f'(0) * x + ... + (f'n(0) * (x ^ n)) / n! + ...,\n///     where n is natural number.\n/// </summary>\npublic static class Maclaurin\n{\n    /// <summary>\n    ///     Calculates approximation of e^x function:\n    ///     e^x = 1 + x + x^2 / 2! + ... + x^n / n! + ...,\n    ///     where n is number of terms (natural number),\n    ///     and x is given point (rational number).\n    /// </summary>\n    /// <param name=\"x\">Given point.</param>\n    /// <param name=\"n\">The number of terms in polynomial.</param>\n    /// <returns>Approximated value of the function in the given point.</returns>\n    public static double Exp(double x, int n) =>\n        Enumerable.Range(0, n).Sum(i => ExpTerm(x, i));\n\n    /// <summary>\n    ///     Calculates approximation of sin(x) function:\n    ///     sin(x) = x - x^3 / 3! + ... + (-1)^n * x^(2*n + 1) / (2*n + 1)! + ...,\n    ///     where n is number of terms (natural number),\n    ///     and x is given point (rational number).\n    /// </summary>\n    /// <param name=\"x\">Given point.</param>\n    /// <param name=\"n\">The number of terms in polynomial.</param>\n    /// <returns>Approximated value of the function in the given point.</returns>\n    public static double Sin(double x, int n) =>\n        Enumerable.Range(0, n).Sum(i => SinTerm(x, i));\n\n    /// <summary>\n    ///     Calculates approximation of cos(x) function:\n    ///     cos(x) = 1 - x^2 / 2! + ... + (-1)^n * x^(2*n) / (2*n)! + ...,\n    ///     where n is number of terms (natural number),\n    ///     and x is given point (rational number).\n    /// </summary>\n    /// <param name=\"x\">Given point.</param>\n    /// <param name=\"n\">The number of terms in polynomial.</param>\n    /// <returns>Approximated value of the function in the given point.</returns>\n    public static double Cos(double x, int n) =>\n        Enumerable.Range(0, n).Sum(i => CosTerm(x, i));\n\n    /// <summary>\n    ///     Calculates approximation of e^x function:\n    ///     e^x = 1 + x + x^2 / 2! + ... + x^n / n! + ...,\n    ///     and x is given point (rational number).\n    /// </summary>\n    /// <param name=\"x\">Given point.</param>\n    /// <param name=\"error\">Last term error value.</param>\n    /// <returns>Approximated value of the function in the given point.</returns>\n    /// <exception cref=\"ArgumentException\">Error value is not on interval (0.0; 1.0).</exception>\n    public static double Exp(double x, double error = 0.00001) => ErrorTermWrapper(x, error, ExpTerm);\n\n    /// <summary>\n    ///     Calculates approximation of sin(x) function:\n    ///     sin(x) = x - x^3 / 3! + ... + (-1)^n * x^(2*n + 1) / (2*n + 1)! + ...,\n    ///     and x is given point (rational number).\n    /// </summary>\n    /// <param name=\"x\">Given point.</param>\n    /// <param name=\"error\">Last term error value.</param>\n    /// <returns>Approximated value of the function in the given point.</returns>\n    /// <exception cref=\"ArgumentException\">Error value is not on interval (0.0; 1.0).</exception>\n    public static double Sin(double x, double error = 0.00001) => ErrorTermWrapper(x, error, SinTerm);\n\n    /// <summary>\n    ///     Calculates approximation of cos(x) function:\n    ///     cos(x) = 1 - x^2 / 2! + ... + (-1)^n * x^(2*n) / (2*n)! + ...,\n    ///     and x is given point (rational number).\n    /// </summary>\n    /// <param name=\"x\">Given point.</param>\n    /// <param name=\"error\">Last term error value.</param>\n    /// <returns>Approximated value of the function in the given point.</returns>\n    /// <exception cref=\"ArgumentException\">Error value is not on interval (0.0; 1.0).</exception>\n    public static double Cos(double x, double error = 0.00001) => ErrorTermWrapper(x, error, CosTerm);\n\n    /// <summary>\n    ///     Wrapper function for calculating approximation with estimated\n    ///     count of terms, where last term value is less than given error.\n    /// </summary>\n    /// <param name=\"x\">Given point.</param>\n    /// <param name=\"error\">Last term error value.</param>\n    /// <param name=\"term\">Indexed term of approximation series.</param>\n    /// <returns>Approximated value of the function in the given point.</returns>\n    /// <exception cref=\"ArgumentException\">Error value is not on interval (0.0; 1.0).</exception>\n    private static double ErrorTermWrapper(double x, double error, Func<double, int, double> term)\n    {\n        if (error <= 0.0 || error >= 1.0)\n        {\n            throw new ArgumentException(\"Error value is not on interval (0.0; 1.0).\");\n        }\n\n        var i = 0;\n        var termCoefficient = 0.0;\n        var result = 0.0;\n\n        do\n        {\n            result += termCoefficient;\n            termCoefficient = term(x, i);\n            i++;\n        }\n        while (Math.Abs(termCoefficient) > error);\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Single term for e^x function approximation: x^i / i!.\n    /// </summary>\n    /// <param name=\"x\">Given point.</param>\n    /// <param name=\"i\">Term index from 0 to n.</param>\n    /// <returns>Single term value.</returns>\n    private static double ExpTerm(double x, int i) => Math.Pow(x, i) / (long)Factorial.Calculate(i);\n\n    /// <summary>\n    ///     Single term for sin(x) function approximation: (-1)^i * x^(2*i + 1) / (2*i + 1)!.\n    /// </summary>\n    /// <param name=\"x\">Given point.</param>\n    /// <param name=\"i\">Term index from 0 to n.</param>\n    /// <returns>Single term value.</returns>\n    private static double SinTerm(double x, int i) =>\n        Math.Pow(-1, i) / ((long)Factorial.Calculate(2 * i + 1)) * Math.Pow(x, 2 * i + 1);\n\n    /// <summary>\n    ///     Single term for cos(x) function approximation: (-1)^i * x^(2*i) / (2*i)!.\n    /// </summary>\n    /// <param name=\"x\">Given point.</param>\n    /// <param name=\"i\">Term index from 0 to n.</param>\n    /// <returns>Single term value.</returns>\n    private static double CosTerm(double x, int i) =>\n        Math.Pow(-1, i) / ((long)Factorial.Calculate(2 * i)) * Math.Pow(x, 2 * i);\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Sigmoid.cs",
    "content": "using System;\n\nnamespace Algorithms.Numeric;\n\n/// <summary>\n///     Provides the Sigmoid (Logistic) function, commonly used as an activation\n///     function in neural networks to squash values into the range (0, 1).\n///     Formula: sigma(x) = 1 / (1 + e^(-x)).\n/// </summary>\npublic static class Sigmoid\n{\n    /// <summary>\n    ///     Calculates the value of the Sigmoid function for a given input x.\n    /// </summary>\n    /// <param name=\"x\">The input number.</param>\n    /// <returns>The Sigmoid value, a double between 0 and 1.</returns>\n    public static double Calculate(double x)\n    {\n        // The Sigmoid function is 1 / (1 + e^(-x))\n        // We use Math.Exp(-x) to calculate e^(-x)\n        double exponent = Math.Exp(-x);\n\n        // The result is 1.0 divided by (1.0 + exponent)\n        return 1.0 / (1.0 + exponent);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/SoftMax.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     Implementation of the SoftMax function.\n///     Its a function that takes as input a vector of K real numbers, and normalizes\n///     it into a probability distribution consisting of K probabilities proportional\n///     to the exponentials of the input numbers. After softmax, the elements of the vector always sum up to 1.\n///     https://en.wikipedia.org/wiki/Softmax_function.\n/// </summary>\npublic static class SoftMax\n{\n    /// <summary>\n    ///    Compute the SoftMax function.\n    ///    The SoftMax function is defined as:\n    ///    softmax(x_i) = exp(x_i) / sum(exp(x_j)) for j = 1 to n\n    ///    where x_i is the i-th element of the input vector.\n    ///    The elements of the output vector are the probabilities of the input vector, the output sums up to 1.\n    /// </summary>\n    /// <param name=\"input\">The input vector of real numbers.</param>\n    /// <returns>The output vector of real numbers.</returns>\n    public static double[] Compute(double[] input)\n    {\n        if (input.Length == 0)\n        {\n            throw new ArgumentException(\"Array is empty.\");\n        }\n\n        var exponentVector = new double[input.Length];\n        var sum = 0.0;\n        for (var index = 0; index < input.Length; index++)\n        {\n            exponentVector[index] = Math.Exp(input[index]);\n            sum += exponentVector[index];\n        }\n\n        for (var index = 0; index < input.Length; index++)\n        {\n            exponentVector[index] /= sum;\n        }\n\n        return exponentVector;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/SumOfDigits.cs",
    "content": "using System;\n\nnamespace Algorithms.Numeric;\n\n/// <summary>\n///     Provides functionality to calculate the sum of the digits of an integer.\n/// </summary>\npublic static class SumOfDigits\n{\n    /// <summary>\n    ///     Calculates the sum of the digits of a non-negative integer.\n    ///     The method iteratively uses the modulus operator (%) to get the last digit\n    ///     and the division operator (/) to drop the last digit until the number is 0.\n    /// </summary>\n    /// <param name=\"number\">The non-negative integer whose digits are to be summed.</param>\n    /// <returns>The sum of the digits of the input number.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown if the input number is negative.</exception>\n    public static int Calculate(int number)\n    {\n        if (number < 0)\n        {\n            throw new ArgumentException(\"Input must be a non-negative integer.\", nameof(number));\n        }\n\n        if (number == 0)\n        {\n            return 0;\n        }\n\n        int sum = 0;\n        int currentNumber = number;\n\n        // Loop until the number becomes 0\n        while (currentNumber > 0)\n        {\n            // Get the last digit (e.g., 123 % 10 = 3)\n            int digit = currentNumber % 10;\n\n            // Add the digit to the sum\n            sum += digit;\n\n            // Remove the last digit (e.g., 123 / 10 = 12)\n            currentNumber /= 10;\n        }\n\n        return sum;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Numeric/Tanh.cs",
    "content": "namespace Algorithms.Numeric;\n\n/// <summary>\n///     Implementation of the Hyperbolic Tangent (Tanh) function.\n///     Tanh is an activation function that takes a real number as input and squashes\n///     the output to a range between -1 and 1.\n///     It is defined as: tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x)).\n///     https://en.wikipedia.org/wiki/Hyperbolic_function#Hyperbolic_tangent.\n/// </summary>\npublic static class Tanh\n{\n    /// <summary>\n    ///     Compute the Hyperbolic Tangent (Tanh) function for a single value.\n    ///     The Math.Tanh() method is used for efficient and accurate computation.\n    /// </summary>\n    /// <param name=\"input\">The input real number.</param>\n    /// <returns>The output real number in the range [-1, 1].</returns>\n    public static double Compute(double input)\n    {\n        // For a single double, we can directly use the optimized Math.Tanh method.\n        return Math.Tanh(input);\n    }\n\n    /// <summary>\n    ///     Compute the Hyperbolic Tangent (Tanh) function element-wise for a vector.\n    /// </summary>\n    /// <param name=\"input\">The input vector of real numbers.</param>\n    /// <returns>The output vector of real numbers, where each element is in the range [-1, 1].</returns>\n    public static double[] Compute(double[] input)\n    {\n        if (input is null)\n        {\n            throw new ArgumentNullException(nameof(input));\n        }\n\n        if (input.Length == 0)\n        {\n            throw new ArgumentException(\"Array is empty.\");\n        }\n\n        var outputVector = new double[input.Length];\n\n        for (var index = 0; index < input.Length; index++)\n        {\n            // Apply Tanh to each element using the optimized Math.Tanh method.\n            outputVector[index] = Math.Tanh(input[index]);\n        }\n\n        return outputVector;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/BoyerMooreMajorityVote.cs",
    "content": "namespace Algorithms.Other;\n\n/// <summary>\n/// Boyer-Moore Majority Vote algorithm.\n/// Finds element appearing more than n/2 times in O(n) time, O(1) space.\n/// </summary>\npublic static class BoyerMooreMajorityVote\n{\n    /// <summary>\n    /// Finds the majority element.\n    /// </summary>\n    /// <param name=\"nums\">Input array.</param>\n    /// <returns>Majority element or null.</returns>\n    public static int? FindMajority(int[] nums)\n    {\n        if (nums == null || nums.Length == 0)\n        {\n            return null;\n        }\n\n        var candidate = FindCandidate(nums);\n        return IsMajority(nums, candidate) ? candidate : null;\n    }\n\n    private static int FindCandidate(int[] nums)\n    {\n        int candidate = nums[0];\n        int count = 1;\n\n        for (int i = 1; i < nums.Length; i++)\n        {\n            if (count == 0)\n            {\n                candidate = nums[i];\n            }\n\n            count += nums[i] == candidate ? 1 : -1;\n        }\n\n        return candidate;\n    }\n\n    private static bool IsMajority(int[] nums, int candidate) =>\n        nums.Count(n => n == candidate) > nums.Length / 2;\n}\n"
  },
  {
    "path": "Algorithms/Other/DecisionsConvolutions.cs",
    "content": "namespace Algorithms.Other;\n\n/// <summary>\n/// Almost all real complex decision-making task is described by more than one criterion.\n/// There are different methods to select the best decisions from the defined set of decisions.\n/// This class contains implementations of the popular convolution methods: linear and maxmin.\n/// </summary>\npublic static class DecisionsConvolutions\n{\n    /// <summary>\n    /// This method implements the linear method of decision selection. It is based on\n    /// the calculation of the \"value\" for each decision and the selection of the most\n    /// valuable one.\n    /// </summary>\n    /// <param name=\"matrix\">Contains a collection of the criteria sets.</param>\n    /// <param name=\"priorities\">Contains a set of priorities for each criterion.</param>\n    /// <returns>The most effective decision that is represented by a set of criterias.</returns>\n    public static List<decimal> Linear(List<List<decimal>> matrix, List<decimal> priorities)\n    {\n        var decisionValues = new List<decimal>();\n\n        foreach (var decision in matrix)\n        {\n            decimal sum = 0;\n            for (int i = 0; i < decision.Count; i++)\n            {\n                sum += decision[i] * priorities[i];\n            }\n\n            decisionValues.Add(sum);\n        }\n\n        decimal bestDecisionValue = decisionValues.Max();\n        int bestDecisionIndex = decisionValues.IndexOf(bestDecisionValue);\n\n        return matrix[bestDecisionIndex];\n    }\n\n    /// <summary>\n    /// This method implements maxmin method of the decision selection. It is based on\n    /// the calculation of the least criteria value and comparison of decisions based\n    /// on the calculated results.\n    /// </summary>\n    /// <param name=\"matrix\">Contains a collection of the criteria sets.</param>\n    /// <param name=\"priorities\">Contains a set of priorities for each criterion.</param>\n    /// <returns>The most effective decision that is represented by a set of criterias.</returns>\n    public static List<decimal> MaxMin(List<List<decimal>> matrix, List<decimal> priorities)\n    {\n        var decisionValues = new List<decimal>();\n\n        foreach (var decision in matrix)\n        {\n            decimal minValue = decimal.MaxValue;\n            for (int i = 0; i < decision.Count; i++)\n            {\n                decimal result = decision[i] * priorities[i];\n                if (result < minValue)\n                {\n                    minValue = result;\n                }\n            }\n\n            decisionValues.Add(minValue);\n        }\n\n        decimal bestDecisionValue = decisionValues.Max();\n        int bestDecisionIndex = decisionValues.IndexOf(bestDecisionValue);\n\n        return matrix[bestDecisionIndex];\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/FermatPrimeChecker.cs",
    "content": "namespace Algorithms.Other;\n\n/// <summary>\n///     Fermat's prime tester https://en.wikipedia.org/wiki/Fermat_primality_test.\n/// </summary>\npublic static class FermatPrimeChecker\n{\n    /// <summary>\n    ///     Checks if input number is a probable prime.\n    /// </summary>\n    /// <param name=\"numberToTest\">Input number.</param>\n    /// <param name=\"timesToCheck\">Number of times to check.</param>\n    /// <returns>True if is a prime; False otherwise.</returns>\n    public static bool IsPrime(int numberToTest, int timesToCheck)\n    {\n        // You have to use BigInteger for two reasons:\n        //   1. The pow operation between two int numbers usually overflows an int\n        //   2. The pow and modular operation is very optimized\n        var numberToTestBigInteger = new BigInteger(numberToTest);\n        var exponentBigInteger = new BigInteger(numberToTest - 1);\n\n        // Create a random number generator using the current time as seed\n        var r = new Random(default(DateTime).Millisecond);\n\n        var iterator = 1;\n        var prime = true;\n\n        while (iterator < timesToCheck && prime)\n        {\n            var randomNumber = r.Next(1, numberToTest);\n            var randomNumberBigInteger = new BigInteger(randomNumber);\n            if (BigInteger.ModPow(randomNumberBigInteger, exponentBigInteger, numberToTestBigInteger) != 1)\n            {\n                prime = false;\n            }\n\n            iterator++;\n        }\n\n        return prime;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/FloodFill.cs",
    "content": "using SkiaSharp;\n\nnamespace Algorithms.Other;\n\n/// <summary>\n/// Flood fill, also called seed fill, is an algorithm that determines and\n/// alters the area connected to a given node in a multi-dimensional array with\n/// some matching attribute. It is used in the \"bucket\" fill tool of paint\n/// programs to fill connected, similarly-colored areas with a different color.\n/// (description adapted from https://en.wikipedia.org/wiki/Flood_fill)\n/// (see also: https://www.techiedelight.com/flood-fill-algorithm/).\n/// </summary>\npublic static class FloodFill\n{\n    private static readonly List<(int XOffset, int YOffset)> Neighbors = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)];\n\n    /// <summary>\n    /// Implements the flood fill algorithm through a breadth-first approach using a queue.\n    /// </summary>\n    /// <param name=\"bitmap\">The bitmap to which the algorithm is applied.</param>\n    /// <param name=\"location\">The start location on the bitmap.</param>\n    /// <param name=\"targetColor\">The old color to be replaced.</param>\n    /// <param name=\"replacementColor\">The new color to replace the old one.</param>\n    public static void BreadthFirstSearch(SKBitmap bitmap, (int X, int Y) location, SKColor targetColor, SKColor replacementColor)\n    {\n        if (location.X < 0 || location.X >= bitmap.Width || location.Y < 0 || location.Y >= bitmap.Height)\n        {\n            throw new ArgumentOutOfRangeException(nameof(location), $\"{nameof(location)} should point to a pixel within the bitmap\");\n        }\n\n        var queue = new List<(int X, int Y)>\n        {\n            location,\n        };\n\n        while (queue.Count > 0)\n        {\n            BreadthFirstFill(bitmap, location, targetColor, replacementColor, queue);\n        }\n    }\n\n    /// <summary>\n    /// Implements the flood fill algorithm through a depth-first approach through recursion.\n    /// </summary>\n    /// <param name=\"bitmap\">The bitmap to which the algorithm is applied.</param>\n    /// <param name=\"location\">The start location on the bitmap.</param>\n    /// <param name=\"targetColor\">The old color to be replaced.</param>\n    /// <param name=\"replacementColor\">The new color to replace the old one.</param>\n    public static void DepthFirstSearch(SKBitmap bitmap, (int X, int Y) location, SKColor targetColor, SKColor replacementColor)\n    {\n        if (location.X < 0 || location.X >= bitmap.Width || location.Y < 0 || location.Y >= bitmap.Height)\n        {\n            throw new ArgumentOutOfRangeException(nameof(location), $\"{nameof(location)} should point to a pixel within the bitmap\");\n        }\n\n        DepthFirstFill(bitmap, location, targetColor, replacementColor);\n    }\n\n    private static void BreadthFirstFill(SKBitmap bitmap, (int X, int Y) location, SKColor targetColor, SKColor replacementColor, List<(int X, int Y)> queue)\n    {\n        (int X, int Y) currentLocation = queue[0];\n        queue.RemoveAt(0);\n\n        if (bitmap.GetPixel(currentLocation.X, currentLocation.Y) == targetColor)\n        {\n            bitmap.SetPixel(currentLocation.X, currentLocation.Y, replacementColor);\n\n            for (int i = 0; i < Neighbors.Count; i++)\n            {\n                int x = currentLocation.X + Neighbors[i].XOffset;\n                int y = currentLocation.Y + Neighbors[i].YOffset;\n                if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height)\n                {\n                    queue.Add((x, y));\n                }\n            }\n        }\n    }\n\n    private static void DepthFirstFill(SKBitmap bitmap, (int X, int Y) location, SKColor targetColor, SKColor replacementColor)\n    {\n        if (bitmap.GetPixel(location.X, location.Y) == targetColor)\n        {\n            bitmap.SetPixel(location.X, location.Y, replacementColor);\n\n            for (int i = 0; i < Neighbors.Count; i++)\n            {\n                int x = location.X + Neighbors[i].XOffset;\n                int y = location.Y + Neighbors[i].YOffset;\n                if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height)\n                {\n                    DepthFirstFill(bitmap, (x, y), targetColor, replacementColor);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/GaussOptimization.cs",
    "content": "namespace Algorithms.Other;\n\n/// <summary>\n/// The Gaussian method (coordinate descent method) refers to zero-order methods in which only the value\n/// of the function Q(X) at different points in the space of variables is used to organize the search\n/// for the extremum. This reduces the overall computational cost of finding the extremum. Also in\n/// the Gaussian method, the procedures for finding and moving the operating point are simplified as\n/// much as possible.\n/// </summary>\npublic class GaussOptimization\n{\n    /// <summary>\n    /// Implementation of function extremum search by the Gauss optimization algorithm.\n    /// </summary>\n    /// <param name=\"func\">Function for which extremum has to be found.</param>\n    /// <param name=\"n\">This parameter identifies how much step size will be decreased each iteration.</param>\n    /// <param name=\"step\">The initial shift step.</param>\n    /// <param name=\"eps\">This value is used to control the accuracy of the optimization. In case if the error is less than eps,\n    /// optimization will be stopped.</param>\n    /// <param name=\"x1\">The first function parameter.</param>\n    /// <param name=\"x2\">The second function parameter.</param>\n    /// <returns>A tuple of coordinates of function extremum.</returns>\n    public (double X1, double X2) Optimize(\n        Func<double, double, double> func,\n        double n,\n        double step,\n        double eps,\n        double x1,\n        double x2)\n    {\n        // The initial value of the error\n        double error = 1;\n\n        while (Math.Abs(error) > eps)\n        {\n            // Calculation of the function with coordinates that are calculated with shift\n            double bottom = func(x1, x2 - step);\n            double top = func(x1, x2 + step);\n            double left = func(x1 - step, x2);\n            double right = func(x1 + step, x2);\n\n            // Determination of the best option.\n            var possibleFunctionValues = new List<double> { bottom, top, left, right };\n            double maxValue = possibleFunctionValues.Max();\n            double maxValueIndex = possibleFunctionValues.IndexOf(maxValue);\n\n            // Error evaluation\n            error = maxValue - func(x1, x2);\n\n            // Coordinates update for the best option\n            switch (maxValueIndex)\n            {\n                case 0:\n                    x2 -= step;\n                    break;\n                case 1:\n                    x2 += step;\n                    break;\n                case 2:\n                    x1 -= step;\n                    break;\n                default:\n                    x1 += step;\n                    break;\n            }\n\n            // Step reduction\n            step /= n;\n        }\n\n        return (x1, x2);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/GeoLocation.cs",
    "content": "namespace Algorithms.Other;\n\npublic static class GeoLocation\n{\n    private const double EarthRadiusKm = 6371.01d;\n\n    /// <summary>\n    ///     Calculates spherical distance between 2 points given their latitude, longitude coordinates.\n    ///     https://www.movable-type.co.uk/scripts/latlong.html.\n    /// </summary>\n    /// <param name=\"lat1\">Latitude of point A.</param>\n    /// <param name=\"lng1\">Longitude of point A.</param>\n    /// <param name=\"lat2\">Latitude of point B.</param>\n    /// <param name=\"lng2\">Longitude of point B.</param>\n    /// <returns>Spherical distance between A and B.</returns>\n    public static double CalculateDistanceFromLatLng(double lat1, double lng1, double lat2, double lng2)\n    {\n        var pi180 = Math.PI / 180d;\n        var lat1Radian = lat1 * pi180;\n        var lng1Radian = lng1 * pi180;\n        var lat2Radian = lat2 * pi180;\n        var lng2Radian = lng2 * pi180;\n\n        var diffLat = lat2Radian - lat1Radian;\n        var diffLng = lng2Radian - lng1Radian;\n\n        var haversine =\n            Math.Sin(diffLat / 2) * Math.Sin(diffLat / 2)\n            + Math.Cos(lat1Radian) * Math.Cos(lat2Radian) * Math.Sin(diffLng / 2) * Math.Sin(diffLng / 2);\n        var distance = EarthRadiusKm * (2d * Math.Atan2(Math.Sqrt(haversine), Math.Sqrt(1 - haversine)));\n\n        return distance * 1000; // Convert from km -> m\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/Geofence.cs",
    "content": "namespace Algorithms.Other;\n\npublic class Geofence(double latitude, double longitude, double radiusInMeters)\n{\n    public double Latitude { get; set; } = latitude;\n\n    public double Longitude { get; set; } = longitude;\n\n    public double RadiusInMeters { get; set; } = radiusInMeters;\n\n    /// <summary>\n    /// Checks whether the provided user location (latitude and longitude) is within the geofence boundary.\n    /// The geofence is defined by a center point (latitude, longitude) and a radius in meters.\n    /// </summary>\n    /// <param name=\"userLatitude\">The latitude of the user's current location.</param>\n    /// <param name=\"userLongitude\">The longitude of the user's current location.</param>\n    /// <returns>Returns true if the user is inside the geofence, otherwise returns false.</returns>\n    public bool IsInside(double userLatitude, double userLongitude)\n    {\n        double distance = GeoLocation.CalculateDistanceFromLatLng(Latitude, Longitude, userLatitude, userLongitude);\n        return distance <= RadiusInMeters;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/Geohash.cs",
    "content": "namespace Algorithms.Other;\n\npublic static class Geohash\n{\n    private const string Base32Characters = \"0123456789bcdefghjkmnpqrstuvwxyz\"; // Convert latitude and longitude coordinates into a concise string\n    private const int GeohashLength = 12; // ± 1.86 cm\n\n    /// <summary>\n    /// Encodes the provided latitude and longitude coordinates into a Geohash string.\n    /// Geohashing is a method to encode geographic coordinates (latitude, longitude).\n    /// into a short string of letters and digits. Each character in the resulting Geohash .\n    /// string adds more precision to the location. The longer the Geohash, the smaller the area.\n    /// </summary>\n    /// <param name=\"latitude\">The latitude of the location to encode. It must be a value between -90 and 90.</param>\n    /// <param name=\"longitude\">The longitude of the location to encode. It must be a value between -180 and 180.</param>\n    /// <returns>\n    /// A Geohash string of length 12 representing the location with high precision.\n    /// A longer Geohash provides higher precision in terms of geographic area.\n    /// and a 12-character Geohash can be accurate down to around 1.86 cm.\n    /// </returns>\n    public static string Encode(double latitude, double longitude)\n    {\n        double[] latitudeRange = [-90.0, 90.0];\n        double[] longitudeRange = [-180.0, 180.0];\n        bool isEncodingLongitude = true;\n        int currentBit = 0;\n        int base32Index = 0;\n        StringBuilder geohashResult = new StringBuilder();\n\n        while (geohashResult.Length < GeohashLength)\n        {\n            double midpoint;\n\n            if (isEncodingLongitude)\n            {\n                midpoint = (longitudeRange[0] + longitudeRange[1]) / 2;\n                if (longitude > midpoint)\n                {\n                    base32Index |= 1 << (4 - currentBit);\n                    longitudeRange[0] = midpoint;\n                }\n                else\n                {\n                    longitudeRange[1] = midpoint;\n                }\n            }\n            else\n            {\n                midpoint = (latitudeRange[0] + latitudeRange[1]) / 2;\n                if (latitude > midpoint)\n                {\n                    base32Index |= 1 << (4 - currentBit);\n                    latitudeRange[0] = midpoint;\n                }\n                else\n                {\n                    latitudeRange[1] = midpoint;\n                }\n            }\n\n            isEncodingLongitude = !isEncodingLongitude;\n\n            if (currentBit < 4)\n            {\n                currentBit++;\n            }\n            else\n            {\n                geohashResult.Append(Base32Characters[base32Index]);\n                currentBit = 0;\n                base32Index = 0;\n            }\n        }\n\n        return geohashResult.ToString();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/Int2Binary.cs",
    "content": "namespace Algorithms.Other;\n\n/// <summary>\n///     Manually converts an integer of certain size to a string of the binary representation.\n/// </summary>\npublic static class Int2Binary\n{\n    /// <summary>\n    ///     Returns string of the binary representation of given Int.\n    /// </summary>\n    /// <param name=\"input\">Number to be converted.</param>\n    /// <returns>Binary representation of input.</returns>\n    public static string Int2Bin(ushort input)\n    {\n        ushort msb = ushort.MaxValue / 2 + 1;\n        var output = new StringBuilder();\n        for (var i = 0; i < 16; i++)\n        {\n            if (input >= msb)\n            {\n                output.Append(\"1\");\n                input -= msb;\n                msb /= 2;\n            }\n            else\n            {\n                output.Append(\"0\");\n                msb /= 2;\n            }\n        }\n\n        return output.ToString();\n    }\n\n    /// <summary>\n    ///     Returns string of the binary representation of given Int.\n    /// </summary>\n    /// <param name=\"input\">Number to be converted.</param>\n    /// <returns>Binary representation of input.</returns>\n    public static string Int2Bin(uint input)\n    {\n        var msb = uint.MaxValue / 2 + 1;\n        var output = new StringBuilder();\n        for (var i = 0; i < 32; i++)\n        {\n            if (input >= msb)\n            {\n                output.Append(\"1\");\n                input -= msb;\n                msb /= 2;\n            }\n            else\n            {\n                output.Append(\"0\");\n                msb /= 2;\n            }\n        }\n\n        return output.ToString();\n    }\n\n    /// <summary>\n    ///     Returns string of the binary representation of given Int.\n    /// </summary>\n    /// <param name=\"input\">Number to be converted.</param>\n    /// <returns>Binary representation of input.</returns>\n    public static string Int2Bin(ulong input)\n    {\n        var msb = ulong.MaxValue / 2 + 1;\n        var output = new StringBuilder();\n        for (var i = 0; i < 64; i++)\n        {\n            if (input >= msb)\n            {\n                output.Append(\"1\");\n                input -= msb;\n                msb /= 2;\n            }\n            else\n            {\n                output.Append(\"0\");\n                msb /= 2;\n            }\n        }\n\n        return output.ToString();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/JulianEaster.cs",
    "content": "namespace Algorithms.Other;\n\n/// <summary>\n///     Date of Easter calculated with Meeus's Julian algorithm.\n///     The algorithm is described in Jean Meeus' <a href=\"https://archive.org/details/astronomicalalgorithmsjeanmeeus1991/page/n73/mode/2up\">Astronomical Algorithms (1991, p. 69)</a>.\n/// </summary>\npublic static class JulianEaster\n{\n    /// <summary>\n    ///     Calculates the date of Easter.\n    /// </summary>\n    /// <param name=\"year\">Year to calculate the date of Easter.</param>\n    /// <returns>Date of Easter as a DateTime.</returns>\n    public static DateTime Calculate(int year)\n    {\n        var a = year % 4;\n        var b = year % 7;\n        var c = year % 19;\n        var d = (19 * c + 15) % 30;\n        var e = (2 * a + 4 * b - d + 34) % 7;\n        var month = (int)Math.Floor((d + e + 114) / 31M);\n        var day = ((d + e + 114) % 31) + 1;\n\n        DateTime easter = new(year, month, day, 00, 00, 00, DateTimeKind.Utc);\n\n        return easter;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/KadanesAlgorithm.cs",
    "content": "namespace Algorithms.Other;\n\n/// <summary>\n///     Kadane's Algorithm is used to find the maximum sum of a contiguous subarray\n///     within a one-dimensional array of numbers. It has a time complexity of O(n).\n///     This algorithm is a classic example of dynamic programming.\n///     Reference: \"Introduction to Algorithms\" by Cormen, Leiserson, Rivest, and Stein (CLRS).\n/// </summary>\npublic static class KadanesAlgorithm\n{\n    /// <summary>\n    ///     Finds the maximum sum of a contiguous subarray using Kadane's Algorithm.\n    ///     The algorithm works by maintaining two variables:\n    ///     - maxSoFar: The maximum sum found so far (global maximum)\n    ///     - maxEndingHere: The maximum sum of subarray ending at current position (local maximum)\n    ///     At each position, we decide whether to extend the existing subarray or start a new one.\n    /// </summary>\n    /// <param name=\"array\">The input array of integers.</param>\n    /// <returns>The maximum sum of a contiguous subarray.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown when the input array is null or empty.</exception>\n    /// <example>\n    ///     Input: [-2, 1, -3, 4, -1, 2, 1, -5, 4].\n    ///     Output: 6 (subarray [4, -1, 2, 1]).\n    /// </example>\n    public static int FindMaximumSubarraySum(int[] array)\n    {\n        // Validate input to ensure array is not null or empty\n        if (array == null || array.Length == 0)\n        {\n            throw new ArgumentException(\"Array cannot be null or empty.\", nameof(array));\n        }\n\n        // Initialize both variables with the first element\n        // maxSoFar tracks the best sum we've seen across all subarrays\n        int maxSoFar = array[0];\n\n        // maxEndingHere tracks the best sum ending at the current position\n        int maxEndingHere = array[0];\n\n        // Iterate through the array starting from the second element\n        for (int i = 1; i < array.Length; i++)\n        {\n            // Key decision: Either extend the current subarray or start fresh\n            // If adding current element to existing sum is worse than the element alone,\n            // it's better to start a new subarray from current element\n            maxEndingHere = Math.Max(array[i], maxEndingHere + array[i]);\n\n            // Update the global maximum if current subarray sum is better\n            maxSoFar = Math.Max(maxSoFar, maxEndingHere);\n        }\n\n        return maxSoFar;\n    }\n\n    /// <summary>\n    ///     Finds the maximum sum of a contiguous subarray and returns the start and end indices.\n    ///     This variant tracks the indices of the maximum subarray in addition to the sum.\n    ///     Useful when you need to know which elements form the maximum subarray.\n    /// </summary>\n    /// <param name=\"array\">The input array of integers.</param>\n    /// <returns>A tuple containing the maximum sum, start index, and end index.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown when the input array is null or empty.</exception>\n    /// <example>\n    ///     Input: [-2, 1, -3, 4, -1, 2, 1, -5, 4].\n    ///     Output: (MaxSum: 6, StartIndex: 3, EndIndex: 6).\n    ///     The subarray is [4, -1, 2, 1].\n    /// </example>\n    public static (int MaxSum, int StartIndex, int EndIndex) FindMaximumSubarrayWithIndices(int[] array)\n    {\n        // Validate input\n        if (array == null || array.Length == 0)\n        {\n            throw new ArgumentException(\"Array cannot be null or empty.\", nameof(array));\n        }\n\n        // Initialize tracking variables\n        int maxSoFar = array[0];        // Global maximum sum\n        int maxEndingHere = array[0];   // Local maximum sum ending at current position\n        int start = 0;                   // Start index of the maximum subarray\n        int end = 0;                     // End index of the maximum subarray\n        int tempStart = 0;               // Temporary start index for current subarray\n\n        // Process each element starting from index 1\n        for (int i = 1; i < array.Length; i++)\n        {\n            // Decide whether to extend current subarray or start a new one\n            if (array[i] > maxEndingHere + array[i])\n            {\n                // Starting fresh from current element is better\n                maxEndingHere = array[i];\n                tempStart = i;  // Mark this as potential start of new subarray\n            }\n            else\n            {\n                // Extending the current subarray is better\n                maxEndingHere = maxEndingHere + array[i];\n            }\n\n            // Update global maximum and indices if we found a better subarray\n            if (maxEndingHere > maxSoFar)\n            {\n                maxSoFar = maxEndingHere;\n                start = tempStart;  // Commit the start index\n                end = i;            // Current position is the end\n            }\n        }\n\n        return (maxSoFar, start, end);\n    }\n\n    /// <summary>\n    ///     Finds the maximum sum of a contiguous subarray using Kadane's Algorithm for long integers.\n    ///     This overload handles larger numbers that exceed int range (up to 2^63 - 1).\n    ///     The algorithm logic is identical to the int version but uses long arithmetic.\n    /// </summary>\n    /// <param name=\"array\">The input array of long integers.</param>\n    /// <returns>The maximum sum of a contiguous subarray.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown when the input array is null or empty.</exception>\n    /// <example>\n    ///     Input: [1000000000L, -500000000L, 1000000000L].\n    ///     Output: 1500000000L (entire array).\n    /// </example>\n    public static long FindMaximumSubarraySum(long[] array)\n    {\n        // Validate input\n        if (array == null || array.Length == 0)\n        {\n            throw new ArgumentException(\"Array cannot be null or empty.\", nameof(array));\n        }\n\n        // Initialize with first element (using long arithmetic)\n        long maxSoFar = array[0];\n        long maxEndingHere = array[0];\n\n        // Apply Kadane's algorithm with long values\n        for (int i = 1; i < array.Length; i++)\n        {\n            // Decide: extend current subarray or start new one\n            maxEndingHere = Math.Max(array[i], maxEndingHere + array[i]);\n\n            // Update global maximum\n            maxSoFar = Math.Max(maxSoFar, maxEndingHere);\n        }\n\n        return maxSoFar;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/KochSnowflake.cs",
    "content": "using SkiaSharp;\n\nnamespace Algorithms.Other;\n\n/// <summary>\n///     The Koch snowflake is a fractal curve and one of the earliest fractals to\n///     have been described. The Koch snowflake can be built up iteratively, in a\n///     sequence of stages. The first stage is an equilateral triangle, and each\n///     successive stage is formed by adding outward bends to each side of the\n///     previous stage, making smaller equilateral triangles.\n///     This can be achieved through the following steps for each line:\n///     1. divide the line segment into three segments of equal length.\n///     2. draw an equilateral triangle that has the middle segment from step 1\n///     as its base and points outward.\n///     3. remove the line segment that is the base of the triangle from step 2.\n///     (description adapted from https://en.wikipedia.org/wiki/Koch_snowflake )\n///     (for a more detailed explanation and an implementation in the\n///     Processing language, see  https://natureofcode.com/book/chapter-8-fractals/\n///     #84-the-koch-curve-and-the-arraylist-technique ).\n/// </summary>\npublic static class KochSnowflake\n{\n    /// <summary>\n    ///     Go through the number of iterations determined by the argument \"steps\".\n    ///     Be careful with high values (above 5) since the time to calculate increases\n    ///     exponentially.\n    /// </summary>\n    /// <param name=\"initialVectors\">\n    ///     The vectors composing the shape to which\n    ///     the algorithm is applied.\n    /// </param>\n    /// <param name=\"steps\">The number of iterations.</param>\n    /// <returns>The transformed vectors after the iteration-steps.</returns>\n    public static List<Vector2> Iterate(List<Vector2> initialVectors, int steps = 5)\n    {\n        List<Vector2> vectors = initialVectors;\n        for (var i = 0; i < steps; i++)\n        {\n            vectors = IterationStep(vectors);\n        }\n\n        return vectors;\n    }\n\n    /// <summary>\n    ///     Method to render the Koch snowflake to a bitmap. To save the\n    ///     bitmap the command 'GetKochSnowflake().Save(\"KochSnowflake.png\")' can be used.\n    /// </summary>\n    /// <param name=\"bitmapWidth\">The width of the rendered bitmap.</param>\n    /// <param name=\"steps\">The number of iterations.</param>\n    /// <returns>The bitmap of the rendered Koch snowflake.</returns>\n    public static SKBitmap GetKochSnowflake(\n        int bitmapWidth = 600,\n        int steps = 5)\n    {\n        if (bitmapWidth <= 0)\n        {\n            throw new ArgumentOutOfRangeException(\n                nameof(bitmapWidth),\n                $\"{nameof(bitmapWidth)} should be greater than zero\");\n        }\n\n        var offsetX = bitmapWidth / 10f;\n        var offsetY = bitmapWidth / 3.7f;\n        var vector1 = new Vector2(offsetX, offsetY);\n        var vector2 = new Vector2(bitmapWidth / 2, (float)Math.Sin(Math.PI / 3) * bitmapWidth * 0.8f + offsetY);\n        var vector3 = new Vector2(bitmapWidth - offsetX, offsetY);\n        List<Vector2> initialVectors = [vector1, vector2, vector3, vector1];\n        List<Vector2> vectors = Iterate(initialVectors, steps);\n        return GetBitmap(vectors, bitmapWidth, bitmapWidth);\n    }\n\n    /// <summary>\n    ///     Loops through each pair of adjacent vectors. Each line between two adjacent\n    ///     vectors is divided into 4 segments by adding 3 additional vectors in-between\n    ///     the original two vectors. The vector in the middle is constructed through a\n    ///     60 degree rotation so it is bent outwards.\n    /// </summary>\n    /// <param name=\"vectors\">\n    ///     The vectors composing the shape to which\n    ///     the algorithm is applied.\n    /// </param>\n    /// <returns>The transformed vectors after the iteration-step.</returns>\n    private static List<Vector2> IterationStep(List<Vector2> vectors)\n    {\n        List<Vector2> newVectors = [];\n        for (var i = 0; i < vectors.Count - 1; i++)\n        {\n            var startVector = vectors[i];\n            var endVector = vectors[i + 1];\n            newVectors.Add(startVector);\n            var differenceVector = endVector - startVector;\n            newVectors.Add(startVector + differenceVector / 3);\n            newVectors.Add(startVector + differenceVector / 3 + Rotate(differenceVector / 3, 60));\n            newVectors.Add(startVector + differenceVector * 2 / 3);\n        }\n\n        newVectors.Add(vectors[^1]);\n        return newVectors;\n    }\n\n    /// <summary>\n    ///     Standard rotation of a 2D vector with a rotation matrix\n    ///     (see https://en.wikipedia.org/wiki/Rotation_matrix ).\n    /// </summary>\n    /// <param name=\"vector\">The vector to be rotated.</param>\n    /// <param name=\"angleInDegrees\">The angle by which to rotate the vector.</param>\n    /// <returns>The rotated vector.</returns>\n    private static Vector2 Rotate(Vector2 vector, float angleInDegrees)\n    {\n        var radians = angleInDegrees * (float)Math.PI / 180;\n        var ca = (float)Math.Cos(radians);\n        var sa = (float)Math.Sin(radians);\n        return new Vector2(ca * vector.X - sa * vector.Y, sa * vector.X + ca * vector.Y);\n    }\n\n    /// <summary>\n    ///     Utility-method to render the Koch snowflake to a bitmap.\n    /// </summary>\n    /// <param name=\"vectors\">The vectors defining the edges to be rendered.</param>\n    /// <param name=\"bitmapWidth\">The width of the rendered bitmap.</param>\n    /// <param name=\"bitmapHeight\">The height of the rendered bitmap.</param>\n    /// <returns>The bitmap of the rendered edges.</returns>\n    private static SKBitmap GetBitmap(\n        List<Vector2> vectors,\n        int bitmapWidth,\n        int bitmapHeight)\n    {\n        SKBitmap bitmap = new(bitmapWidth, bitmapHeight);\n        var canvas = new SKCanvas(bitmap);\n\n        // Set the background white\n        var rect = SKRect.Create(0, 0, bitmapWidth, bitmapHeight);\n\n        var paint = new SKPaint\n        {\n            Style = SKPaintStyle.Fill,\n            Color = SKColors.White,\n        };\n\n        canvas.DrawRect(rect, paint);\n\n        paint.Color = SKColors.Black;\n\n        // Draw the edges\n        for (var i = 0; i < vectors.Count - 1; i++)\n        {\n            var x1 = vectors[i].X;\n            var y1 = vectors[i].Y;\n            var x2 = vectors[i + 1].X;\n            var y2 = vectors[i + 1].Y;\n\n            canvas.DrawLine(new SKPoint(x1, y1), new SKPoint(x2, y2), paint);\n        }\n\n        return bitmap;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/Luhn.cs",
    "content": "namespace Algorithms.Other;\n\n/// <summary>\n///     Luhn algorithm is a simple\n///     checksum formula used to validate\n///     a variety of identification numbers,\n///     such as credit card numbers.\n///     More information on the link:\n///     https://en.wikipedia.org/wiki/Luhn_algorithm.\n/// </summary>\npublic static class Luhn\n{\n    /// <summary>\n    ///     Checking the validity of a sequence of numbers.\n    /// </summary>\n    /// <param name=\"number\">The number that will be checked for validity.</param>\n    /// <returns>\n    ///     True: Number is valid.\n    ///     False: Number isn`t valid.\n    /// </returns>\n    public static bool Validate(string number) => GetSum(number) % 10 == 0;\n\n    /// <summary>\n    ///     This algorithm finds one missing digit.\n    ///     In place of the unknown digit, put \"x\".\n    /// </summary>\n    /// <param name=\"number\">The number in which to find the missing digit.</param>\n    /// <returns>Missing digit.</returns>\n    public static int GetLostNum(string number)\n    {\n        var missingDigitIndex = number.Length - 1 - number.LastIndexOf(\"x\", StringComparison.CurrentCultureIgnoreCase);\n        var checkDigit = GetSum(number.Replace(\"x\", \"0\", StringComparison.CurrentCultureIgnoreCase)) * 9 % 10;\n\n        return missingDigitIndex % 2 == 0\n            ? checkDigit\n            : Validate(number.Replace(\"x\", (checkDigit / 2).ToString()))\n                ? checkDigit / 2\n                : (checkDigit + 9) / 2;\n    }\n\n    /// <summary>\n    ///     Computes the sum found by the Luhn algorithm.\n    /// </summary>\n    /// <param name=\"number\">The number for which the sum will be calculated.</param>\n    /// <returns>Sum.</returns>\n    private static int GetSum(string number)\n    {\n        var sum = 0;\n        var span = number.AsSpan();\n        for (var i = 0; i < span.Length; i++)\n        {\n            var c = span[i];\n            if (c is < '0' or > '9')\n            {\n                continue;\n            }\n\n            var digit = c - '0';\n            digit = (i + span.Length) % 2 == 0 ? 2 * digit : digit;\n            if (digit > 9)\n            {\n                digit -= 9;\n            }\n\n            sum += digit;\n        }\n\n        return sum;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/Mandelbrot.cs",
    "content": "using SkiaSharp;\n\nnamespace Algorithms.Other;\n\n/// <summary>\n///     The Mandelbrot set is the set of complex numbers \"c\" for which the series\n///     \"z_(n+1) = z_n * z_n + c\" does not diverge, i.e. remains bounded. Thus, a\n///     complex number \"c\" is a member of the Mandelbrot set if, when starting with\n///     \"z_0 = 0\" and applying the iteration repeatedly, the absolute value of\n///     \"z_n\" remains bounded for all \"n > 0\". Complex numbers can be written as\n///     \"a + b*i\": \"a\" is the real component, usually drawn on the x-axis, and \"b*i\"\n///     is the imaginary component, usually drawn on the y-axis. Most visualizations\n///     of the Mandelbrot set use a color-coding to indicate after how many steps in\n///     the series the numbers outside the set cross the divergence threshold.\n///     Images of the Mandelbrot set exhibit an elaborate and infinitely\n///     complicated boundary that reveals progressively ever-finer recursive detail\n///     at increasing magnifications, making the boundary of the Mandelbrot set a\n///     fractal curve.\n///     (description adapted from https://en.wikipedia.org/wiki/Mandelbrot_set)\n///     (see also https://en.wikipedia.org/wiki/Plotting_algorithms_for_the_Mandelbrot_set).\n/// </summary>\npublic static class Mandelbrot\n{\n    private const byte Alpha = 255;\n\n    /// <summary>\n    ///     Method to generate the bitmap of the Mandelbrot set. Two types of coordinates\n    ///     are used: bitmap-coordinates that refer to the pixels and figure-coordinates\n    ///     that refer to the complex numbers inside and outside the Mandelbrot set. The\n    ///     figure-coordinates in the arguments of this method determine which section\n    ///     of the Mandelbrot set is viewed. The main area of the Mandelbrot set is\n    ///     roughly between \"-1.5 &lt; x &lt; 0.5\" and \"-1 &lt; y &lt; 1\" in the figure-coordinates.\n    ///     To save the bitmap the command 'GetBitmap().Save(\"Mandelbrot.png\")' can be used.\n    /// </summary>\n    /// <param name=\"bitmapWidth\">The width of the rendered bitmap.</param>\n    /// <param name=\"bitmapHeight\">The height of the rendered bitmap.</param>\n    /// <param name=\"figureCenterX\">The x-coordinate of the center of the figure.</param>\n    /// <param name=\"figureCenterY\">The y-coordinate of the center of the figure.</param>\n    /// <param name=\"figureWidth\">The width of the figure.</param>\n    /// <param name=\"maxStep\">Maximum number of steps to check for divergent behavior.</param>\n    /// <param name=\"useDistanceColorCoding\">Render in color or black and white.</param>\n    /// <returns>The bitmap of the rendered Mandelbrot set.</returns>\n    public static SKBitmap GetBitmap(\n        int bitmapWidth = 800,\n        int bitmapHeight = 600,\n        double figureCenterX = -0.6,\n        double figureCenterY = 0,\n        double figureWidth = 3.2,\n        int maxStep = 50,\n        bool useDistanceColorCoding = true)\n    {\n        if (bitmapWidth <= 0)\n        {\n            throw new ArgumentOutOfRangeException(\n                nameof(bitmapWidth),\n                $\"{nameof(bitmapWidth)} should be greater than zero\");\n        }\n\n        if (bitmapHeight <= 0)\n        {\n            throw new ArgumentOutOfRangeException(\n                nameof(bitmapHeight),\n                $\"{nameof(bitmapHeight)} should be greater than zero\");\n        }\n\n        if (maxStep <= 0)\n        {\n            throw new ArgumentOutOfRangeException(\n                nameof(maxStep),\n                $\"{nameof(maxStep)} should be greater than zero\");\n        }\n\n        var bitmap = new SKBitmap(bitmapWidth, bitmapHeight);\n        var figureHeight = figureWidth / bitmapWidth * bitmapHeight;\n\n        // loop through the bitmap-coordinates\n        for (var bitmapX = 0; bitmapX < bitmapWidth; bitmapX++)\n        {\n            for (var bitmapY = 0; bitmapY < bitmapHeight; bitmapY++)\n            {\n                // determine the figure-coordinates based on the bitmap-coordinates\n                var figureX = figureCenterX + ((double)bitmapX / bitmapWidth - 0.5) * figureWidth;\n                var figureY = figureCenterY + ((double)bitmapY / bitmapHeight - 0.5) * figureHeight;\n\n                var distance = GetDistance(figureX, figureY, maxStep);\n\n                // color the corresponding pixel based on the selected coloring-function\n                bitmap.SetPixel(\n                    bitmapX,\n                    bitmapY,\n                    useDistanceColorCoding ? ColorCodedColorMap(distance) : BlackAndWhiteColorMap(distance));\n            }\n        }\n\n        return bitmap;\n    }\n\n    /// <summary>\n    ///     Black and white color-coding that ignores the relative distance. The Mandelbrot\n    ///     set is black, everything else is white.\n    /// </summary>\n    /// <param name=\"distance\">Distance until divergence threshold.</param>\n    /// <returns>The color corresponding to the distance.</returns>\n    private static SKColor BlackAndWhiteColorMap(double distance) =>\n        distance >= 1\n            ? new SKColor(0, 0, 0, Alpha)\n            : new SKColor(255, 255, 255, Alpha);\n\n    /// <summary>\n    ///     Color-coding taking the relative distance into account. The Mandelbrot set\n    ///     is black.\n    /// </summary>\n    /// <param name=\"distance\">Distance until divergence threshold.</param>\n    /// <returns>The color corresponding to the distance.</returns>\n    private static SKColor ColorCodedColorMap(double distance)\n    {\n        if (distance >= 1)\n        {\n            return new SKColor(0, 0, 0, Alpha);\n        }\n\n        // simplified transformation of HSV to RGB\n        // distance determines hue\n        var hue = 360 * distance;\n        double saturation = 1;\n        double val = 255;\n        var hi = (int)Math.Floor(hue / 60) % 6;\n        var f = hue / 60 - Math.Floor(hue / 60);\n\n        var v = (byte)val;\n        const byte p = 0;\n        var q = (byte)(val * (1 - f * saturation));\n        var t = (byte)(val * (1 - (1 - f) * saturation));\n\n        switch (hi)\n        {\n            case 0: return new SKColor(v, t, p, Alpha);\n            case 1: return new SKColor(q, v, p, Alpha);\n            case 2: return new SKColor(p, v, t, Alpha);\n            case 3: return new SKColor(p, q, v, Alpha);\n            case 4: return new SKColor(t, p, v, Alpha);\n            default: return new SKColor(v, p, q, Alpha);\n        }\n    }\n\n    /// <summary>\n    ///     Return the relative distance (ratio of steps taken to maxStep) after which the complex number\n    ///     constituted by this x-y-pair diverges. Members of the Mandelbrot set do not\n    ///     diverge so their distance is 1.\n    /// </summary>\n    /// <param name=\"figureX\">The x-coordinate within the figure.</param>\n    /// <param name=\"figureY\">The y-coordinate within the figure.</param>\n    /// <param name=\"maxStep\">Maximum number of steps to check for divergent behavior.</param>\n    /// <returns>The relative distance as the ratio of steps taken to maxStep.</returns>\n    private static double GetDistance(double figureX, double figureY, int maxStep)\n    {\n        var a = figureX;\n        var b = figureY;\n        var currentStep = 0;\n        for (var step = 0; step < maxStep; step++)\n        {\n            currentStep = step;\n            var aNew = a * a - b * b + figureX;\n            b = 2 * a * b + figureY;\n            a = aNew;\n\n            // divergence happens for all complex number with an absolute value\n            // greater than 4 (= divergence threshold)\n            if (a * a + b * b > 4)\n            {\n                break;\n            }\n        }\n\n        return (double)currentStep / (maxStep - 1);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/ParetoOptimization.cs",
    "content": "namespace Algorithms.Other;\n\n/// <summary>\n/// Almost all real complex decision-making task is described by more than one criterion.\n/// Therefore, the methods of multicriteria optimization are important. For a wide range\n/// of tasks multicriteria optimization, described by some axioms of \"reasonable\"\n/// behavior in the process of choosing from a set of possible solutions X, each set of\n/// selected solutions Sel X should be contained in a set optimal for Pareto.\n/// </summary>\npublic class ParetoOptimization\n{\n    /// <summary>\n    /// Performs decision optimizations by using Paretor's optimization algorithm.\n    /// </summary>\n    /// <param name=\"matrix\">Contains a collection of the criterias sets.</param>\n    /// <returns>An optimized collection of the criterias sets.</returns>\n    public List<List<decimal>> Optimize(List<List<decimal>> matrix)\n    {\n        var optimizedMatrix = new List<List<decimal>>(matrix.Select(i => i));\n        int i = 0;\n        while (i < optimizedMatrix.Count)\n        {\n            for (int j = i + 1; j < optimizedMatrix.Count; j++)\n            {\n                decimal directParwiseDifference = GetMinimalPairwiseDifference(optimizedMatrix[i], optimizedMatrix[j]);\n                decimal indirectParwiseDifference = GetMinimalPairwiseDifference(optimizedMatrix[j], optimizedMatrix[i]);\n                /*\n                 * in case all criteria of one set are larger that the criteria of another, this\n                 * decision is not optimal and it has to be removed\n                */\n                if (directParwiseDifference >= 0 || indirectParwiseDifference >= 0)\n                {\n                    optimizedMatrix.RemoveAt(directParwiseDifference >= 0 ? j : i);\n                    i--;\n                    break;\n                }\n            }\n\n            i++;\n        }\n\n        return optimizedMatrix;\n    }\n\n    /// <summary>\n    /// Calculates the smallest difference between criteria of input decisions.\n    /// </summary>\n    /// <param name=\"arr1\">Criterias of the first decision.</param>\n    /// <param name=\"arr2\">Criterias of the second decision.</param>\n    /// <returns>Values that represent the smallest difference between criteria of input decisions.</returns>\n    private decimal GetMinimalPairwiseDifference(List<decimal> arr1, List<decimal> arr2)\n    {\n        decimal min = decimal.MaxValue;\n        if (arr1.Count == arr2.Count)\n        {\n            for (int i = 0; i < arr1.Count; i++)\n            {\n                decimal difference = arr1[i] - arr2[i];\n                if (min > difference)\n                {\n                    min = difference;\n                }\n            }\n        }\n\n        return min;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/PollardsRhoFactorizing.cs",
    "content": "using Algorithms.Numeric.GreatestCommonDivisor;\n\nnamespace Algorithms.Other;\n\n/// <summary>Implementation of the Pollard's rho algorithm.\n/// Algorithm for integer factorization.\n/// Wiki: https://en.wikipedia.org/wiki/Pollard's_rho_algorithm.\n/// </summary>\npublic static class PollardsRhoFactorizing\n{\n    public static int Calculate(int number)\n    {\n        var x = 2;\n        var y = 2;\n        var d = 1;\n        var p = number;\n        var i = 0;\n        var gcd = new BinaryGreatestCommonDivisorFinder();\n\n        while (d == 1)\n        {\n            x = Fun_g(x, p);\n            y = Fun_g(Fun_g(y, p), p);\n            d = gcd.FindGcd(Math.Abs(x - y), p);\n            i++;\n        }\n\n        return d;\n    }\n\n    private static int Fun_g(int x, int p)\n    {\n        return (x * x + 1) % p;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/RGBHSVConversion.cs",
    "content": "namespace Algorithms.Other;\n\n/// <summary>\n///     The RGB color model is an additive color model in which red, green, and\n///     blue light are added together in various ways to reproduce a broad array of\n///     colors. The name of the model comes from the initials of the three additive\n///     primary colors, red, green, and blue. Meanwhile, the HSV representation\n///     models how colors appear under light. In it, colors are represented using\n///     three components: hue, saturation and (brightness-)value. This class\n///     provides methods for converting colors from one representation to the other.\n///     (description adapted from https://en.wikipedia.org/wiki/RGB_color_model and\n///     https://en.wikipedia.org/wiki/HSL_and_HSV).\n/// </summary>\npublic static class RgbHsvConversion\n{\n    /// <summary>\n    ///     Conversion from the HSV-representation to the RGB-representation.\n    /// </summary>\n    /// <param name=\"hue\">Hue of the color.</param>\n    /// <param name=\"saturation\">Saturation of the color.</param>\n    /// <param name=\"value\">Brightness-value of the color.</param>\n    /// <returns>The tuple of RGB-components.</returns>\n    public static (byte Red, byte Green, byte Blue) HsvToRgb(\n        double hue,\n        double saturation,\n        double value)\n    {\n        if (hue < 0 || hue > 360)\n        {\n            throw new ArgumentOutOfRangeException(nameof(hue), $\"{nameof(hue)} should be between 0 and 360\");\n        }\n\n        if (saturation < 0 || saturation > 1)\n        {\n            throw new ArgumentOutOfRangeException(\n                nameof(saturation),\n                $\"{nameof(saturation)} should be between 0 and 1\");\n        }\n\n        if (value < 0 || value > 1)\n        {\n            throw new ArgumentOutOfRangeException(nameof(value), $\"{nameof(value)} should be between 0 and 1\");\n        }\n\n        var chroma = value * saturation;\n        var hueSection = hue / 60;\n        var secondLargestComponent = chroma * (1 - Math.Abs(hueSection % 2 - 1));\n        var matchValue = value - chroma;\n\n        return GetRgbBySection(hueSection, chroma, matchValue, secondLargestComponent);\n    }\n\n    /// <summary>\n    ///     Conversion from the RGB-representation to the HSV-representation.\n    /// </summary>\n    /// <param name=\"red\">Red-component of the color.</param>\n    /// <param name=\"green\">Green-component of the color.</param>\n    /// <param name=\"blue\">Blue-component of the color.</param>\n    /// <returns>The tuple of HSV-components.</returns>\n    public static (double Hue, double Saturation, double Value) RgbToHsv(\n        byte red,\n        byte green,\n        byte blue)\n    {\n        var dRed = (double)red / 255;\n        var dGreen = (double)green / 255;\n        var dBlue = (double)blue / 255;\n        var value = Math.Max(Math.Max(dRed, dGreen), dBlue);\n        var chroma = value - Math.Min(Math.Min(dRed, dGreen), dBlue);\n        var saturation = value.Equals(0) ? 0 : chroma / value;\n        double hue;\n\n        if (chroma.Equals(0))\n        {\n            hue = 0;\n        }\n        else if (value.Equals(dRed))\n        {\n            hue = 60 * (0 + (dGreen - dBlue) / chroma);\n        }\n        else if (value.Equals(dGreen))\n        {\n            hue = 60 * (2 + (dBlue - dRed) / chroma);\n        }\n        else\n        {\n            hue = 60 * (4 + (dRed - dGreen) / chroma);\n        }\n\n        hue = (hue + 360) % 360;\n\n        return (hue, saturation, value);\n    }\n\n    private static (byte Red, byte Green, byte Blue) GetRgbBySection(\n        double hueSection,\n        double chroma,\n        double matchValue,\n        double secondLargestComponent)\n    {\n        byte red;\n        byte green;\n        byte blue;\n\n        if (hueSection >= 0 && hueSection <= 1)\n        {\n            red = ConvertToByte(chroma + matchValue);\n            green = ConvertToByte(secondLargestComponent + matchValue);\n            blue = ConvertToByte(matchValue);\n        }\n        else if (hueSection > 1 && hueSection <= 2)\n        {\n            red = ConvertToByte(secondLargestComponent + matchValue);\n            green = ConvertToByte(chroma + matchValue);\n            blue = ConvertToByte(matchValue);\n        }\n        else if (hueSection > 2 && hueSection <= 3)\n        {\n            red = ConvertToByte(matchValue);\n            green = ConvertToByte(chroma + matchValue);\n            blue = ConvertToByte(secondLargestComponent + matchValue);\n        }\n        else if (hueSection > 3 && hueSection <= 4)\n        {\n            red = ConvertToByte(matchValue);\n            green = ConvertToByte(secondLargestComponent + matchValue);\n            blue = ConvertToByte(chroma + matchValue);\n        }\n        else if (hueSection > 4 && hueSection <= 5)\n        {\n            red = ConvertToByte(secondLargestComponent + matchValue);\n            green = ConvertToByte(matchValue);\n            blue = ConvertToByte(chroma + matchValue);\n        }\n        else\n        {\n            red = ConvertToByte(chroma + matchValue);\n            green = ConvertToByte(matchValue);\n            blue = ConvertToByte(secondLargestComponent + matchValue);\n        }\n\n        return (red, green, blue);\n    }\n\n    private static byte ConvertToByte(double input) => (byte)Math.Round(255 * input);\n}\n"
  },
  {
    "path": "Algorithms/Other/SieveOfEratosthenes.cs",
    "content": "namespace Algorithms.Other;\n\n/// <summary>\n///     Implements the Sieve of Eratosthenes.\n/// </summary>\npublic class SieveOfEratosthenes\n{\n    private readonly bool[] primes;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"SieveOfEratosthenes\"/> class.\n    /// Uses the Sieve of Eratosthenes to precalculate the primes from 0 up to maximumNumberToCheck.\n    /// Requires enough memory to allocate maximumNumberToCheck bytes.\n    /// https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes .\n    /// </summary>\n    /// <param name=\"maximumNumberToCheck\">long which specifies the largest number you wish to know if it is prime.</param>\n    public SieveOfEratosthenes(long maximumNumberToCheck)\n    {\n        primes = new bool[maximumNumberToCheck + 1];\n\n        // initialize primes array\n        Array.Fill(this.primes, true, 2, primes.Length - 2);\n\n        for (long i = 2; i * i <= maximumNumberToCheck; i++)\n        {\n            if (!primes[i])\n            {\n                continue;\n            }\n\n            for (long composite = i * i; composite <= maximumNumberToCheck; composite += i)\n            {\n                primes[composite] = false;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Gets the maximumNumberToCheck the class was instantiated with.\n    /// </summary>\n    public long MaximumNumber => primes.Length - 1;\n\n    /// <summary>\n    /// Returns a boolean indicating whether the number is prime.\n    /// </summary>\n    /// <param name=\"numberToCheck\">The number you desire to know if it is prime or not.</param>\n    /// <returns>A boolean indicating whether the number is prime or not.</returns>\n    public bool IsPrime(long numberToCheck) => primes[numberToCheck];\n\n    /// <summary>\n    /// Returns an IEnumerable of long primes in asending order.\n    /// </summary>\n    /// <returns>Primes in ascending order.</returns>\n    public IEnumerable<long> GetPrimes()\n    {\n        for (long i = 2; i < primes.Length; i++)\n        {\n            if (primes[i])\n            {\n                yield return i;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/Triangulator.cs",
    "content": "namespace Algorithms.Other;\n\npublic class Triangulator\n{\n    public (double Latitude, double Longitude) CalculatePosition(List<(double Latitude, double Longitude)> baseLocations, List<double> distances)\n    {\n        if (baseLocations.Count < 3 || distances.Count < 3)\n        {\n            throw new ArgumentException(\"At least three points and corresponding distances are required.\");\n        }\n\n        // Get the coordinates of the three base stations\n        double lat1 = baseLocations[0].Latitude;\n        double lon1 = baseLocations[0].Longitude;\n        double lat2 = baseLocations[1].Latitude;\n        double lon2 = baseLocations[1].Longitude;\n        double lat3 = baseLocations[2].Latitude;\n        double lon3 = baseLocations[2].Longitude;\n\n        // Convert coordinates to radians\n        lat1 = ToRadians(lat1);\n        lon1 = ToRadians(lon1);\n        lat2 = ToRadians(lat2);\n        lon2 = ToRadians(lon2);\n        lat3 = ToRadians(lat3);\n        lon3 = ToRadians(lon3);\n\n        // Calculate the center point\n        double centerLat = (lat1 + lat2 + lat3) / 3;\n        double centerLon = (lon1 + lon2 + lon3) / 3;\n\n        // Convert back to degrees\n        centerLat = ToDegrees(centerLat);\n        centerLon = ToDegrees(centerLon);\n\n        return (centerLat, centerLon);\n    }\n\n    private double ToRadians(double degrees)\n    {\n        return degrees * Math.PI / 180;\n    }\n\n    private double ToDegrees(double radians)\n    {\n        return radians * 180 / Math.PI;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Other/WelfordsVariance.cs",
    "content": "namespace Algorithms.Other;\n\n/// <summary>Implementation of Welford's variance algorithm.\n/// </summary>\npublic class WelfordsVariance\n{\n    /// <summary>\n    ///     Mean accumulates the mean of the entire dataset,\n    ///     m2 aggregates the squared distance from the mean,\n    ///     count aggregates the number of samples seen so far.\n    /// </summary>\n    private int count;\n\n    public double Count => count;\n\n    private double mean;\n\n    public double Mean => count > 1 ? mean : double.NaN;\n\n    private double m2;\n\n    public double Variance => count > 1 ? m2 / count : double.NaN;\n\n    public double SampleVariance => count > 1 ? m2 / (count - 1) : double.NaN;\n\n    public WelfordsVariance()\n    {\n        count = 0;\n        mean = 0;\n    }\n\n    public WelfordsVariance(double[] values)\n    {\n        count = 0;\n        mean = 0;\n        AddRange(values);\n    }\n\n    public void AddValue(double newValue)\n    {\n        count++;\n        AddValueToDataset(newValue);\n    }\n\n    public void AddRange(double[] values)\n    {\n        var length = values.Length;\n        for (var i = 1; i <= length; i++)\n        {\n            count++;\n            AddValueToDataset(values[i - 1]);\n        }\n    }\n\n    private void AddValueToDataset(double newValue)\n    {\n        var delta1 = newValue - mean;\n        var newMean = mean + delta1 / count;\n\n        var delta2 = newValue - newMean;\n        m2 += delta1 * delta2;\n\n        mean = newMean;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs",
    "content": "namespace Algorithms.Problems.DynamicProgramming.CoinChange;\n\npublic static class DynamicCoinChangeSolver\n{\n    /// <summary>\n    /// Generates an array of changes for current coin.\n    /// For instance, having coin C = 6 and array A = [1,3,4] it returns an array R = [2,3,5].\n    /// Because, 6 - 4 = 2, 6 - 3 = 3, 6 - 1 = 5.\n    /// </summary>\n    /// <param name=\"coin\">The value of the coin to be exchanged.</param>\n    /// <param name=\"coins\">An array of available coins.</param>\n    /// <returns>Array of changes of current coins by available coins.</returns>\n    public static int[] GenerateSingleCoinChanges(int coin, int[] coins)\n    {\n        ValidateCoin(coin);\n        ValidateCoinsArray(coins);\n\n        var coinsArrayCopy = new int[coins.Length];\n\n        Array.Copy(coins, coinsArrayCopy, coins.Length);\n        Array.Sort(coinsArrayCopy);\n        Array.Reverse(coinsArrayCopy);\n\n        List<int> list = [];\n\n        foreach (var item in coinsArrayCopy)\n        {\n            if (item > coin)\n            {\n                continue;\n            }\n\n            var difference = coin - item;\n\n            list.Add(difference);\n        }\n\n        var result = list.ToArray();\n\n        return result;\n    }\n\n    /// <summary>\n    /// Given a positive integer N, such as coin.\n    /// Generates a change dictionary for all values [1,N].\n    /// Used in so-called backward induction in search of the minimum exchange.\n    /// </summary>\n    /// <param name=\"coin\">The value of coin.</param>\n    /// <param name=\"coins\">Array of available coins.</param>\n    /// <returns>Change dictionary for all values [1,N], where N is the coin.</returns>\n    public static Dictionary<int, int[]> GenerateChangesDictionary(int coin, int[] coins)\n    {\n        Dictionary<int, int[]> dict = [];\n        var currentCoin = 1;\n\n        while (currentCoin <= coin)\n        {\n            var changeArray = GenerateSingleCoinChanges(currentCoin, coins);\n            dict[currentCoin] = changeArray;\n            currentCoin++;\n        }\n\n        return dict;\n    }\n\n    /// <summary>\n    /// Gets a next coin value, such that changes array contains the minimal change overall possible changes.\n    /// For example, having coin N = 6 and A = [1,3,4] coins array.\n    /// The minimum next coin for 6 will be 3, because changes of 3 by A = [1,3,4] contains 0, the minimal change.\n    /// </summary>\n    /// <param name=\"coin\">Coin to be exchanged.</param>\n    /// <param name=\"exchanges\">Dictionary of exchanges for [1, coin].</param>\n    /// <returns>Index of the next coin with minimal exchange.</returns>\n    public static int GetMinimalNextCoin(int coin, Dictionary<int, int[]> exchanges)\n    {\n        var nextCoin = int.MaxValue;\n        var minChange = int.MaxValue;\n\n        var coinChanges = exchanges[coin];\n\n        foreach (var change in coinChanges)\n        {\n            if (change == 0)\n            {\n                return 0;\n            }\n\n            var currentChange = exchanges[change];\n            var min = currentChange.Min();\n\n            var minIsLesser = min < minChange;\n\n            if (minIsLesser)\n            {\n                nextCoin = change;\n                minChange = min;\n            }\n        }\n\n        return nextCoin;\n    }\n\n    /// <summary>\n    /// Performs a coin change such that an amount of coins is minimal.\n    /// </summary>\n    /// <param name=\"coin\">The value of coin to be exchanged.</param>\n    /// <param name=\"coins\">An array of available coins.</param>\n    /// <returns>Array of exchanges.</returns>\n    public static int[] MakeCoinChangeDynamic(int coin, int[] coins)\n    {\n        var changesTable = GenerateChangesDictionary(coin, coins);\n        var list = new List<int>();\n\n        var currentCoin = coin;\n        var nextCoin = int.MaxValue;\n\n        while (nextCoin != 0)\n        {\n            nextCoin = GetMinimalNextCoin(currentCoin, changesTable);\n            var difference = currentCoin - nextCoin;\n            list.Add(difference);\n            currentCoin = nextCoin;\n        }\n\n        var result = list.ToArray();\n\n        return result;\n    }\n\n    private static void ValidateCoin(int coin)\n    {\n        if (coin <= 0)\n        {\n            throw new InvalidOperationException($\"The coin cannot be lesser or equal to zero {nameof(coin)}.\");\n        }\n    }\n\n    private static void ValidateCoinsArray(int[] coinsArray)\n    {\n        var coinsAsArray = coinsArray.ToArray();\n\n        if (coinsAsArray.Length == 0)\n        {\n            throw new InvalidOperationException($\"Coins array cannot be empty {nameof(coinsAsArray)}.\");\n        }\n\n        var coinsContainOne = coinsAsArray.Any(x => x == 1);\n\n        if (!coinsContainOne)\n        {\n            throw new InvalidOperationException($\"Coins array must contain coin 1 {nameof(coinsAsArray)}.\");\n        }\n\n        var containsNonPositive = coinsAsArray.Any(x => x <= 0);\n\n        if (containsNonPositive)\n        {\n            throw new InvalidOperationException(\n                $\"{nameof(coinsAsArray)} cannot contain numbers less than or equal to zero\");\n        }\n\n        var containsDuplicates = coinsAsArray.GroupBy(x => x).Any(g => g.Count() > 1);\n\n        if (containsDuplicates)\n        {\n            throw new InvalidOperationException($\"Coins array cannot contain duplicates {nameof(coinsAsArray)}.\");\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs",
    "content": "namespace Algorithms.Problems.DynamicProgramming;\n\n/// <summary>\n///     <para>\n///         Levenshtein distance between two words is the minimum number of single-character edits (insertions, deletions or substitutions) required to change one word into the other.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Levenshtein_distance.\n///     </para>\n/// </summary>\npublic static class LevenshteinDistance\n{\n    /// <summary>\n    ///     Calculates Levenshtein distance.\n    ///     Time and space complexity is O(ab) where a and b are the lengths of the source and target strings.\n    /// </summary>\n    /// <param name=\"source\">Source string.</param>\n    /// <param name=\"target\">Target string.</param>\n    /// <returns>Levenshtein distance between source and target strings.</returns>\n    public static int Calculate(string source, string target)\n    {\n        var distances = new int[source.Length + 1, target.Length + 1];\n\n        for (var i = 0; i <= source.Length; i++)\n        {\n            distances[i, 0] = i;\n        }\n\n        for (var i = 0; i <= target.Length; i++)\n        {\n            distances[0, i] = i;\n        }\n\n        for (var i = 1; i <= source.Length; i++)\n        {\n            for (var j = 1; j <= target.Length; j++)\n            {\n                var substitionCost = source[i - 1] == target[j - 1] ? 0 : 1;\n                distances[i, j] = Math.Min(distances[i - 1, j] + 1, Math.Min(distances[i, j - 1] + 1, distances[i - 1, j - 1] + substitionCost));\n            }\n        }\n\n        return distances[source.Length, target.Length];\n    }\n}\n"
  },
  {
    "path": "Algorithms/Problems/GraphColoring/GraphColoringSolver.cs",
    "content": "namespace Algorithms.Problems.GraphColoring;\n\n/// <summary>\n/// Solves the Graph Coloring Problem using backtracking to assign colors to graph vertices\n/// such that no two adjacent vertices share the same color.\n/// </summary>\n/// <remarks>\n/// <para>\n/// The Graph Coloring Problem is an NP-complete problem that aims to color the vertices\n/// of a graph with the minimum number of colors such that no two adjacent vertices have\n/// the same color. This implementation uses a backtracking algorithm to find a valid coloring\n/// given a specific number of colors.\n/// </para>\n/// <para>\n/// The algorithm attempts to assign colors to vertices one by one. If a color assignment\n/// leads to a conflict, it backtracks and tries a different color. If no valid coloring\n/// exists with the given number of colors, an exception is thrown.\n/// </para>\n/// <para>\n/// <b>Complexity:</b> The worst-case time complexity is O(k^n) where n is the number of\n/// vertices and k is the number of colors. This is an exponential algorithm suitable for\n/// small to medium-sized graphs or graphs with special structures.\n/// </para>\n/// <para>\n/// <b>Applications:</b> Graph coloring has numerous practical applications including:\n/// register allocation in compilers, scheduling problems, frequency assignment in mobile networks,\n/// and solving Sudoku puzzles.\n/// </para>\n/// <para>\n/// For more information, see:\n/// <see href=\"https://en.wikipedia.org/wiki/Graph_coloring\">Graph Coloring on Wikipedia</see>.\n/// </para>\n/// </remarks>\npublic sealed class GraphColoringSolver\n{\n    /// <summary>\n    /// Attempts to color a graph with the specified number of colors.\n    /// </summary>\n    /// <param name=\"adjacencyMatrix\">\n    /// A square boolean matrix representing the graph where <c>adjacencyMatrix[i, j]</c>\n    /// is <c>true</c> if there is an edge between vertex <c>i</c> and vertex <c>j</c>.\n    /// The matrix must be symmetric for undirected graphs.\n    /// </param>\n    /// <param name=\"numColors\">The number of colors to use for coloring. Must be positive.</param>\n    /// <returns>\n    /// An array where each element represents the color assigned to the corresponding vertex\n    /// (0-indexed colors from 0 to <paramref name=\"numColors\"/> - 1).\n    /// </returns>\n    /// <exception cref=\"ArgumentNullException\">\n    /// Thrown when <paramref name=\"adjacencyMatrix\"/> is <c>null</c>.\n    /// </exception>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown when the adjacency matrix is not square, when <paramref name=\"numColors\"/> is non-positive,\n    /// or when no valid coloring exists with the given number of colors.\n    /// </exception>\n    /// <remarks>\n    /// <para>\n    /// This method finds the first valid coloring it encounters. Multiple valid colorings\n    /// may exist for a given graph, but only one is returned.\n    /// </para>\n    /// <para>\n    /// <b>Example:</b> For a triangle graph (3 vertices, all connected), at least 3 colors\n    /// are required. Calling this method with <c>numColors = 2</c> will throw an exception,\n    /// while <c>numColors = 3</c> will return a valid coloring such as <c>[0, 1, 2]</c>.\n    /// </para>\n    /// </remarks>\n    public int[] ColorGraph(bool[,] adjacencyMatrix, int numColors)\n    {\n        if (adjacencyMatrix is null)\n        {\n            throw new ArgumentNullException(nameof(adjacencyMatrix));\n        }\n\n        var numVertices = adjacencyMatrix.GetLength(0);\n\n        if (numVertices != adjacencyMatrix.GetLength(1))\n        {\n            throw new ArgumentException(\"Adjacency matrix must be square.\", nameof(adjacencyMatrix));\n        }\n\n        if (numColors <= 0)\n        {\n            throw new ArgumentException(\"Number of colors must be positive.\", nameof(numColors));\n        }\n\n        // Handle empty graph\n        if (numVertices == 0)\n        {\n            return Array.Empty<int>();\n        }\n\n        var colors = new int[numVertices];\n\n        // Initialize all vertices as uncolored (-1)\n        Array.Fill(colors, -1);\n\n        if (!ColorVertex(adjacencyMatrix, colors, 0, numColors))\n        {\n            throw new ArgumentException(\n                $\"Graph cannot be colored with {numColors} color(s). \" +\n                $\"A larger number of colors may be required.\");\n        }\n\n        return colors;\n    }\n\n    /// <summary>\n    /// Recursively attempts to color vertices using backtracking.\n    /// </summary>\n    /// <param name=\"adjacencyMatrix\">The graph adjacency matrix.</param>\n    /// <param name=\"colors\">Current color assignment for each vertex.</param>\n    /// <param name=\"vertex\">The current vertex to color.</param>\n    /// <param name=\"numColors\">The number of available colors.</param>\n    /// <returns><c>true</c> if a valid coloring is found; otherwise, <c>false</c>.</returns>\n    /// <remarks>\n    /// This method tries each available color for the current vertex. If a color is valid\n    /// (doesn't conflict with adjacent vertices), it proceeds to color the next vertex.\n    /// If no valid color is found, it backtracks.\n    /// </remarks>\n    private bool ColorVertex(bool[,] adjacencyMatrix, int[] colors, int vertex, int numColors)\n    {\n        var numVertices = adjacencyMatrix.GetLength(0);\n\n        // Base case: all vertices are colored\n        if (vertex == numVertices)\n        {\n            return true;\n        }\n\n        // Try each color for the current vertex\n        for (var color = 0; color < numColors; color++)\n        {\n            if (IsSafeToColor(adjacencyMatrix, colors, vertex, color))\n            {\n                colors[vertex] = color;\n\n                // Recursively color the next vertex\n                if (ColorVertex(adjacencyMatrix, colors, vertex + 1, numColors))\n                {\n                    return true;\n                }\n\n                // Backtrack if the current color assignment doesn't lead to a solution\n                colors[vertex] = -1;\n            }\n        }\n\n        return false;\n    }\n\n    /// <summary>\n    /// Checks whether it is safe to assign a color to a vertex.\n    /// </summary>\n    /// <param name=\"adjacencyMatrix\">The graph adjacency matrix.</param>\n    /// <param name=\"colors\">Current color assignment for each vertex.</param>\n    /// <param name=\"vertex\">The vertex to check.</param>\n    /// <param name=\"color\">The color to assign.</param>\n    /// <returns>\n    /// <c>true</c> if the color can be safely assigned (no adjacent vertex has this color);\n    /// otherwise, <c>false</c>.\n    /// </returns>\n    /// <remarks>\n    /// A color is safe to assign if none of the already-colored adjacent vertices\n    /// have the same color.\n    /// </remarks>\n    private bool IsSafeToColor(bool[,] adjacencyMatrix, int[] colors, int vertex, int color)\n    {\n        var numVertices = adjacencyMatrix.GetLength(0);\n\n        for (var i = 0; i < numVertices; i++)\n        {\n            // Check if vertex i is adjacent to the current vertex and has the same color\n            if (adjacencyMatrix[vertex, i] && colors[i] == color)\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Problems/JobScheduling/IntervalSchedulingSolver.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Algorithms.Problems.JobScheduling;\n\n/// <summary>\n/// Implements the greedy algorithm for Interval Scheduling.\n/// Finds the maximum set of non-overlapping jobs.\n/// </summary>\npublic static class IntervalSchedulingSolver\n{\n    /// <summary>\n    /// Returns the maximal set of non-overlapping jobs.\n    /// </summary>\n    /// <param name=\"jobs\">List of jobs to schedule.</param>\n    /// <returns>List of selected jobs (maximal set).</returns>\n    public static List<Job> Schedule(IEnumerable<Job> jobs)\n    {\n        if (jobs == null)\n        {\n            throw new ArgumentNullException(nameof(jobs));\n        }\n\n        // Sort jobs by their end time (earliest finish first)\n        var sortedJobs = jobs.OrderBy(j => j.End).ToList();\n        var result = new List<Job>();\n        int lastEnd = int.MinValue;\n\n        foreach (var job in sortedJobs)\n        {\n            // If the job starts after the last selected job ends, select it\n            if (job.Start >= lastEnd)\n            {\n                result.Add(job);\n                lastEnd = job.End;\n            }\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Problems/JobScheduling/Job.cs",
    "content": "namespace Algorithms.Problems.JobScheduling;\n\n/// <summary>\n/// Represents a single job with a start and end time.\n/// </summary>\npublic record Job(int Start, int End);\n"
  },
  {
    "path": "Algorithms/Problems/KnightTour/OpenKnightTour.cs",
    "content": "namespace Algorithms.Problems.KnightTour;\n\n/// <summary>\n/// Computes a (single) Knight's Tour on an <c>n × n</c> chessboard using\n/// depth-first search (DFS) with backtracking.\n/// </summary>\n/// <remarks>\n/// <para>\n/// A Knight's Tour is a sequence of knight moves that visits every square exactly once.\n/// This implementation returns the first tour it finds (if any), starting from whichever\n/// starting cell leads to a solution first. It explores every board square as a potential\n/// starting position in row-major order.\n/// </para>\n/// <para>\n/// The algorithm is a plain backtracking search—no heuristics (e.g., Warnsdorff’s rule)\n/// are applied. As a result, runtime can grow exponentially with <c>n</c> and become\n/// impractical on larger boards.\n/// </para>\n/// <para>\n/// <b>Solvability (square boards):</b>\n/// A (non-closed) tour exists for <c>n = 1</c> and for all <c>n ≥ 5</c>.\n/// There is no tour for <c>n ∈ {2, 3, 4}</c>. This implementation throws an\n/// <see cref=\"ArgumentException\"/> if no tour is found.\n/// </para>\n/// <para>\n/// <b>Coordinate convention:</b> The board is indexed as <c>[row, column]</c>,\n/// zero-based, with <c>(0,0)</c> in the top-left corner.\n/// </para>\n/// </remarks>\npublic sealed class OpenKnightTour\n{\n    /// <summary>\n    /// Attempts to find a Knight's Tour on an <c>n × n</c> board.\n    /// </summary>\n    /// <param name=\"n\">Board size (number of rows/columns). Must be positive.</param>\n    /// <returns>\n    /// A 2D array of size <c>n × n</c> where each cell contains the\n    /// 1-based visit order (from <c>1</c> to <c>n*n</c>) of the knight.\n    /// </returns>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown when <paramref name=\"n\"/> ≤ 0, or when no tour exists / is found for the given <paramref name=\"n\"/>.\n    /// </exception>\n    /// <remarks>\n    /// <para>\n    /// This routine tries every square as a starting point. As soon as a complete tour is found,\n    /// the filled board is returned. If no tour is found, an exception is thrown.\n    /// </para>\n    /// <para>\n    /// <b>Performance:</b> Exponential in the worst case. For larger boards, consider adding\n    /// Warnsdorff’s heuristic (choose next moves with the fewest onward moves) or a hybrid approach.\n    /// </para>\n    /// </remarks>\n    public int[,] Tour(int n)\n    {\n        if (n <= 0)\n        {\n            throw new ArgumentException(\"Board size must be positive.\", nameof(n));\n        }\n\n        var board = new int[n, n];\n\n        // Try every square as a starting point.\n        for (var r = 0; r < n; r++)\n        {\n            for (var c = 0; c < n; c++)\n            {\n                board[r, c] = 1; // first step\n                if (KnightTourHelper(board, (r, c), 1))\n                {\n                    return board;\n                }\n\n                board[r, c] = 0; // backtrack and try next start\n            }\n        }\n\n        throw new ArgumentException($\"Knight Tour cannot be performed on a board of size {n}.\");\n    }\n\n    /// <summary>\n    /// Recursively extends the current partial tour from <paramref name=\"pos\"/> after placing\n    /// move number <paramref name=\"current\"/> in that position.\n    /// </summary>\n    /// <param name=\"board\">The board with placed move numbers; <c>0</c> means unvisited.</param>\n    /// <param name=\"pos\">Current knight position (<c>Row</c>, <c>Col</c>).</param>\n    /// <param name=\"current\">The move number just placed at <paramref name=\"pos\"/>.</param>\n    /// <returns><c>true</c> if a full tour is completed; <c>false</c> otherwise.</returns>\n    /// <remarks>\n    /// Tries each legal next move in a fixed order (no heuristics). If a move leads to a dead end,\n    /// it backtracks by resetting the target cell to <c>0</c> and tries the next candidate.\n    /// </remarks>\n    private bool KnightTourHelper(int[,] board, (int Row, int Col) pos, int current)\n    {\n        if (IsComplete(board))\n        {\n            return true;\n        }\n\n        foreach (var (nr, nc) in GetValidMoves(pos, board.GetLength(0)))\n        {\n            if (board[nr, nc] == 0)\n            {\n                board[nr, nc] = current + 1;\n\n                if (KnightTourHelper(board, (nr, nc), current + 1))\n                {\n                    return true;\n                }\n\n                board[nr, nc] = 0; // backtrack\n            }\n        }\n\n        return false;\n    }\n\n    /// <summary>\n    /// Computes all legal knight moves from <paramref name=\"position\"/> on an <c>n × n</c> board.\n    /// </summary>\n    /// <param name=\"position\">Current position (<c>R</c>, <c>C</c>).</param>\n    /// <param name=\"n\">Board dimension (rows = columns = <paramref name=\"n\"/>).</param>\n    /// <returns>\n    /// An enumeration of on-board destination coordinates. Order is fixed and unoptimized:\n    /// <c>(+1,+2), (-1,+2), (+1,-2), (-1,-2), (+2,+1), (+2,-1), (-2,+1), (-2,-1)</c>.\n    /// </returns>\n    /// <remarks>\n    /// Keeping a deterministic order makes the search reproducible, but it’s not necessarily fast.\n    /// To accelerate, pre-sort by onward-degree (Warnsdorff) or by a custom heuristic.\n    /// </remarks>\n    private IEnumerable<(int R, int C)> GetValidMoves((int R, int C) position, int n)\n    {\n        var r = position.R;\n        var c = position.C;\n\n        var candidates = new (int Dr, int Dc)[]\n        {\n            (1,  2), (-1,  2), (1, -2), (-1, -2),\n            (2,  1), (2, -1), (-2,  1), (-2, -1),\n        };\n\n        foreach (var (dr, dc) in candidates)\n        {\n            var nr = r + dr;\n            var nc = c + dc;\n\n            if (nr >= 0 && nr < n && nc >= 0 && nc < n)\n            {\n                yield return (nr, nc);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Checks whether the tour is complete; i.e., every cell is non-zero.\n    /// </summary>\n    /// <param name=\"board\">The board to check.</param>\n    /// <returns><c>true</c> if all cells have been visited; otherwise, <c>false</c>.</returns>\n    /// <remarks>\n    /// A complete board means the knight has visited exactly <c>n × n</c> distinct cells.\n    /// </remarks>\n    private bool IsComplete(int[,] board)\n    {\n        var n = board.GetLength(0);\n        for (var row = 0; row < n; row++)\n        {\n            for (var col = 0; col < n; col++)\n            {\n                if (board[row, col] == 0)\n                {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs",
    "content": "namespace Algorithms.Problems.NQueens;\n\npublic class BacktrackingNQueensSolver\n{\n    /// <summary>\n    ///     Solves N-Queen Problem given a n dimension chessboard and using backtracking with recursion algorithm.\n    ///     If we find a dead-end within or current solution we go back and try another position for queen.\n    /// </summary>\n    /// <param name=\"n\">Number of rows.</param>\n    /// <returns>All solutions.</returns>\n    public IEnumerable<bool[,]> BacktrackSolve(int n)\n    {\n        if (n < 0)\n        {\n            throw new ArgumentException(nameof(n));\n        }\n\n        return BacktrackSolve(new bool[n, n], 0);\n    }\n\n    private static IEnumerable<bool[,]> BacktrackSolve(bool[,] board, int col)\n    {\n        var solutions = col < board.GetLength(0) - 1\n            ? HandleIntermediateColumn(board, col)\n            : HandleLastColumn(board);\n        return solutions;\n    }\n\n    private static IEnumerable<bool[,]> HandleIntermediateColumn(bool[,] board, int col)\n    {\n        // To start placing queens on possible spaces within the board.\n        for (var i = 0; i < board.GetLength(0); i++)\n        {\n            if (CanPlace(board, i, col))\n            {\n                board[i, col] = true;\n\n                foreach (var solution in BacktrackSolve(board, col + 1))\n                {\n                    yield return solution;\n                }\n\n                board[i, col] = false;\n            }\n        }\n    }\n\n    private static IEnumerable<bool[,]> HandleLastColumn(bool[,] board)\n    {\n        var n = board.GetLength(0);\n        for (var i = 0; i < n; i++)\n        {\n            if (CanPlace(board, i, n - 1))\n            {\n                board[i, n - 1] = true;\n\n                yield return (bool[,])board.Clone();\n\n                board[i, n - 1] = false;\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Checks whether current queen can be placed in current position,\n    ///     outside attacking range of another queen.\n    /// </summary>\n    /// <param name=\"board\">Source board.</param>\n    /// <param name=\"row\">Row coordinate.</param>\n    /// <param name=\"col\">Col coordinate.</param>\n    /// <returns>true if queen can be placed in given chessboard coordinates; false otherwise.</returns>\n    private static bool CanPlace(bool[,] board, int row, int col)\n    {\n        // To check whether there are any queens on current row.\n        for (var i = 0; i < col; i++)\n        {\n            if (board[row, i])\n            {\n                return false;\n            }\n        }\n\n        // To check diagonal attack top-left range.\n        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--)\n        {\n            if (board[i, j])\n            {\n                return false;\n            }\n        }\n\n        // To check diagonal attack bottom-left range.\n        for (int i = row + 1, j = col - 1; j >= 0 && i < board.GetLength(0); i++, j--)\n        {\n            if (board[i, j])\n            {\n                return false;\n            }\n        }\n\n        // Return true if it can use position.\n        return true;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Problems/StableMarriage/Accepter.cs",
    "content": "namespace Algorithms.Problems.StableMarriage;\n\npublic class Accepter\n{\n    public Proposer? EngagedTo { get; set; }\n\n    public List<Proposer> PreferenceOrder { get; set; } = [];\n\n    public bool PrefersOverCurrent(Proposer newProposer) =>\n        EngagedTo is null ||\n        PreferenceOrder.IndexOf(newProposer) < PreferenceOrder.IndexOf(EngagedTo);\n}\n"
  },
  {
    "path": "Algorithms/Problems/StableMarriage/GaleShapley.cs",
    "content": "namespace Algorithms.Problems.StableMarriage;\n\npublic static class GaleShapley\n{\n    /// <summary>\n    ///     Finds a stable matching between two equal sets of elements (fills EngagedTo properties).\n    ///     time complexity: O(n^2), where n - array size.\n    ///     Guarantees:\n    ///     - Everyone is matched\n    ///     - Matches are stable (there is no better accepter, for any given proposer, which would accept a new match).\n    ///     Presented and proven by David Gale and Lloyd Shapley in 1962.\n    /// </summary>\n    public static void Match(Proposer[] proposers, Accepter[] accepters)\n    {\n        if (proposers.Length != accepters.Length)\n        {\n            throw new ArgumentException(\"Collections must have equal count\");\n        }\n\n        while (proposers.Any(m => !IsEngaged(m)))\n        {\n            DoSingleMatchingRound(proposers.Where(m => !IsEngaged(m)));\n        }\n    }\n\n    private static bool IsEngaged(Proposer proposer) => proposer.EngagedTo is not null;\n\n    private static void DoSingleMatchingRound(IEnumerable<Proposer> proposers)\n    {\n        foreach (var newProposer in proposers)\n        {\n            var accepter = newProposer.PreferenceOrder.First!.Value;\n\n            if (accepter.EngagedTo is null)\n            {\n                Engage(newProposer, accepter);\n            }\n            else\n            {\n                if (accepter.PrefersOverCurrent(newProposer))\n                {\n                    Free(accepter.EngagedTo);\n                    Engage(newProposer, accepter);\n                }\n            }\n\n            newProposer.PreferenceOrder.RemoveFirst();\n        }\n    }\n\n    private static void Free(Proposer proposer)\n    {\n        proposer.EngagedTo = null;\n    }\n\n    private static void Engage(Proposer proposer, Accepter accepter)\n    {\n        proposer.EngagedTo = accepter;\n        accepter.EngagedTo = proposer;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Problems/StableMarriage/Proposer.cs",
    "content": "namespace Algorithms.Problems.StableMarriage;\n\npublic class Proposer\n{\n    public Accepter? EngagedTo { get; set; }\n\n    public LinkedList<Accepter> PreferenceOrder { get; set; } = new();\n}\n"
  },
  {
    "path": "Algorithms/Problems/TravelingSalesman/TravelingSalesmanSolver.cs",
    "content": "namespace Algorithms.Problems.TravelingSalesman;\n\n/// <summary>\n/// Provides methods to solve the Traveling Salesman Problem (TSP) using brute-force and nearest neighbor heuristics.\n/// The TSP is a classic optimization problem in which a salesman must visit each city exactly once and return to the starting city, minimizing the total travel distance.\n/// </summary>\npublic static class TravelingSalesmanSolver\n{\n    /// <summary>\n    /// Solves the TSP using brute-force search. This method checks all possible permutations of cities to find the shortest possible route.\n    /// WARNING: This approach is only feasible for small numbers of cities due to factorial time complexity.\n    /// </summary>\n    /// <param name=\"distanceMatrix\">A square matrix where element [i, j] represents the distance from city i to city j.</param>\n    /// <returns>A tuple containing the minimal route (as an array of city indices) and the minimal total distance.</returns>\n    public static (int[] Route, double Distance) SolveBruteForce(double[,] distanceMatrix)\n    {\n        int n = distanceMatrix.GetLength(0);\n        if (n != distanceMatrix.GetLength(1))\n        {\n            throw new ArgumentException(\"Distance matrix must be square.\");\n        }\n\n        if (n < 2)\n        {\n            throw new ArgumentException(\"At least two cities are required.\");\n        }\n\n        var cities = Enumerable.Range(0, n).ToArray();\n        double minDistance = double.MaxValue;\n        int[]? bestRoute = null;\n\n        foreach (var perm in Permute(cities.Skip(1).ToArray()))\n        {\n            var route = new int[n + 1];\n            route[0] = 0;\n            for (int i = 0; i < perm.Length; i++)\n            {\n                route[i + 1] = perm[i];\n            }\n\n            // Ensure route ends at city 0\n            route[n] = 0;\n\n            double dist = 0;\n            for (int i = 0; i < n; i++)\n            {\n                dist += distanceMatrix[route[i], route[i + 1]];\n            }\n\n            if (dist < minDistance)\n            {\n                minDistance = dist;\n                bestRoute = (int[])route.Clone();\n            }\n        }\n\n        return (bestRoute ?? Array.Empty<int>(), minDistance);\n    }\n\n    /// <summary>\n    /// Solves the TSP using the nearest neighbor heuristic. This method builds a route by always visiting the nearest unvisited city next.\n    /// This approach is much faster but may not find the optimal solution.\n    /// </summary>\n    /// <param name=\"distanceMatrix\">A square matrix where element [i, j] represents the distance from city i to city j.</param>\n    /// <param name=\"start\">The starting city index.</param>\n    /// <returns>A tuple containing the route (as an array of city indices) and the total distance.</returns>\n    public static (int[] Route, double Distance) SolveNearestNeighbor(double[,] distanceMatrix, int start = 0)\n    {\n        int n = distanceMatrix.GetLength(0);\n        if (n != distanceMatrix.GetLength(1))\n        {\n            throw new ArgumentException(\"Distance matrix must be square.\");\n        }\n\n        if (start < 0 || start >= n)\n        {\n            throw new ArgumentOutOfRangeException(nameof(start));\n        }\n\n        var visited = new bool[n];\n        List<int> route = [start];\n        visited[start] = true;\n        double totalDistance = 0;\n        int current = start;\n        for (int step = 1; step < n; step++)\n        {\n            double minDist = double.MaxValue;\n            int next = -1;\n            for (int j = 0; j < n; j++)\n            {\n                if (!visited[j] && distanceMatrix[current, j] < minDist)\n                {\n                    minDist = distanceMatrix[current, j];\n                    next = j;\n                }\n            }\n\n            if (next == -1)\n            {\n                throw new InvalidOperationException(\"No unvisited cities remain.\");\n            }\n\n            route.Add(next);\n            visited[next] = true;\n            totalDistance += minDist;\n            current = next;\n        }\n\n        totalDistance += distanceMatrix[current, start];\n        route.Add(start);\n        return (route.ToArray(), totalDistance);\n    }\n\n    /// <summary>\n    /// Generates all permutations of the input array.\n    /// Used for brute-force TSP solution.\n    /// </summary>\n    private static IEnumerable<int[]> Permute(int[] arr)\n    {\n        if (arr.Length == 1)\n        {\n            yield return arr;\n            yield break;\n        }\n\n        for (int i = 0; i < arr.Length; i++)\n        {\n            var rest = arr.Where((_, idx) => idx != i).ToArray();\n            foreach (var perm in Permute(rest))\n            {\n                yield return [arr[i], ..perm];\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/RecommenderSystem/CollaborativeFiltering.cs",
    "content": "namespace Algorithms.RecommenderSystem;\n\npublic class CollaborativeFiltering(ISimilarityCalculator similarityCalculator)\n{\n    private readonly ISimilarityCalculator similarityCalculator = similarityCalculator;\n\n    /// <summary>\n    /// Method to calculate similarity between two users using Pearson correlation.\n    /// </summary>\n    /// <param name=\"user1Ratings\">Rating of User 1.</param>\n    /// <param name=\"user2Ratings\">Rating of User 2.</param>\n    /// <returns>double value to reflect the index of similarity between two users.</returns>\n    public double CalculateSimilarity(Dictionary<string, double> user1Ratings, Dictionary<string, double> user2Ratings)\n    {\n        var commonItems = user1Ratings.Keys.Intersect(user2Ratings.Keys).ToList();\n        if (commonItems.Count == 0)\n        {\n            return 0;\n        }\n\n        var user1Scores = commonItems.Select(item => user1Ratings[item]).ToArray();\n        var user2Scores = commonItems.Select(item => user2Ratings[item]).ToArray();\n\n        var avgUser1 = user1Scores.Average();\n        var avgUser2 = user2Scores.Average();\n\n        double numerator = 0;\n        double sumSquare1 = 0;\n        double sumSquare2 = 0;\n        double epsilon = 1e-10;\n\n        for (var i = 0; i < commonItems.Count; i++)\n        {\n            var diff1 = user1Scores[i] - avgUser1;\n            var diff2 = user2Scores[i] - avgUser2;\n\n            numerator += diff1 * diff2;\n            sumSquare1 += diff1 * diff1;\n            sumSquare2 += diff2 * diff2;\n        }\n\n        var denominator = Math.Sqrt(sumSquare1 * sumSquare2);\n        return Math.Abs(denominator) < epsilon ? 0 : numerator / denominator;\n    }\n\n    /// <summary>\n    /// Predict a rating for a specific item by a target user.\n    /// </summary>\n    /// <param name=\"targetItem\">The item for which the rating needs to be predicted.</param>\n    /// <param name=\"targetUser\">The user for whom the rating is being predicted.</param>\n    /// <param name=\"ratings\">\n    /// A dictionary containing user ratings where:\n    /// - The key is the user's identifier (string).\n    /// - The value is another dictionary where the key is the item identifier (string), and the value is the rating given by the user (double).\n    /// </param>\n    /// <returns>The predicted rating for the target item by the target user.\n    /// If there is insufficient data to predict a rating, the method returns 0.\n    /// </returns>\n    public double PredictRating(string targetItem, string targetUser, Dictionary<string, Dictionary<string, double>> ratings)\n    {\n        var targetUserRatings = ratings[targetUser];\n        double totalSimilarity = 0;\n        double weightedSum = 0;\n        double epsilon = 1e-10;\n\n        foreach (var otherUser in ratings.Keys.Where(u => u != targetUser))\n        {\n            var otherUserRatings = ratings[otherUser];\n            if (otherUserRatings.ContainsKey(targetItem))\n            {\n                var similarity = similarityCalculator.CalculateSimilarity(targetUserRatings, otherUserRatings);\n                totalSimilarity += Math.Abs(similarity);\n                weightedSum += similarity * otherUserRatings[targetItem];\n            }\n        }\n\n        return Math.Abs(totalSimilarity) < epsilon ? 0 : weightedSum / totalSimilarity;\n    }\n}\n"
  },
  {
    "path": "Algorithms/RecommenderSystem/ISimilarityCalculator.cs",
    "content": "namespace Algorithms.RecommenderSystem\n{\n    public interface ISimilarityCalculator\n    {\n        double CalculateSimilarity(Dictionary<string, double> user1Ratings, Dictionary<string, double> user2Ratings);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Search/AStar/AStar.cs",
    "content": "namespace Algorithms.Search.AStar;\n\n/// <summary>\n///     Contains the code for A* Pathfinding.\n/// </summary>\npublic static class AStar\n{\n    /// <summary>\n    ///     Resets the Nodes in the list.\n    /// </summary>\n    /// <param name=\"nodes\">Resets the nodes to be used again.</param>\n    public static void ResetNodes(List<Node> nodes)\n    {\n        foreach (var node in nodes)\n        {\n            node.CurrentCost = 0;\n            node.EstimatedCost = 0;\n            node.Parent = null;\n            node.State = NodeState.Unconsidered;\n        }\n    }\n\n    /// <summary>\n    ///     Generates the Path from an (solved) node graph, before it gets reset.\n    /// </summary>\n    /// <param name=\"target\">The node where we want to go.</param>\n    /// <returns>The Path to the target node.</returns>\n    public static List<Node> GeneratePath(Node target)\n    {\n        var ret = new List<Node>();\n        var current = target;\n        while (!(current is null))\n        {\n            ret.Add(current);\n            current = current.Parent;\n        }\n\n        ret.Reverse();\n        return ret;\n    }\n\n    /// <summary>\n    ///     Computes the path from => to.\n    /// </summary>\n    /// <param name=\"from\">Start node.</param>\n    /// <param name=\"to\">end node.</param>\n    /// <returns>Path from start to end.</returns>\n    public static List<Node> Compute(Node from, Node to)\n    {\n        var done = new List<Node>();\n\n        // A priority queue that will sort our nodes based on the total cost estimate\n        var open = new PriorityQueue<Node>();\n        foreach (var node in from.ConnectedNodes)\n        {\n            // Add connecting nodes if traversable\n            if (node.Traversable)\n            {\n                // Calculate the Costs\n                node.CurrentCost = from.CurrentCost + from.DistanceTo(node) * node.TraversalCostMultiplier;\n                node.EstimatedCost = from.CurrentCost + node.DistanceTo(to);\n\n                // Enqueue\n                open.Enqueue(node);\n            }\n        }\n\n        while (true)\n        {\n            // End Condition( Path not found )\n            if (open.Count == 0)\n            {\n                ResetNodes(done);\n                ResetNodes(open.GetData());\n                return [];\n            }\n\n            // Selecting next Element from queue\n            var current = open.Dequeue();\n\n            // Add it to the done list\n            done.Add(current);\n\n            current.State = NodeState.Closed;\n\n            // EndCondition( Path was found )\n            if (current == to)\n            {\n                var ret = GeneratePath(to); // Create the Path\n\n                // Reset all Nodes that were used.\n                ResetNodes(done);\n                ResetNodes(open.GetData());\n                return ret;\n            }\n\n            AddOrUpdateConnected(current, to, open);\n        }\n    }\n\n    private static void AddOrUpdateConnected(Node current, Node to, PriorityQueue<Node> queue)\n    {\n        foreach (var connected in current.ConnectedNodes)\n        {\n            if (!connected.Traversable ||\n                connected.State == NodeState.Closed)\n            {\n                continue; // Do ignore already checked and not traversable nodes.\n            }\n\n            // Adds a previously not \"seen\" node into the Queue\n            if (connected.State == NodeState.Unconsidered)\n            {\n                connected.Parent = current;\n                connected.CurrentCost =\n                    current.CurrentCost + current.DistanceTo(connected) * connected.TraversalCostMultiplier;\n                connected.EstimatedCost = connected.CurrentCost + connected.DistanceTo(to);\n                connected.State = NodeState.Open;\n                queue.Enqueue(connected);\n            }\n            else if (current != connected)\n            {\n                // Updating the cost of the node if the current way is cheaper than the previous\n                var newCCost = current.CurrentCost + current.DistanceTo(connected);\n                var newTCost = newCCost + current.EstimatedCost;\n                if (newTCost < connected.TotalCost)\n                {\n                    connected.Parent = current;\n                    connected.CurrentCost = newCCost;\n                }\n            }\n            else\n            {\n                // Codacy made me do it.\n                throw new PathfindingException(\n                    \"Detected the same node twice. Confusion how this could ever happen\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Search/AStar/Node.cs",
    "content": "namespace Algorithms.Search.AStar;\n\n/// <summary>\n///     Contains Positional and other information about a single node.\n/// </summary>\npublic class Node(VecN position, bool traversable, double traverseMultiplier) : IComparable<Node>, IEquatable<Node>\n{\n    /// <summary>\n    ///     Gets the Total cost of the Node.\n    ///     The Current Costs + the estimated costs.\n    /// </summary>\n    public double TotalCost => EstimatedCost + CurrentCost;\n\n    /// <summary>\n    ///     Gets or sets the Distance between this node and the target node.\n    /// </summary>\n    public double EstimatedCost { get; set; }\n\n    /// <summary>\n    ///     Gets a value indicating whether how costly it is to traverse over this node.\n    /// </summary>\n    public double TraversalCostMultiplier { get; } = traverseMultiplier;\n\n    /// <summary>\n    ///     Gets or sets a value indicating whether to go from the start node to this node.\n    /// </summary>\n    public double CurrentCost { get; set; }\n\n    /// <summary>\n    ///     Gets or sets the state of the Node\n    ///     Can be Unconsidered(Default), Open and Closed.\n    /// </summary>\n    public NodeState State { get; set; }\n\n    /// <summary>\n    ///     Gets a value indicating whether the node is traversable.\n    /// </summary>\n    public bool Traversable { get; } = traversable;\n\n    /// <summary>\n    ///     Gets or sets a list of all connected nodes.\n    /// </summary>\n    public Node[] ConnectedNodes { get; set; } = [];\n\n    /// <summary>\n    ///     Gets or sets he \"previous\" node that was processed before this node.\n    /// </summary>\n    public Node? Parent { get; set; }\n\n    /// <summary>\n    ///     Gets the positional information of the node.\n    /// </summary>\n    public VecN Position { get; } = position;\n\n    /// <summary>\n    ///     Compares the Nodes based on their total costs.\n    ///     Total Costs: A* Pathfinding.\n    ///     Current: Djikstra Pathfinding.\n    ///     Estimated: Greedy Pathfinding.\n    /// </summary>\n    /// <param name=\"other\">The other node.</param>\n    /// <returns>A comparison between the costs.</returns>\n    public int CompareTo(Node? other) => TotalCost.CompareTo(other?.TotalCost ?? 0);\n\n    public bool Equals(Node? other) => CompareTo(other) == 0;\n\n    public static bool operator ==(Node left, Node right) => left?.Equals(right) != false;\n\n    public static bool operator >(Node left, Node right) => left.CompareTo(right) > 0;\n\n    public static bool operator <(Node left, Node right) => left.CompareTo(right) < 0;\n\n    public static bool operator !=(Node left, Node right) => !(left == right);\n\n    public static bool operator <=(Node left, Node right) => left.CompareTo(right) <= 0;\n\n    public static bool operator >=(Node left, Node right) => left.CompareTo(right) >= 0;\n\n    public override bool Equals(object? obj) => obj is Node other && Equals(other);\n\n    public override int GetHashCode() =>\n        Position.GetHashCode()\n        + Traversable.GetHashCode()\n        + TraversalCostMultiplier.GetHashCode();\n\n    /// <summary>\n    ///     Returns the distance to the other node.\n    /// </summary>\n    /// <param name=\"other\">The other node.</param>\n    /// <returns>Distance between this and other.</returns>\n    public double DistanceTo(Node other) => Math.Sqrt(Position.SqrDistance(other.Position));\n}\n"
  },
  {
    "path": "Algorithms/Search/AStar/NodeState.cs",
    "content": "namespace Algorithms.Search.AStar;\n\n/// <summary>\n///     The states the nodes can have.\n/// </summary>\npublic enum NodeState\n{\n    /// <summary>\n    ///     TODO.\n    /// </summary>\n    Unconsidered = 0,\n\n    /// <summary>\n    ///     TODO.\n    /// </summary>\n    Open = 1,\n\n    /// <summary>\n    ///     TODO.\n    /// </summary>\n    Closed = 2,\n}\n"
  },
  {
    "path": "Algorithms/Search/AStar/PathfindingException.cs",
    "content": "namespace Algorithms.Search.AStar;\n\n/// <summary>\n///     A pathfinding exception is thrown when the Pathfinder encounters a critical error and can not continue.\n/// </summary>\npublic class PathfindingException(string message) : Exception(message)\n{\n}\n"
  },
  {
    "path": "Algorithms/Search/AStar/PriorityQueue.cs",
    "content": "// todo: extract to data structures\nnamespace Algorithms.Search.AStar;\n\n/// <summary>\n///     Generic Priority Queue.\n///     List based.\n/// </summary>\n/// <typeparam name=\"T\">\n///     The type that will be stored.\n///     Has to be IComparable of T.\n/// </typeparam>\npublic class PriorityQueue<T>\n    where T : IComparable<T>\n{\n    private readonly bool isDescending;\n\n    // The underlying structure.\n    private readonly List<T> list;\n\n    public PriorityQueue(bool isDescending = false)\n    {\n        this.isDescending = isDescending;\n        list = [];\n    }\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"PriorityQueue{T}\" /> class.\n    /// </summary>\n    /// <param name=\"capacity\">Initial capacity.</param>\n    /// <param name=\"isDescending\">Should Reverse Sort order? Default: false.</param>\n    public PriorityQueue(int capacity, bool isDescending = false)\n    {\n        list = new List<T>(capacity);\n        this.isDescending = isDescending;\n    }\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"PriorityQueue{T}\" /> class.\n    /// </summary>\n    /// <param name=\"collection\">Internal data.</param>\n    /// <param name=\"isDescending\">Should Reverse Sort order? Default: false.</param>\n    public PriorityQueue(IEnumerable<T> collection, bool isDescending = false)\n        : this()\n    {\n        this.isDescending = isDescending;\n        foreach (var item in collection)\n        {\n            Enqueue(item);\n        }\n    }\n\n    /// <summary>\n    ///     Gets Number of enqueued items.\n    /// </summary>\n    public int Count => list.Count;\n\n    /// <summary>\n    ///     Enqueues an item into the Queue.\n    /// </summary>\n    /// <param name=\"x\">The item to Enqueue.</param>\n    public void Enqueue(T x)\n    {\n        list.Add(x);\n        var i = Count - 1; // Position of x\n\n        while (i > 0)\n        {\n            var p = (i - 1) / 2; // Start at half of i\n            if ((isDescending ? -1 : 1) * list[p].CompareTo(x) <= 0)\n            {\n                break;\n            }\n\n            list[i] = list[p]; // Put P to position of i\n            i = p; // I = (I-1)/2\n        }\n\n        if (Count > 0)\n        {\n            list[i] = x; // If while loop way executed at least once(X got replaced by some p), add it to the list\n        }\n    }\n\n    /// <summary>\n    ///     Dequeues the item at the end of the queue.\n    /// </summary>\n    /// <returns>The dequeued item.</returns>\n    public T Dequeue()\n    {\n        var target = Peek(); // Get first in list\n        var root = list[Count - 1]; // Hold last of the list\n        list.RemoveAt(Count - 1); // But remove it from the list\n\n        var i = 0;\n        while (i * 2 + 1 < Count)\n        {\n            var a = i * 2 + 1; // Every second entry starting by 1\n            var b = i * 2 + 2; // Every second entries neighbour\n            var c = b < Count && (isDescending ? -1 : 1) * list[b].CompareTo(list[a]) < 0\n                ? b\n                : a; // Whether B(B is in range && B is smaller than A) or A\n\n            if ((isDescending ? -1 : 1) * list[c].CompareTo(root) >= 0)\n            {\n                break;\n            }\n\n            list[i] = list[c];\n            i = c;\n        }\n\n        if (Count > 0)\n        {\n            list[i] = root;\n        }\n\n        return target;\n    }\n\n    /// <summary>\n    ///     Returns the next element in the queue without dequeuing.\n    /// </summary>\n    /// <returns>The next element of the queue.</returns>\n    public T Peek()\n    {\n        if (Count == 0)\n        {\n            throw new InvalidOperationException(\"Queue is empty.\");\n        }\n\n        return list[0];\n    }\n\n    /// <summary>\n    ///     Clears the Queue.\n    /// </summary>\n    public void Clear() => list.Clear();\n\n    /// <summary>\n    ///     Returns the Internal Data.\n    /// </summary>\n    /// <returns>The internal data structure.</returns>\n    public List<T> GetData() => list;\n}\n"
  },
  {
    "path": "Algorithms/Search/AStar/VecN.cs",
    "content": "namespace Algorithms.Search.AStar;\n\n/// <summary>\n///     Vector Struct with N Dimensions.\n/// </summary>\n/// <remarks>\n///     Initializes a new instance of the <see cref=\"VecN\" /> struct.\n/// </remarks>\n/// <param name=\"vals\">Vector components as array.</param>\npublic struct VecN(params double[] vals) : IEquatable<VecN>\n{\n    private readonly double[] data = vals;\n\n    /// <summary>\n    ///     Gets the dimension count of this vector.\n    /// </summary>\n    public int N => data.Length;\n\n    /// <summary>\n    ///     Returns the Length squared.\n    /// </summary>\n    /// <returns>The squared length of the vector.</returns>\n    public double SqrLength()\n    {\n        double ret = 0;\n        for (var i = 0; i < data.Length; i++)\n        {\n            ret += data[i] * data[i];\n        }\n\n        return ret;\n    }\n\n    /// <summary>\n    ///     Returns the Length of the vector.\n    /// </summary>\n    /// <returns>Length of the Vector.</returns>\n    public double Length() => Math.Sqrt(SqrLength());\n\n    /// <summary>\n    ///     Returns the Distance between this and other.\n    /// </summary>\n    /// <param name=\"other\">Other vector.</param>\n    /// <returns>The distance between this and other.</returns>\n    public double Distance(VecN other)\n    {\n        var delta = Subtract(other);\n        return delta.Length();\n    }\n\n    /// <summary>\n    ///     Returns the squared Distance between this and other.\n    /// </summary>\n    /// <param name=\"other\">Other vector.</param>\n    /// <returns>The squared distance between this and other.</returns>\n    public double SqrDistance(VecN other)\n    {\n        var delta = Subtract(other);\n        return delta.SqrLength();\n    }\n\n    /// <summary>\n    ///     Substracts other from this vector.\n    /// </summary>\n    /// <param name=\"other\">Other vector.</param>\n    /// <returns>The new vector.</returns>\n    public VecN Subtract(VecN other)\n    {\n        var dd = new double[Math.Max(data.Length, other.data.Length)];\n        for (var i = 0; i < dd.Length; i++)\n        {\n            double val = 0;\n            if (data.Length > i)\n            {\n                val = data[i];\n            }\n\n            if (other.data.Length > i)\n            {\n                val -= other.data[i];\n            }\n\n            dd[i] = val;\n        }\n\n        return new VecN(dd);\n    }\n\n    /// <summary>\n    ///     Is used to compare Vectors with each other.\n    /// </summary>\n    /// <param name=\"other\">The vector to be compared.</param>\n    /// <returns>A value indicating if other has the same values as this.</returns>\n    public bool Equals(VecN other)\n    {\n        if (other.N != N)\n        {\n            return false;\n        }\n\n        for (var i = 0; i < other.data.Length; i++)\n        {\n            if (Math.Abs(data[i] - other.data[i]) > 0.000001)\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Search/BinarySearcher.cs",
    "content": "namespace Algorithms.Search;\n\n/// <summary>\n///     Binary Searcher checks an array for element specified by checking\n///     if element is greater or less than the half being checked.\n///     time complexity: O(log(n)),\n///     space complexity: O(1).\n///     Note: Array must be sorted beforehand.\n/// </summary>\n/// <typeparam name=\"T\">Type of element stored inside array. 2.</typeparam>\npublic class BinarySearcher<T> where T : IComparable<T>\n{\n    /// <summary>\n    ///     Finds index of an array by using binary search.\n    /// </summary>\n    /// <param name=\"sortedData\">Sorted array to search in.</param>\n    /// <param name=\"item\">Item to search for.</param>\n    /// <returns>Index of item that equals to item searched for or -1 if none found.</returns>\n    public int FindIndex(T[] sortedData, T item)\n    {\n        var leftIndex = 0;\n        var rightIndex = sortedData.Length - 1;\n\n        while (leftIndex <= rightIndex)\n        {\n            var middleIndex = leftIndex + (rightIndex - leftIndex) / 2;\n\n            if (item.CompareTo(sortedData[middleIndex]) > 0)\n            {\n                leftIndex = middleIndex + 1;\n                continue;\n            }\n\n            if (item.CompareTo(sortedData[middleIndex]) < 0)\n            {\n                rightIndex = middleIndex - 1;\n                continue;\n            }\n\n            return middleIndex;\n        }\n\n        return -1;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Search/BoyerMoore.cs",
    "content": "namespace Algorithms.Search;\r\n\r\n/// <summary>\r\n///     A Boyer-Moore majority finder algorithm implementation.\r\n/// </summary>\r\n/// <typeparam name=\"T\">Type of element stored inside array.</typeparam>\r\npublic static class BoyerMoore<T> where T : IComparable\r\n{\r\n    public static T? FindMajority(IEnumerable<T> input)\r\n    {\r\n        var candidate = FindMajorityCandidate(input, input.Count());\r\n\r\n        if (VerifyMajority(input, input.Count(), candidate))\r\n        {\r\n            return candidate;\r\n        }\r\n\r\n        return default(T?);\r\n    }\r\n\r\n    // Find majority candidate\r\n    private static T FindMajorityCandidate(IEnumerable<T> input, int length)\r\n    {\r\n        int count = 1;\r\n        T candidate = input.First();\r\n\r\n        foreach (var element in input.Skip(1))\r\n        {\r\n            if (candidate.Equals(element))\r\n            {\r\n                count++;\r\n            }\r\n            else\r\n            {\r\n                count--;\r\n            }\r\n\r\n            if (count == 0)\r\n            {\r\n                candidate = element;\r\n                count = 1;\r\n            }\r\n        }\r\n\r\n        return candidate;\r\n    }\r\n\r\n    // Verify that candidate is indeed the majority\r\n    private static bool VerifyMajority(IEnumerable<T> input, int size, T candidate)\r\n    {\r\n        return input.Count(x => x.Equals(candidate)) > size / 2;\r\n    }\r\n}\r\n"
  },
  {
    "path": "Algorithms/Search/FastSearcher.cs",
    "content": "using Utilities.Exceptions;\n\nnamespace Algorithms.Search;\n\n/// <summary>\n///     The idea: you could combine the advantages from both binary-search and interpolation search algorithm.\n///     Time complexity:\n///     worst case: Item couldn't be found: O(log n),\n///     average case: O(log log n),\n///     best case: O(1).\n///     Note: This algorithm is recursive and the array has to be sorted beforehand.\n/// </summary>\npublic class FastSearcher\n{\n    /// <summary>\n    ///     Finds index of first item in array that satisfies specified term\n    ///     throws ItemNotFoundException if the item couldn't be found.\n    /// </summary>\n    /// <param name=\"array\">Span of sorted numbers which will be used to find the item.</param>\n    /// <param name=\"item\">Term to check against.</param>\n    /// <returns>Index of first item that satisfies term.</returns>\n    /// <exception cref=\"ItemNotFoundException\"> Gets thrown when the given item couldn't be found in the array.</exception>\n    public int FindIndex(Span<int> array, int item)\n    {\n        if (array.Length == 0)\n        {\n            throw new ItemNotFoundException();\n        }\n\n        if (item < array[0] || item > array[^1])\n        {\n            throw new ItemNotFoundException();\n        }\n\n        if (array[0] == array[^1])\n        {\n            return item == array[0] ? 0 : throw new ItemNotFoundException();\n        }\n\n        var (left, right) = ComputeIndices(array, item);\n        var (from, to) = SelectSegment(array, left, right, item);\n\n        return from + FindIndex(array.Slice(from, to - from + 1), item);\n    }\n\n    private (int Left, int Right) ComputeIndices(Span<int> array, int item)\n    {\n        var indexBinary = array.Length / 2;\n\n        int[] section =\n        [\n            array.Length - 1,\n            item - array[0],\n            array[^1] - array[0],\n        ];\n        var indexInterpolation = section[0] * section[1] / section[2];\n\n        // Left is min and right is max of the indices\n        return indexInterpolation > indexBinary\n            ? (indexBinary, indexInterpolation)\n            : (indexInterpolation, indexBinary);\n    }\n\n    private (int From, int To) SelectSegment(Span<int> array, int left, int right, int item)\n    {\n        if (item < array[left])\n        {\n            return (0, left - 1);\n        }\n\n        if (item < array[right])\n        {\n            return (left, right - 1);\n        }\n\n        return (right, array.Length - 1);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Search/FibonacciSearcher.cs",
    "content": "namespace Algorithms.Search;\n\n/// <summary>\n///     Class that implements Fibonacci search algorithm.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class FibonacciSearcher<T> where T : IComparable<T>\n{\n    /// <summary>\n    ///     Finds the index of the item searched for in the array.\n    ///     Time complexity:\n    ///     worst-case: O(log n),\n    ///     average-case: O(log n),\n    ///     best-case: O(1).\n    /// </summary>\n    /// <param name=\"array\">Sorted array to be searched in. Cannot be null.</param>\n    /// <param name=\"item\">Item to be searched for. Cannot be null.</param>\n    /// <returns>If an item is found, return index. If the array is empty or an item is not found, return -1.</returns>\n    /// <exception cref=\"ArgumentNullException\">Gets thrown when the given array or item is null.</exception>\n    public int FindIndex(T[] array, T item)\n    {\n        if (array is null)\n        {\n            throw new ArgumentNullException(\"array\");\n        }\n\n        if (item is null)\n        {\n            throw new ArgumentNullException(\"item\");\n        }\n\n        var arrayLength = array.Length;\n\n        if (arrayLength > 0)\n        {\n            // find the smallest Fibonacci number that equals or is greater than the array length\n            var fibonacciNumberBeyondPrevious = 0;\n            var fibonacciNumPrevious = 1;\n            var fibonacciNum = fibonacciNumPrevious;\n\n            while (fibonacciNum <= arrayLength)\n            {\n                fibonacciNumberBeyondPrevious = fibonacciNumPrevious;\n                fibonacciNumPrevious = fibonacciNum;\n                fibonacciNum = fibonacciNumberBeyondPrevious + fibonacciNumPrevious;\n            }\n\n            // offset to drop the left part of the array\n            var offset = -1;\n\n            while (fibonacciNum > 1)\n            {\n                var index = Math.Min(offset + fibonacciNumberBeyondPrevious, arrayLength - 1);\n\n                switch (item.CompareTo(array[index]))\n                {\n                    // reject approximately 1/3 of the existing array in front\n                    // by moving Fibonacci numbers\n                    case > 0:\n                        fibonacciNum = fibonacciNumPrevious;\n                        fibonacciNumPrevious = fibonacciNumberBeyondPrevious;\n                        fibonacciNumberBeyondPrevious = fibonacciNum - fibonacciNumPrevious;\n                        offset = index;\n                        break;\n\n                    // reject approximately 2/3 of the existing array behind\n                    // by moving Fibonacci numbers\n                    case < 0:\n                        fibonacciNum = fibonacciNumberBeyondPrevious;\n                        fibonacciNumPrevious = fibonacciNumPrevious - fibonacciNumberBeyondPrevious;\n                        fibonacciNumberBeyondPrevious = fibonacciNum - fibonacciNumPrevious;\n                        break;\n                    default:\n                        return index;\n                }\n            }\n\n            // check the last element\n            if (fibonacciNumPrevious == 1 && item.Equals(array[^1]))\n            {\n                return arrayLength - 1;\n            }\n        }\n\n        return -1;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Search/InterpolationSearch.cs",
    "content": "namespace Algorithms.Search;\n\n/// <summary>\n///     Class that implements interpolation search algorithm.\n/// </summary>\npublic static class InterpolationSearch\n{\n    /// <summary>\n    ///     Finds the index of the item searched for in the array.\n    ///     Algorithm performance:\n    ///     worst-case: O(n),\n    ///     average-case: O(log(log(n))),\n    ///     best-case: O(1).\n    /// </summary>\n    /// <param name=\"sortedArray\">Array with sorted elements to be searched in. Cannot be null.</param>\n    /// <param name=\"val\">Value to be searched for. Cannot be null.</param>\n    /// <returns>If an item is found, return index, else return -1.</returns>\n    public static int FindIndex(int[] sortedArray, int val)\n    {\n        var start = 0;\n        var end = sortedArray.Length - 1;\n\n        while (start <= end && val >= sortedArray[start] && val <= sortedArray[end])\n        {\n            var denominator = (sortedArray[end] - sortedArray[start]) * (val - sortedArray[start]);\n\n            if (denominator == 0)\n            {\n                denominator = 1;\n            }\n\n            var pos = start + (end - start) / denominator;\n\n            if (sortedArray[pos] == val)\n            {\n                return pos;\n            }\n\n            if (sortedArray[pos] < val)\n            {\n                start = pos + 1;\n            }\n            else\n            {\n                end = pos - 1;\n            }\n        }\n\n        return -1;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Search/JumpSearcher.cs",
    "content": "namespace Algorithms.Search;\n\n/// <summary>\n///     Jump Search checks fewer elements by jumping ahead by fixed steps.\n///     The optimal steps to jump is √n, where n refers to the number of elements in the array.\n///     Time Complexity: O(√n)\n///     Note: The array has to be sorted beforehand.\n/// </summary>\n/// <typeparam name=\"T\">Type of the array element.</typeparam>\npublic class JumpSearcher<T> where T : IComparable<T>\n{\n    /// <summary>\n    ///     Find the index of the item searched for in the array.\n    /// </summary>\n    /// <param name=\"sortedArray\">Sorted array to be search in. Cannot be null.</param>\n    /// <param name=\"searchItem\">Item to be search for. Cannot be null.</param>\n    /// <returns>If item is found, return index. If array is empty or item not found, return -1.</returns>\n    public int FindIndex(T[] sortedArray, T searchItem)\n    {\n        if (sortedArray is null)\n        {\n            throw new ArgumentNullException(\"sortedArray\");\n        }\n\n        if (searchItem is null)\n        {\n            throw new ArgumentNullException(\"searchItem\");\n        }\n\n        int jumpStep = (int)Math.Floor(Math.Sqrt(sortedArray.Length));\n        int currentIndex = 0;\n        int nextIndex = jumpStep;\n\n        if (sortedArray.Length != 0)\n        {\n            while (sortedArray[nextIndex - 1].CompareTo(searchItem) < 0)\n            {\n                currentIndex = nextIndex;\n                nextIndex += jumpStep;\n\n                if (nextIndex >= sortedArray.Length)\n                {\n                    nextIndex = sortedArray.Length - 1;\n                    break;\n                }\n            }\n\n            for (int i = currentIndex; i <= nextIndex; i++)\n            {\n                if (sortedArray[i].CompareTo(searchItem) == 0)\n                {\n                    return i;\n                }\n            }\n        }\n\n        return -1;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Search/LinearSearcher.cs",
    "content": "using Utilities.Exceptions;\n\nnamespace Algorithms.Search;\n\n/// <summary>\n///     Class that implements linear search algorithm.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class LinearSearcher<T>\n{\n    /// <summary>\n    ///     Finds first item in array that satisfies specified term\n    ///     Time complexity: O(n)\n    ///     Space complexity: O(1).\n    /// </summary>\n    /// <param name=\"data\">Array to search in.</param>\n    /// <param name=\"term\">Term to check against.</param>\n    /// <returns>First item that satisfies term.</returns>\n    public T Find(T[] data, Func<T, bool> term)\n    {\n        for (var i = 0; i < data.Length; i++)\n        {\n            if (term(data[i]))\n            {\n                return data[i];\n            }\n        }\n\n        throw new ItemNotFoundException();\n    }\n\n    /// <summary>\n    ///     Finds index of first item in array that satisfies specified term\n    ///     Time complexity: O(n)\n    ///     Space complexity: O(1).\n    /// </summary>\n    /// <param name=\"data\">Array to search in.</param>\n    /// <param name=\"term\">Term to check against.</param>\n    /// <returns>Index of first item that satisfies term or -1 if none found.</returns>\n    public int FindIndex(T[] data, Func<T, bool> term)\n    {\n        for (var i = 0; i < data.Length; i++)\n        {\n            if (term(data[i]))\n            {\n                return i;\n            }\n        }\n\n        return -1;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Search/RecursiveBinarySearcher.cs",
    "content": "namespace Algorithms.Search;\n\n/// <summary>\n///     RecursiveBinarySearcher.\n/// </summary>\n/// <typeparam name=\"T\">Type of searcher target.</typeparam>\npublic class RecursiveBinarySearcher<T> where T : IComparable<T>\n{\n    /// <summary>\n    ///     Finds index of item in collection that equals to item searched for,\n    ///     time complexity: O(log(n)),\n    ///     space complexity: O(1),\n    ///     where n - collection size.\n    /// </summary>\n    /// <param name=\"collection\">Sorted collection to search in.</param>\n    /// <param name=\"item\">Item to search for.</param>\n    /// <exception cref=\"ArgumentNullException\">Thrown if input collection is null.</exception>\n    /// <returns>Index of item that equals to item searched for or -1 if none found.</returns>\n    public int FindIndex(IList<T>? collection, T item)\n    {\n        if (collection is null)\n        {\n            throw new ArgumentNullException(nameof(collection));\n        }\n\n        var leftIndex = 0;\n        var rightIndex = collection.Count - 1;\n\n        return FindIndex(collection, item, leftIndex, rightIndex);\n    }\n\n    /// <summary>\n    ///     Finds index of item in array that equals to item searched for,\n    ///     time complexity: O(log(n)),\n    ///     space complexity: O(1),\n    ///     where n - array size.\n    /// </summary>\n    /// <param name=\"collection\">Sorted array to search in.</param>\n    /// <param name=\"item\">Item to search for.</param>\n    /// <param name=\"leftIndex\">Minimum search range.</param>\n    /// <param name=\"rightIndex\">Maximum search range.</param>\n    /// <returns>Index of item that equals to item searched for or -1 if none found.</returns>\n    private int FindIndex(IList<T> collection, T item, int leftIndex, int rightIndex)\n    {\n        if (leftIndex > rightIndex)\n        {\n            return -1;\n        }\n\n        var middleIndex = leftIndex + (rightIndex - leftIndex) / 2;\n        var result = item.CompareTo(collection[middleIndex]);\n\n        return result switch\n        {\n            var r when r == 0 => middleIndex,\n            var r when r > 0 => FindIndex(collection, item, middleIndex + 1, rightIndex),\n            var r when r < 0 => FindIndex(collection, item, leftIndex, middleIndex - 1),\n            _ => -1,\n        };\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/AllOnesSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         The all ones sequence.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000012.\n///     </para>\n/// </summary>\npublic class AllOnesSequence : ISequence\n{\n    /// <summary>\n    ///     Gets all ones sequence.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            while (true)\n            {\n                yield return 1;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/AllThreesSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         The all threes sequence.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A010701.\n///     </para>\n/// </summary>\npublic class AllThreesSequence : ISequence\n{\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            while (true)\n            {\n                yield return 3;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/AllTwosSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         The all twos sequence.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A007395.\n///     </para>\n/// </summary>\npublic class AllTwosSequence : ISequence\n{\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            while (true)\n            {\n                yield return 2;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/BinaryPrimeConstantSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of binary prime constant\n///         (Characteristic function of primes: 1 if n is prime, else 0).\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Prime_constant.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A010051.\n///     </para>\n/// </summary>\npublic class BinaryPrimeConstantSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of binary prime constant.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            ISequence primes = new PrimesSequence();\n            var n = new BigInteger(0);\n\n            foreach (var p in primes.Sequence)\n            {\n                for (n++; n < p; n++)\n                {\n                    yield return 0;\n                }\n\n                yield return 1;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/BinomialSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of binomial coefficients.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Binomial_coefficient.\n///     </para>\n///     <para>\n///         OEIS: http://oeis.org/A007318.\n///     </para>\n/// </summary>\npublic class BinomialSequence : ISequence\n{\n    /// <summary>\n    ///     Gets sequence of binomial coefficients.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var i = 0;\n\n            while (true)\n            {\n                var row = GenerateRow(i);\n                foreach (var coefficient in row)\n                {\n                    yield return coefficient;\n                }\n\n                i++;\n            }\n        }\n    }\n\n    private static BigInteger BinomialCoefficient(long n, long k)\n    {\n        if (k == 0 || k == n)\n        {\n            return new BigInteger(1);\n        }\n\n        if (n < 0)\n        {\n            return new BigInteger(0);\n        }\n\n        return BinomialCoefficient(n - 1, k) + BinomialCoefficient(n - 1, k - 1);\n    }\n\n    private static IEnumerable<BigInteger> GenerateRow(long n)\n    {\n        long k = 0;\n\n        while (k <= n)\n        {\n            yield return BinomialCoefficient(n, k);\n            k++;\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/CakeNumbersSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Cake numbers: maximal number of pieces resulting from n planar cuts through a cube\n///         (or cake): C(n+1,3) + n + 1.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000125.\n///     </para>\n/// </summary>\npublic class CakeNumbersSequence : ISequence\n{\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var n = new BigInteger(0);\n            while (true)\n            {\n                var next = (BigInteger.Pow(n, 3) + 5 * n + 6) / 6;\n                n++;\n                yield return next;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/CatalanSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Catalan numbers: C[n+1] = (2*(2*n+1)*C[n])/(n+2).\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Catalan_number.\n///     </para>\n///     <para>\n///         OEIS:http://oeis.org/A000108.\n///     </para>\n/// </summary>\npublic class CatalanSequence : ISequence\n{\n    /// <summary>\n    ///     Gets sequence of Catalan numbers.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            // initialize the first element (1) and define it's enumerator (0)\n            var catalan = new BigInteger(1);\n            var n = 0;\n            while (true)\n            {\n                yield return catalan;\n                catalan = (2 * (2 * n + 1) * catalan) / (n + 2);\n                n++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/CentralPolygonalNumbersSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Central polygonal numbers (the Lazy Caterer's sequence): n(n+1)/2 + 1; or, maximal number of pieces\n///         formed when slicing a pancake with n cuts.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000124.\n///     </para>\n/// </summary>\npublic class CentralPolygonalNumbersSequence : ISequence\n{\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var n = new BigInteger(0);\n            while (true)\n            {\n                var next = n * (n + 1) / 2 + 1;\n                n++;\n                yield return next;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/CubesSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of cube numbers.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Cube_(algebra).\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000578.\n///     </para>\n/// </summary>\npublic class CubesSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of cube numbers.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var n = BigInteger.Zero;\n\n            while (true)\n            {\n                yield return n * n * n;\n                n++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/DivisorsCountSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of the number of divisors of n, starting with 1.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000005.\n///     </para>\n/// </summary>\npublic class DivisorsCountSequence : ISequence\n{\n    /// <summary>\n    ///     Gets sequence of number of divisors for n, starting at 1.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            yield return BigInteger.One;\n            for (var n = new BigInteger(2); ; n++)\n            {\n                var count = 2;\n                for (var k = 2; k < n; k++)\n                {\n                    BigInteger.DivRem(n, k, out var remainder);\n                    if (remainder == 0)\n                    {\n                        count++;\n                    }\n                }\n\n                yield return count;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/EuclidNumbersSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of Euclid numbers: 1 + product of the first n primes.\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Euclid_number.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A006862.\n///     </para>\n/// </summary>\npublic class EuclidNumbersSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of Euclid numbers.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var primorialNumbers = new PrimorialNumbersSequence().Sequence;\n\n            foreach (var n in primorialNumbers)\n            {\n                yield return n + 1;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/EulerTotientSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of Euler totient function phi(n).\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Euler%27s_totient_function.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000010.\n///     </para>\n/// </summary>\npublic class EulerTotientSequence : ISequence\n{\n    /// <summary>\n    ///     <para>\n    ///         Gets sequence of Euler totient function phi(n).\n    ///     </para>\n    ///     <para>\n    ///         'n' is copied from value of the loop of i that's being enumerated over.\n    ///         1) Initialize result as n\n    ///         2) Consider every number 'factor' (where 'factor' is a prime divisor of n).\n    ///            If factor divides n, then do following\n    ///            a) Subtract all multiples of factor from 1 to n [all multiples of factor\n    ///               will have gcd more than 1 (at least factor) with n]\n    ///            b) Update n by repeatedly dividing it by factor.\n    ///         3) If the reduced n is more than 1, then remove all multiples\n    ///            of n from result.\n    ///     </para>\n    ///     <para>\n    ///         Base code was from https://www.geeksforgeeks.org/eulers-totient-function/.\n    ///      </para>\n    ///     <para>\n    ///         Implementation avoiding floating point operations was used for base\n    ///         and replacement of loop going from 1 to sqrt(n) was replaced with\n    ///         List of prime factors.\n    ///     </para>\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            yield return BigInteger.One;\n\n            for (BigInteger i = 2; ; i++)\n            {\n                var n = i;\n                var result = n;\n\n                var factors = PrimeFactors(i);\n                foreach (var factor in factors)\n                {\n                    while (n % factor == 0)\n                    {\n                        n /= factor;\n                    }\n\n                    result -= result / factor;\n                }\n\n                if (n > 1)\n                {\n                    result -= result / n;\n                }\n\n                yield return result;\n            }\n        }\n    }\n\n    /// <summary>\n    ///     <para>\n    ///         Uses the prime sequence to find all prime factors of the\n    ///         number we're looking at.\n    ///     </para>\n    ///     <para>\n    ///         The prime sequence is examined until its value squared is\n    ///         less than or equal to target, and checked to make sure it\n    ///         evenly divides the target.  If it evenly divides, it's added\n    ///         to the result which is returned as a List.\n    ///     </para>\n    /// </summary>\n    /// <param name=\"target\">Number that is being factored.</param>\n    /// <returns>List of prime factors of target.</returns>\n    private static IEnumerable<BigInteger> PrimeFactors(BigInteger target)\n    {\n        return new PrimesSequence()\n              .Sequence.TakeWhile(prime => prime * prime <= target)\n              .Where(prime => target % prime == 0)\n              .ToList();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/FactorialSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of factorial numbers.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Factorial.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000142.\n///     </para>\n/// </summary>\npublic class FactorialSequence : ISequence\n{\n    /// <summary>\n    ///     Gets sequence of factorial numbers.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var n = 0;\n            var factorial = new BigInteger(1);\n            while (true)\n            {\n                yield return factorial;\n                n++;\n                factorial *= n;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/FermatNumbersSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of Fermat numbers: a(n) = 2^(2^n) + 1.\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Fermat_number.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000215.\n///     </para>\n/// </summary>\npublic class FermatNumbersSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of Fermat numbers.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var n = new BigInteger(2);\n\n            while (true)\n            {\n                yield return n + 1;\n                n *= n;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/FermatPrimesSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of Fermat primes: primes of the form 2^(2^k) + 1, for some k >= 0.\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Fermat_number.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A019434.\n///     </para>\n/// </summary>\npublic class FermatPrimesSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of Fermat primes.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var fermatNumbers = new FermatNumbersSequence().Sequence.Take(5);\n\n            foreach (var n in fermatNumbers)\n            {\n                yield return n;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/FibonacciSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Fibonacci sequence.\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Fibonacci_number.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000045.\n///     </para>\n/// </summary>\npublic class FibonacciSequence : ISequence\n{\n    /// <summary>\n    ///     Gets Fibonacci sequence.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            yield return 0;\n            yield return 1;\n            BigInteger previous = 0;\n            BigInteger current = 1;\n            while (true)\n            {\n                var next = previous + current;\n                previous = current;\n                current = next;\n                yield return next;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/GolombsSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Golomb's sequence. a(n) is the number of times n occurs in the sequence, starting with a(1) = 1.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Golomb_sequence.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A001462.\n///     </para>\n/// </summary>\npublic class GolombsSequence : ISequence\n{\n    /// <summary>\n    ///     Gets Golomb's sequence.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            yield return 1;\n            yield return 2;\n            yield return 2;\n\n            var queue = new Queue<BigInteger>();\n            queue.Enqueue(2);\n\n            for (var i = 3; ; i++)\n            {\n                var repetitions = queue.Dequeue();\n                for (var j = 0; j < repetitions; j++)\n                {\n                    queue.Enqueue(i);\n                    yield return i;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/ISequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     Common interface for all integer sequences.\n/// </summary>\npublic interface ISequence\n{\n    /// <summary>\n    ///     Gets sequence as enumerable.\n    /// </summary>\n    IEnumerable<BigInteger> Sequence { get; }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/KolakoskiSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Kolakoski sequence; n-th element is the length of the n-th run in the sequence itself.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Kolakoski_sequence.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000002.\n///     </para>\n/// </summary>\npublic class KolakoskiSequence : ISequence\n{\n    /// <summary>\n    /// Gets Kolakoski sequence.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            yield return 1;\n            yield return 2;\n            yield return 2;\n\n            var queue = new Queue<int>();\n            queue.Enqueue(2);\n            var nextElement = 1;\n            while (true)\n            {\n                var nextRun = queue.Dequeue();\n                for (var i = 0; i < nextRun; i++)\n                {\n                    queue.Enqueue(nextElement);\n                    yield return nextElement;\n                }\n\n                nextElement = 1 + nextElement % 2;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/KolakoskiSequence2.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Kolakoski sequence; n-th element is the length of the n-th run in the sequence itself.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Kolakoski_sequence.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000002.\n///     </para>\n/// </summary>\npublic class KolakoskiSequence2 : ISequence\n{\n    /// <summary>\n    /// Gets Kolakoski sequence.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            yield return 1;\n            yield return 2;\n            yield return 2;\n\n            var inner = new KolakoskiSequence2().Sequence.Skip(2);\n            var nextElement = 1;\n            foreach (var runLength in inner)\n            {\n                yield return nextElement;\n                if (runLength > 1)\n                {\n                    yield return nextElement;\n                }\n\n                nextElement = 1 + nextElement % 2;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/KummerNumbersSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of Kummer numbers (also called Euclid numbers of the second kind):\n///         -1 + product of first n consecutive primes.\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Euclid_number.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A057588.\n///     </para>\n/// </summary>\npublic class KummerNumbersSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of Kummer numbers.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var primorialNumbers = new PrimorialNumbersSequence().Sequence.Skip(1);\n\n            foreach (var n in primorialNumbers)\n            {\n                yield return n - 1;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of Lucas number values.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Lucas_number.\n///     </para>\n///     <para>\n///         OEIS: http://oeis.org/A000032.\n///     </para>\n/// </summary>\npublic class LucasNumbersBeginningAt2Sequence : ISequence\n{\n    /// <summary>\n    ///     <para>\n    ///         Gets Lucas number sequence.\n    ///     </para>\n    ///     <para>\n    ///         Lucas numbers follow the same type of operation that the Fibonacci (A000045)\n    ///         sequence performs with starting values of 2, 1 versus 0,1.  As Fibonacci does,\n    ///         the ratio between two consecutive Lucas numbers converges to phi.\n    ///     </para>\n    ///     <para>\n    ///         This implementation is similar to A000204, but starts with the index of 0, thus having the\n    ///         initial values being (2,1) instead of starting at index 1 with initial values of (1,3).\n    ///     </para>\n    ///     <para>\n    ///         A simple relationship to Fibonacci can be shown with L(n) = F(n-1) + F(n+1), n>= 1.\n    ///\n    ///         n |  L(n) | F(n-1) | F(n+1)\n    ///         --|-------|--------+--------+\n    ///         0 |   2   |        |        |\n    ///         1 |   1   |      0 |      1 |\n    ///         2 |   3   |      1 |      2 |\n    ///         3 |   4   |      1 |      3 |\n    ///         4 |   7   |      2 |      5 |\n    ///         5 |  11   |      3 |      8 |\n    ///         --|-------|--------+--------+.\n    ///     </para>\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            yield return 2;\n            yield return 1;\n            BigInteger previous = 2;\n            BigInteger current = 1;\n            while (true)\n            {\n                var next = previous + current;\n                previous = current;\n                current = next;\n\n                yield return next;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/MakeChangeSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Number of ways of making change for n cents using coins of 1, 2, 5, 10 cents.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000008.\n///     </para>\n/// </summary>\npublic class MakeChangeSequence : ISequence\n{\n    /// <summary>\n    ///     <para>\n    ///         Gets sequence of number of ways of making change for n cents\n    ///         using coins of 1, 2, 5, 10 cents.\n    ///     </para>\n    ///     <para>\n    ///         Uses formula from OEIS page by Michael Somos\n    ///         along with first 17 values to prevent index issues.\n    ///     </para>\n    ///     <para>\n    ///         Formula:\n    ///         a(n) = a(n-2) +a(n-5) - a(n-7) + a(n-10) - a(n-12) - a(n-15) + a(n-17) + 1.\n    ///     </para>\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var seed = new List<BigInteger>\n                       {\n                           1, 1, 2, 2, 3, 4, 5, 6, 7, 8,\n                           11, 12, 15, 16, 19, 22, 25,\n                       };\n            foreach (var value in seed)\n            {\n                yield return value;\n            }\n\n            for (var index = 17; ; index++)\n            {\n                BigInteger newValue = seed[index - 2] + seed[index - 5] - seed[index - 7]\n                                    + seed[index - 10] - seed[index - 12] - seed[index - 15]\n                                    + seed[index - 17] + 1;\n\n                seed.Add(newValue);\n                yield return newValue;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/MatchstickTriangleSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of number of triangles in triangular matchstick arrangement of side n for n>=0.\n///     </para>\n///     <para>\n///         M. E. Larsen, The eternal triangle – a history of a counting problem, College Math. J., 20 (1989), 370-392.\n///         https://web.math.ku.dk/~mel/mel.pdf.\n///     </para>\n///     <para>\n///         OEIS: http://oeis.org/A002717.\n///     </para>\n/// </summary>\npublic class MatchstickTriangleSequence : ISequence\n{\n    /// <summary>\n    ///     <para>\n    ///         Gets number of triangles contained in an triangular arrangement of matchsticks of side length n.\n    ///     </para>\n    ///     <para>\n    ///         This also counts the subset of smaller triangles contained within the arrangement.\n    ///     </para>\n    ///     <para>\n    ///         Based on the PDF referenced above, the sequence is derived from step 8, using the resulting equation\n    ///         of f(n) = (n(n+2)(2n+1) -(delta)(n)) / 8.  Using BigInteger values, we can effectively remove\n    ///         (delta)(n) from the previous by using integer division instead.\n    ///     </para>\n    ///     <para>\n    ///         Examples follow.\n    /// <pre>\n    ///   .\n    ///  / \\   This contains 1 triangle of size 1.\n    /// .---.\n    ///\n    ///     .\n    ///    / \\     This contains 4 triangles of size 1.\n    ///   .---.    This contains 1 triangle of size 2.\n    ///  / \\ / \\   This contains 5 triangles total.\n    /// .---.---.\n    ///\n    ///       .\n    ///      / \\      This contains 9 triangles of size 1.\n    ///     .---.     This contains 3 triangles of size 2.\n    ///    / \\ / \\    This contains 1 triangles of size 3.\n    ///   .---.---.\n    ///  / \\ / \\ / \\  This contains 13 triangles total.\n    /// .---.---.---.\n    /// </pre>\n    ///     </para>\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var index = BigInteger.Zero;\n            var eight = new BigInteger(8);\n            while (true)\n            {\n                var temp = index * (index + 2) * (index * 2 + 1);\n                var result = BigInteger.Divide(temp, eight);\n                yield return result;\n                index++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/NaturalSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of natural numbers.\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Natural_number.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000027.\n///     </para>\n/// </summary>\npublic class NaturalSequence : ISequence\n{\n    /// <summary>\n    ///     Gets sequence of natural numbers.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var n = new BigInteger(1);\n            while (true)\n            {\n                yield return n++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/NegativeIntegersSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of negative integers.\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Negative_number.\n///     </para>\n///     <para>\n///         OEIS: http://oeis.org/A001478.\n///     </para>\n/// </summary>\npublic class NegativeIntegersSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of negative integers.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var n = new BigInteger(-1);\n\n            while (true)\n            {\n                yield return n--;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/NumberOfBooleanFunctionsSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of number of truth tables generated by Boolean expressions of n variables\n///         (Double exponentials of 2: a(n) = 2^(2^n)).\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Truth_table.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A001146.\n///     </para>\n/// </summary>\npublic class NumberOfBooleanFunctionsSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of number Of Boolean functions.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var n = new BigInteger(2);\n\n            while (true)\n            {\n                yield return n;\n                n *= n;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/NumberOfPrimesByNumberOfDigitsSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Number of primes with n digits\n///         (The number of primes between 10^(n-1) and 10^n).\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Prime-counting_function.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A006879.\n///     </para>\n/// </summary>\npublic class NumberOfPrimesByNumberOfDigitsSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of number of primes.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            ISequence primes = new PrimesSequence();\n            var powerOf10 = new BigInteger(1);\n            var counter = new BigInteger(0);\n\n            foreach (var p in primes.Sequence)\n            {\n                if (p > powerOf10)\n                {\n                    yield return counter;\n                    counter = 0;\n                    powerOf10 *= 10;\n                }\n\n                counter++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/NumberOfPrimesByPowersOf10Sequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of number of primes less than 10^n (with at most n digits).\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Prime-counting_function.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A006880.\n///     </para>\n/// </summary>\npublic class NumberOfPrimesByPowersOf10Sequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of numbers of primes.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            ISequence primes = new PrimesSequence();\n            var powerOf10 = new BigInteger(1);\n            var counter = new BigInteger(0);\n\n            foreach (var p in primes.Sequence)\n            {\n                if (p > powerOf10)\n                {\n                    yield return counter;\n                    powerOf10 *= 10;\n                }\n\n                counter++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/OnesCountingSequence.cs",
    "content": "﻿namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         1's-counting sequence: number of 1's in binary expression of n.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000120.\n///     </para>\n/// </summary>\npublic class OnesCountingSequence : ISequence\n{\n    /// <summary>\n    ///     <para>\n    ///         Gets the generated sequence of the 1's contained in the binary representation of n.\n    ///     </para>\n    ///     <para>\n    ///         The sequence is generated as follows.\n    ///         1. The initial 0 value is provided.\n    ///         2. A recursively generated sequence is iterated, starting with a length of 1 (i.e., 2^0),\n    ///            followed by increasing 2^x length values.\n    ///         3. Each sequence starts with the value 1, and a targeted value of depths that it will recurse\n    ///            for the specific iteration.\n    ///         4. If the call depth to the recursive function is met, it returns the value argument received.\n    ///         5. If the call depth has not been met, it recurses to create 2 sequences, one starting with the\n    ///            value argument, and the following with the value argument + 1.\n    ///         6. Using ':' as a visual separator for each sequence, this results in the following sequences\n    ///            that are returned sequentially after the initial 0.\n    ///            1 : 1, 2 : 1, 2, 2, 3 : 1, 2, 2, 3, 2, 3, 3, 4.\n    ///     </para>\n    ///     <remarks>\n    ///         <para>\n    ///         This one comes from thinking over information contained within the COMMENTS section of the OEIS page.\n    ///         </para>\n    ///         <para>\n    ///             Using the comments provided by Benoit Cloitre, Robert G. Wilson v, and Daniel Forgues, the above\n    ///             algorithm was coded.\n    ///         </para>\n    ///     </remarks>\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            yield return 0;\n            var depth = 0;\n            while (true)\n            {\n                foreach (var count in GenerateFractalCount(BigInteger.One, depth))\n                {\n                    yield return count;\n                }\n\n                depth++;\n            }\n        }\n    }\n\n    /// <summary>\n    ///     <para>\n    ///         Recursive function to generate sequences.\n    ///     </para>\n    /// </summary>\n    /// <param name=\"i\">The value that will start off the current IEnumerable sequence.</param>\n    /// <param name=\"depth\">The remaining depth of recursion.  Value of 0 is the stop condition.</param>\n    /// <returns>An IEnumerable sequence of BigInteger values that can be iterated over.</returns>\n    private static IEnumerable<BigInteger> GenerateFractalCount(BigInteger i, int depth)\n    {\n        // Terminal condition\n        if (depth == 0)\n        {\n            yield return i;\n            yield break;\n        }\n\n        foreach (var firstHalf in GenerateFractalCount(i, depth - 1))\n        {\n            yield return firstHalf;\n        }\n\n        foreach (var secondHalf in GenerateFractalCount(i + 1, depth - 1))\n        {\n            yield return secondHalf;\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/PowersOf10Sequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of powers of 10: a(n) = 10^n.\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Power_of_10.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A011557.\n///     </para>\n/// </summary>\npublic class PowersOf10Sequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of powers of 10.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var n = new BigInteger(1);\n\n            while (true)\n            {\n                yield return n;\n                n *= 10;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/PowersOf2Sequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of powers of 2: a(n) = 2^n.\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Power_of_two.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000079.\n///     </para>\n/// </summary>\npublic class PowersOf2Sequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of powers of 2.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var n = new BigInteger(1);\n\n            while (true)\n            {\n                yield return n;\n                n *= 2;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/PrimePiSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of number of primes less than or equal to n (PrimePi(n)).\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Prime-counting_function.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000720.\n///     </para>\n/// </summary>\npublic class PrimePiSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of number of primes.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            ISequence primes = new PrimesSequence();\n            var n = new BigInteger(0);\n            var counter = new BigInteger(0);\n\n            foreach (var p in primes.Sequence)\n            {\n                for (n++; n < p; n++)\n                {\n                    yield return counter;\n                }\n\n                yield return ++counter;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/PrimesSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of prime numbers.\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Prime_number.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000040.\n///     </para>\n/// </summary>\npublic class PrimesSequence : ISequence\n{\n    /// <summary>\n    ///     Gets sequence of prime numbers.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            yield return 2;\n            var primes = new List<BigInteger>\n            {\n                2,\n            };\n            var n = new BigInteger(3);\n\n            while (true)\n            {\n                if (primes.All(p => n % p != 0))\n                {\n                    yield return n;\n                    primes.Add(n);\n                }\n\n                n += 2;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/PrimorialNumbersSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of primorial numbers: product of first n primes.\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Primorial.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A002110.\n///     </para>\n/// </summary>\npublic class PrimorialNumbersSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of primorial numbers.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var primes = new PrimesSequence().Sequence;\n            var n = new BigInteger(1);\n\n            foreach (var p in primes)\n            {\n                yield return n;\n                n *= p;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/RecamansSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Recaman's sequence. a(0) = 0; for n > 0, a(n) = a(n-1) - n if nonnegative and not already in the sequence, otherwise a(n) = a(n-1) + n.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Recam%C3%A1n%27s_sequence.\n///     </para>\n///     <para>\n///         OEIS: http://oeis.org/A005132.\n///     </para>\n/// </summary>\npublic class RecamansSequence : ISequence\n{\n    /// <summary>\n    ///     Gets Recaman's sequence.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            yield return 0;\n            var elements = new HashSet<BigInteger> { 0 };\n            var previous = 0;\n            var i = 1;\n\n            while (true)\n            {\n                var current = previous - i;\n                if (current < 0 || elements.Contains(current))\n                {\n                    current = previous + i;\n                }\n\n                yield return current;\n                previous = current;\n                elements.Add(current);\n                i++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/SquaresSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of square numbers.\n///     </para>\n///     <para>\n///         Wikipedia: https://wikipedia.org/wiki/Square_number.\n///     </para>\n///     <para>\n///         OEIS: http://oeis.org/A000290.\n///     </para>\n/// </summary>\npublic class SquaresSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of square numbers.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var n = new BigInteger(0);\n\n            while (true)\n            {\n                yield return n * n;\n                n++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/TetrahedralSequence.cs",
    "content": "﻿namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Sequence of tetrahedral (triangular pyramids) counts for n >= 0.\n///     </para>\n///     <para>\n///         OEIS: http://oeis.org/A000292.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Tetrahedral_number.\n///     </para>\n/// </summary>\npublic class TetrahedralSequence : ISequence\n{\n    /// <summary>\n    ///     <para>\n    ///         Gets the value of packing spheres in a regular tetrahedron\n    ///         with increasing by 1 triangular numbers under each layer.\n    ///     </para>\n    ///     <para>\n    ///         It can be reviewed by starting at the 4th row of Pascal's Triangle\n    ///         following the diagonal values going into the triangle.\n    ///     </para>\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var index = BigInteger.Zero;\n            var six = new BigInteger(6);\n            while (true)\n            {\n                yield return BigInteger.Divide(index * (index + 1) * (index + 2), six);\n                index++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/TetranacciNumbersSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Tetranacci numbers: a(n) = a(n-1) + a(n-2) + a(n-3) + a(n-4) with a(0) = a(1) = a(2) = a(3) = 1.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000288.\n///     </para>\n/// </summary>\npublic class TetranacciNumbersSequence : ISequence\n{\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var buffer = Enumerable.Repeat(BigInteger.One, 4).ToArray();\n            while (true)\n            {\n                yield return buffer[0];\n                var next = buffer[0] + buffer[1] + buffer[2] + buffer[3];\n                buffer[0] = buffer[1];\n                buffer[1] = buffer[2];\n                buffer[2] = buffer[3];\n                buffer[3] = next;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/ThreeNPlusOneStepsSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Number of halving and tripling steps to reach 1 in the '3n+1' problem.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Collatz_conjecture.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A006577.\n///     </para>\n/// </summary>\npublic class ThreeNPlusOneStepsSequence : ISequence\n{\n    /// <summary>\n    /// Gets sequence of number of halving and tripling steps to reach 1 in the '3n+1' problem.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            BigInteger startingValue = 1;\n\n            while (true)\n            {\n                BigInteger counter = 0;\n                BigInteger currentValue = startingValue;\n\n                while (currentValue != 1)\n                {\n                    if (currentValue.IsEven)\n                    {\n                        currentValue /= 2;\n                    }\n                    else\n                    {\n                        currentValue = 3 * currentValue + 1;\n                    }\n\n                    counter++;\n                }\n\n                yield return counter;\n                startingValue++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/TribonacciNumbersSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Tribonacci numbers: a(n) = a(n-1) + a(n-2) + a(n-3) with a(0)=a(1)=a(2)=1.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000213.\n///     </para>\n/// </summary>\npublic class TribonacciNumbersSequence : ISequence\n{\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            var buffer = Enumerable.Repeat(BigInteger.One, 4).ToArray();\n            while (true)\n            {\n                yield return buffer[0];\n                var next = buffer[0] + buffer[1] + buffer[2];\n                buffer[0] = buffer[1];\n                buffer[1] = buffer[2];\n                buffer[2] = next;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/VanEcksSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         Van Eck's sequence. For n >= 1, if there exists an m &lt; n such that a(m) = a(n), take the largest such m and set a(n+1) = n-m; otherwise a(n+1) = 0. Start with a(1)=0.\n///     </para>\n///     <para>\n///         OEIS: http://oeis.org/A181391.\n///     </para>\n/// </summary>\npublic class VanEcksSequence : ISequence\n{\n    /// <summary>\n    ///     Gets Van Eck's sequence.\n    /// </summary>\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            yield return 0;\n            var dictionary = new Dictionary<BigInteger, BigInteger>();\n            BigInteger previous = 0;\n            BigInteger currentIndex = 2; // 1-based index\n            while (true)\n            {\n                BigInteger element = 0;\n                if (dictionary.TryGetValue(previous, out var previousIndex))\n                {\n                    element = currentIndex - previousIndex;\n                }\n\n                yield return element;\n\n                dictionary[previous] = currentIndex;\n                previous = element;\n                currentIndex++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sequences/ZeroSequence.cs",
    "content": "namespace Algorithms.Sequences;\n\n/// <summary>\n///     <para>\n///         The zero sequence.\n///     </para>\n///     <para>\n///         OEIS: https://oeis.org/A000004.\n///     </para>\n/// </summary>\npublic class ZeroSequence : ISequence\n{\n    public IEnumerable<BigInteger> Sequence\n    {\n        get\n        {\n            while (true)\n            {\n                yield return 0;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Shufflers/FisherYatesShuffler.cs",
    "content": "namespace Algorithms.Shufflers;\n\n/// <summary>\n///     Fisher-Yates shuffle is a simple shuffling algorithm,\n///     which is usually used to shuffle a deck of cards.\n/// </summary>\n/// <typeparam name=\"T\">Type array input.</typeparam>\npublic class FisherYatesShuffler<T> : IShuffler<T>\n{\n    /// <summary>\n    ///     Shuffles input array using Fisher-Yates algorithm.\n    ///     The algorithm starts shuffling from the last element\n    ///     and swap elements one by one. We use random index to\n    ///     choose element we use in swap operation.\n    /// </summary>\n    /// <param name=\"array\">Array to shuffle.</param>\n    /// <param name=\"seed\">Random generator seed. Used to repeat the shuffle.</param>\n    public void Shuffle(T[] array, int? seed = null)\n    {\n        var random = seed is null ? new Random() : new Random(seed.Value);\n\n        for (var i = array.Length - 1; i > 0; i--)\n        {\n            var j = random.Next(0, i + 1);\n\n            (array[i], array[j]) = (array[j], array[i]);\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Shufflers/IShuffler.cs",
    "content": "namespace Algorithms.Shufflers;\n\n/// <summary>\n///     Shuffles array.\n/// </summary>\n/// <typeparam name=\"T\">Type of array item.</typeparam>\npublic interface IShuffler<in T>\n{\n    /// <summary>\n    ///     Shuffles array.\n    /// </summary>\n    /// <param name=\"array\">Array to Shuffle.</param>\n    void Shuffle(T[] array, int? seed = null);\n}\n"
  },
  {
    "path": "Algorithms/Shufflers/LINQShuffler.cs",
    "content": "namespace Algorithms.Shufflers;\n\n/// <summary>\n///     LINQ Shuffle is a simple shuffling algorithm,\n///     where the elements within a collection are shuffled using\n///     LINQ queries and lambda expressions in C#.\n/// </summary>\n/// <typeparam name=\"T\">Type array input.</typeparam>\npublic class LinqShuffler<T>\n{\n    /// <summary>\n    /// First, it will generate a random value for each element.\n    /// Next, it will sort the elements based on these generated\n    /// random numbers using OrderBy.\n    /// </summary>\n    /// <param name=\"array\">Array to shuffle.</param>\n    /// <param name=\"seed\">Random generator seed. Used to repeat the shuffle.</param>\n    public T[] Shuffle(T[] array, int? seed = null)\n    {\n        var random = seed is null ? new Random() : new Random(seed.Value);\n        return array.OrderBy(x => random.Next()).ToArray();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Shufflers/NaiveShuffler.cs",
    "content": "namespace Algorithms.Shufflers;\n\n/// <summary>\n///     Naive Shuffle is a simple and incorrect shuffling algorithm\n///     that randomly swaps every element with any other element in the array.\n/// </summary>\n/// <typeparam name=\"T\">Type array input.</typeparam>\npublic class NaiveShuffler<T> : IShuffler<T>\n{\n    /// <summary>\n    /// First, it loop from 0 to n - 1.\n    /// Next, it will randomly pick any j in the array.\n    /// Lastly, it will swap array[i] with array[j].\n    /// </summary>\n    /// <param name=\"array\">Array to shuffle.</param>\n    /// <param name=\"seed\">Random generator seed. Used to repeat the shuffle.</param>\n    public void Shuffle(T[] array, int? seed = null)\n    {\n        var random = seed is null ? new Random() : new Random(seed.Value);\n        for (int i = 0; i < array.Length; i++)\n        {\n            int j = random.Next(array.Length);\n            T temp = array[i];\n            array[i] = array[j];\n            array[j] = temp;\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Shufflers/RecursiveShuffler.cs",
    "content": "namespace Algorithms.Shufflers;\n\n/// <summary>\n///     Recursive Shuffler is a recursive version of\n///     Fisher-Yates shuffle algorithm. This can only be used\n///     for educational purposes due to stack depth limits.\n/// </summary>\n/// <typeparam name=\"T\">Type array input.</typeparam>\npublic class RecursiveShuffler<T> : IShuffler<T>\n{\n    /// <summary>\n    /// This is the public overload method that calls the private overload method.\n    /// </summary>\n    /// <param name=\"array\">Array to shuffle.</param>\n    /// <param name=\"seed\">Random generator seed. Used to repeat the shuffle.</param>\n    public void Shuffle(T[] array, int? seed = null)\n    {\n        Shuffle(array, array.Length - 1, seed);\n    }\n\n    /// <summary>\n    /// First, it will check the length of the array on the base case.\n    /// Next, if there's still items left, it will shuffle the sub-array.\n    /// Lastly, it will randomly select index from 0 to number of items of the array\n    /// then swap the elements array[items] and array[index].\n    /// </summary>\n    /// <param name=\"array\">Array to shuffle.</param>\n    /// <param name=\"items\">Number of items in the array.</param>\n    /// <param name=\"seed\">Random generator seed. Used to repeat the shuffle.</param>\n    private void Shuffle(T[] array, int items, int? seed)\n    {\n        if (items <= 0)\n        {\n            return;\n        }\n\n        Shuffle(array, items - 1, seed);\n        var random = seed is null ? new Random() : new Random(seed.Value);\n        int index = random.Next(items + 1);\n        (array[items], array[index]) = (array[index], array[items]);\n        (array[items], array[index]) = (array[index], array[items]);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/BasicTimSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n/// A basic implementation of the TimSort algorithm for sorting arrays.\n/// </summary>\n/// <typeparam name=\"T\">The type of elements in the array.</typeparam>\n/// <remarks>\n/// Initializes a new instance of the <see cref=\"BasicTimSorter{T}\"/> class.\n/// </remarks>\n/// <param name=\"comparer\">The comparer to use for comparing elements.</param>\npublic class BasicTimSorter<T>(IComparer<T> comparer)\n{\n    private readonly int minRuns = 32;\n    private readonly IComparer<T> comparer = comparer ?? Comparer<T>.Default;\n\n    /// <summary>\n    /// Sorts the specified array using the TimSort algorithm.\n    /// </summary>\n    /// <param name=\"array\">The array to sort.</param>\n    public void Sort(T[] array)\n    {\n        var n = array.Length;\n\n        // Step 1: Sort small pieces of the array using Insertion Sort\n        for (var i = 0; i < n; i += minRuns)\n        {\n            InsertionSort(array, i, Math.Min(i + minRuns - 1, n - 1));\n        }\n\n        // Step 2: Merge sorted runs using Merge Sort\n        for (var size = minRuns; size < n; size *= 2)\n        {\n            for (var left = 0; left < n; left += 2 * size)\n            {\n                var mid = left + size - 1;\n                var right = Math.Min(left + 2 * size - 1, n - 1);\n\n                if (mid < right)\n                {\n                    Merge(array, left, mid, right);\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Sorts a portion of the array using the Insertion Sort algorithm.\n    /// </summary>\n    /// <param name=\"array\">The array to sort.</param>\n    /// <param name=\"left\">The starting index of the portion to sort.</param>\n    /// <param name=\"right\">The ending index of the portion to sort.</param>\n    private void InsertionSort(T[] array, int left, int right)\n    {\n        for (var i = left + 1; i <= right; i++)\n        {\n            var key = array[i];\n            var j = i - 1;\n\n            // Move elements of array[0..i-1], that are greater than key,\n            // to one position ahead of their current position\n            while (j >= left && comparer.Compare(array[j], key) > 0)\n            {\n                array[j + 1] = array[j];\n                j--;\n            }\n\n            array[j + 1] = key;\n        }\n    }\n\n    /// <summary>\n    /// Merges two sorted subarrays into a single sorted subarray.\n    /// </summary>\n    /// <param name=\"array\">The array containing the subarrays to merge.</param>\n    /// <param name=\"left\">The starting index of the first subarray.</param>\n    /// <param name=\"mid\">The ending index of the first subarray.</param>\n    /// <param name=\"right\">The ending index of the second subarray.</param>\n    private void Merge(T[] array, int left, int mid, int right)\n    {\n        // Create segments for left and right subarrays\n        var leftSegment = new ArraySegment<T>(array, left, mid - left + 1);\n        var rightSegment = new ArraySegment<T>(array, mid + 1, right - mid);\n\n        // Convert segments to arrays\n        var leftArray = leftSegment.ToArray();\n        var rightArray = rightSegment.ToArray();\n\n        var i = 0;\n        var j = 0;\n        var k = left;\n\n        // Merge the two subarrays back into the main array\n        while (i < leftArray.Length && j < rightArray.Length)\n        {\n            array[k++] = comparer.Compare(leftArray[i], rightArray[j]) <= 0 ? leftArray[i++] : rightArray[j++];\n        }\n\n        // Copy remaining elements from leftArray, if any\n        while (i < leftArray.Length)\n        {\n            array[k++] = leftArray[i++];\n        }\n\n        // Copy remaining elements from rightArray, if any\n        while (j < rightArray.Length)\n        {\n            array[k++] = rightArray[j++];\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/BinaryInsertionSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Class that implements binary insertion sort algorithm.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class BinaryInsertionSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts array using specified comparer,\n    ///     variant of insertion sort where binary search is used to find place for next element\n    ///     internal, in-place, unstable,\n    ///     time complexity: O(n^2),\n    ///     space complexity: O(1),\n    ///     where n - array length.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        for (var i = 1; i < array.Length; i++)\n        {\n            var target = array[i];\n            var moveIndex = i - 1;\n            var targetInsertLocation = BinarySearch(array, 0, moveIndex, target, comparer);\n            Array.Copy(array, targetInsertLocation, array, targetInsertLocation + 1, i - targetInsertLocation);\n\n            array[targetInsertLocation] = target;\n        }\n    }\n\n    /// <summary>Implementation of Binary Search using an iterative approach.</summary>\n    /// <param name=\"array\">\n    ///     An array of values sorted in ascending order between the index values left and right to search\n    ///     through.\n    /// </param>\n    /// <param name=\"from\">Left index to search from (inclusive).</param>\n    /// <param name=\"to\">Right index to search to (inclusive).</param>\n    /// <param name=\"target\">The value to find placefor in the provided array.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    /// <returns>The index where to insert target value.</returns>\n    private static int BinarySearch(T[] array, int from, int to, T target, IComparer<T> comparer)\n    {\n        var left = from;\n        var right = to;\n        while (right > left)\n        {\n            var middle = (left + right) / 2;\n            var comparisonResult = comparer.Compare(target, array[middle]);\n\n            if (comparisonResult == 0)\n            {\n                return middle + 1;\n            }\n\n            if (comparisonResult > 0)\n            {\n                left = middle + 1;\n            }\n            else\n            {\n                right = middle - 1;\n            }\n        }\n\n        return comparer.Compare(target, array[left]) < 0 ? left : left + 1;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/BogoSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Class that implements bogo sort algorithm.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class BogoSorter<T> : IComparisonSorter<T>\n{\n    private readonly Random random = new();\n\n    /// <summary>\n    ///     Sorts array using specified comparer,\n    ///     randomly shuffles elements until array is sorted,\n    ///     internal, in-place, unstable,\n    ///     worst-case time complexity: unbounded (infinite),\n    ///     average time complexity: O((n+1)!),\n    ///     space complexity: O(n),\n    ///     where n - array length.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        while (!IsSorted(array, comparer))\n        {\n            Shuffle(array);\n        }\n    }\n\n    private bool IsSorted(T[] array, IComparer<T> comparer)\n    {\n        for (var i = 0; i < array.Length - 1; i++)\n        {\n            if (comparer.Compare(array[i], array[i + 1]) > 0)\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    private void Shuffle(T[] array)\n    {\n        var taken = new bool[array.Length];\n        var newArray = new T[array.Length];\n        for (var i = 0; i < array.Length; i++)\n        {\n            int nextPos;\n            do\n            {\n                nextPos = random.Next(0, int.MaxValue) % array.Length;\n            }\n            while (taken[nextPos]);\n\n            taken[nextPos] = true;\n            newArray[nextPos] = array[i];\n        }\n\n        for (var i = 0; i < array.Length; i++)\n        {\n            array[i] = newArray[i];\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/BubbleSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Class that implements bubble sort algorithm.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class BubbleSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts array using specified comparer,\n    ///     internal, in-place, stable,\n    ///     time complexity: O(n^2),\n    ///     space complexity: O(1),\n    ///     where n - array length.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        for (var i = 0; i < array.Length - 1; i++)\n        {\n            var wasChanged = false;\n            for (var j = 0; j < array.Length - i - 1; j++)\n            {\n                if (comparer.Compare(array[j], array[j + 1]) > 0)\n                {\n                    var temp = array[j];\n                    array[j] = array[j + 1];\n                    array[j + 1] = temp;\n                    wasChanged = true;\n                }\n            }\n\n            if (!wasChanged)\n            {\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/CocktailSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Cocktail Sort is a variation of Bubble sort, where Cocktail\n///     Sort traverses through a given array in both directions alternatively.\n/// </summary>\n/// <typeparam name=\"T\">Array input type.</typeparam>\npublic class CocktailSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts array using Cocktail sort algorithm.\n    /// </summary>\n    /// <param name=\"array\">Input array.</param>\n    /// <param name=\"comparer\">Type of comparer for array elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer) => CocktailSort(array, comparer);\n\n    private static void CocktailSort(IList<T> array, IComparer<T> comparer)\n    {\n        var swapped = true;\n\n        var startIndex = 0;\n        var endIndex = array.Count - 1;\n\n        while (swapped)\n        {\n            for (var i = startIndex; i < endIndex; i++)\n            {\n                if (comparer.Compare(array[i], array[i + 1]) != 1)\n                {\n                    continue;\n                }\n\n                var highValue = array[i];\n                array[i] = array[i + 1];\n                array[i + 1] = highValue;\n            }\n\n            endIndex--;\n            swapped = false;\n\n            for (var i = endIndex; i > startIndex; i--)\n            {\n                if (comparer.Compare(array[i], array[i - 1]) != -1)\n                {\n                    continue;\n                }\n\n                var highValue = array[i];\n                array[i] = array[i - 1];\n                array[i - 1] = highValue;\n\n                swapped = true;\n            }\n\n            startIndex++;\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/CombSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Comb sort is a relatively simple sorting algorithm that improves on bubble sort.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class CombSorter<T>(double shrinkFactor = 1.3) : IComparisonSorter<T>\n{\n    private double ShrinkFactor { get; } = shrinkFactor;\n\n    /// <summary>\n    ///     Sorts array using specified comparer,\n    ///     internal, in-place, unstable,\n    ///     worst case performance: O(n^2),\n    ///     best case performance: O(n log(n)),\n    ///     average performance: O(n^2 / 2^p),\n    ///     space complexity: O(1),\n    ///     where n - array length and p - number of increments.\n    ///     See <a href=\"https://en.wikipedia.org/wiki/Comb_sort\">here</a> for more info.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        var gap = array.Length;\n        var sorted = false;\n        while (!sorted)\n        {\n            gap = (int)Math.Floor(gap / ShrinkFactor);\n            if (gap <= 1)\n            {\n                gap = 1;\n                sorted = true;\n            }\n\n            for (var i = 0; i < array.Length - gap; i++)\n            {\n                if (comparer.Compare(array[i], array[i + gap]) > 0)\n                {\n                    (array[i], array[i + gap]) = (array[i + gap], array[i]);\n                    sorted = false;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/CycleSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Cycle sort is an in-place, unstable sorting algorithm,\n///     a comparison sort that is theoretically optimal in terms of the total\n///     number of writes to the original array.\n///     It is based on the idea that the permutation to be sorted can be factored\n///     into cycles, which can individually be rotated to give a sorted result.\n/// </summary>\n/// <typeparam name=\"T\">Type array input.</typeparam>\npublic class CycleSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts input array using Cycle sort.\n    /// </summary>\n    /// <param name=\"array\">Input array.</param>\n    /// <param name=\"comparer\">Integer comparer.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        for (var i = 0; i < array.Length - 1; i++)\n        {\n            MoveCycle(array, i, comparer);\n        }\n    }\n\n    private static void MoveCycle(T[] array, int startingIndex, IComparer<T> comparer)\n    {\n        var item = array[startingIndex];\n        var pos = startingIndex + CountSmallerElements(array, startingIndex + 1, item, comparer);\n\n        if (pos == startingIndex)\n        {\n            return;\n        }\n\n        pos = SkipSameElements(array, pos, item, comparer);\n\n        var temp = array[pos];\n        array[pos] = item;\n        item = temp;\n\n        while (pos != startingIndex)\n        {\n            pos = startingIndex + CountSmallerElements(array, startingIndex + 1, item, comparer);\n            pos = SkipSameElements(array, pos, item, comparer);\n\n            temp = array[pos];\n            array[pos] = item;\n            item = temp;\n        }\n    }\n\n    private static int SkipSameElements(T[] array, int nextIndex, T item, IComparer<T> comparer)\n    {\n        while (comparer.Compare(array[nextIndex], item) == 0)\n        {\n            nextIndex++;\n        }\n\n        return nextIndex;\n    }\n\n    private static int CountSmallerElements(T[] array, int startingIndex, T element, IComparer<T> comparer)\n    {\n        var smallerElements = 0;\n        for (var i = startingIndex; i < array.Length; i++)\n        {\n            if (comparer.Compare(array[i], element) < 0)\n            {\n                smallerElements++;\n            }\n        }\n\n        return smallerElements;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/ExchangeSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Class that implements exchange sort algorithm.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class ExchangeSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts array using specified comparer,\n    ///     internal, in-place, stable,\n    ///     time complexity: O(n^2),\n    ///     space complexity: O(1),\n    ///     where n - array length.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        for (var i = 0; i < array.Length - 1; i++)\n        {\n            for (var j = i + 1; j < array.Length; j++)\n            {\n                if (comparer.Compare(array[i], array[j]) > 0)\n                {\n                    (array[j], array[i]) = (array[i], array[j]);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/GnomeSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Class that implements gnome sort algorithm.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class GnomeSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Moves forward through the array until it founds two elements out of order,\n    ///     then swaps them and move back one position,\n    ///     internal, in-place, stable,\n    ///     time complexity: O(n2),\n    ///     space complexity: O(1).\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        int index = 0;\n\n        while (index < array.Length)\n        {\n            if (index == 0 || comparer.Compare(array[index], array[index - 1]) >= 0)\n            {\n                index++;\n            }\n            else\n            {\n                Swap(array, index, index - 1);\n                index--;\n            }\n        }\n    }\n\n    public void Swap(T[] array, int index1, int index2)\n    {\n        (array[index1], array[index2]) = (array[index2], array[index1]);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/HeapSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Heap sort is a comparison based sorting technique\n///     based on Binary Heap data structure.\n/// </summary>\n/// <typeparam name=\"T\">Input array type.</typeparam>\npublic class HeapSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts input array using heap sort algorithm.\n    /// </summary>\n    /// <param name=\"array\">Input array.</param>\n    /// <param name=\"comparer\">Comparer type for elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer) => HeapSort(array, comparer);\n\n    private static void HeapSort(IList<T> data, IComparer<T> comparer)\n    {\n        var heapSize = data.Count;\n        for (var p = (heapSize - 1) / 2; p >= 0; p--)\n        {\n            MakeHeap(data, heapSize, p, comparer);\n        }\n\n        for (var i = data.Count - 1; i > 0; i--)\n        {\n            var temp = data[i];\n            data[i] = data[0];\n            data[0] = temp;\n\n            heapSize--;\n            MakeHeap(data, heapSize, 0, comparer);\n        }\n    }\n\n    private static void MakeHeap(IList<T> input, int heapSize, int index, IComparer<T> comparer)\n    {\n        var rIndex = index;\n\n        while (true)\n        {\n            var left = (rIndex + 1) * 2 - 1;\n            var right = (rIndex + 1) * 2;\n            var largest = left < heapSize && comparer.Compare(input[left], input[rIndex]) == 1 ? left : rIndex;\n\n            // finds the index of the largest\n            if (right < heapSize && comparer.Compare(input[right], input[largest]) == 1)\n            {\n                largest = right;\n            }\n\n            if (largest == rIndex)\n            {\n                return;\n            }\n\n            // process of reheaping / swapping\n            var temp = input[rIndex];\n            input[rIndex] = input[largest];\n            input[largest] = temp;\n\n            rIndex = largest;\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/IComparisonSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Sorts array in ascending order using comparison sort.\n/// </summary>\n/// <typeparam name=\"T\">Type of array item.</typeparam>\npublic interface IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts array in ascending order.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Comparer to compare items of <paramref name=\"array\" />.</param>\n    void Sort(T[] array, IComparer<T> comparer);\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/InsertionSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Class that implements insertion sort algorithm.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class InsertionSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts array using specified comparer,\n    ///     internal, in-place, stable,\n    ///     time complexity: O(n^2),\n    ///     space complexity: O(1),\n    ///     where n - array length.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        for (var i = 1; i < array.Length; i++)\n        {\n            for (var j = i; j > 0 && comparer.Compare(array[j], array[j - 1]) < 0; j--)\n            {\n                var temp = array[j - 1];\n                array[j - 1] = array[j];\n                array[j] = temp;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/MedianOfThreeQuickSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Sorts arrays using quicksort (selecting median of three as a pivot).\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic sealed class MedianOfThreeQuickSorter<T> : QuickSorter<T>\n{\n    protected override T SelectPivot(T[] array, IComparer<T> comparer, int left, int right)\n    {\n        var leftPoint = array[left];\n        var middlePoint = array[left + (right - left) / 2];\n        var rightPoint = array[right];\n\n        return FindMedian(comparer, leftPoint, middlePoint, rightPoint);\n    }\n\n    private static T FindMedian(IComparer<T> comparer, T a, T b, T c)\n    {\n        if (comparer.Compare(a, b) <= 0)\n        {\n            // a <= b <= c\n            if (comparer.Compare(b, c) <= 0)\n            {\n                return b;\n            }\n\n            // a <= c < b\n            if (comparer.Compare(a, c) <= 0)\n            {\n                return c;\n            }\n\n            // c < a <= b\n            return a;\n        }\n\n        // a > b >= c\n        if (comparer.Compare(b, c) >= 0)\n        {\n            return b;\n        }\n\n        // a >= c > b\n        if (comparer.Compare(a, c) >= 0)\n        {\n            return c;\n        }\n\n        // c > a > b\n        return a;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/MergeSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Divide and Conquer algorithm, which splits\n///     array in two halves, calls itself for the two\n///     halves and then merges the two sorted halves.\n/// </summary>\n/// <typeparam name=\"T\">Type of array elements.</typeparam>\npublic class MergeSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts array using merge sort algorithm,\n    ///     originally designed as external sorting algorithm,\n    ///     internal, stable,\n    ///     time complexity: O(n log(n)),\n    ///     space complexity: O(n),\n    ///     where n - array length.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Comparer to compare elements of <paramref name=\"array\" />.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        if (array.Length <= 1)\n        {\n            return;\n        }\n\n        var (left, right) = Split(array);\n        Sort(left, comparer);\n        Sort(right, comparer);\n        Merge(array, left, right, comparer);\n    }\n\n    private static void Merge(T[] array, T[] left, T[] right, IComparer<T> comparer)\n    {\n        var mainIndex = 0;\n        var leftIndex = 0;\n        var rightIndex = 0;\n\n        while (leftIndex < left.Length && rightIndex < right.Length)\n        {\n            var compResult = comparer.Compare(left[leftIndex], right[rightIndex]);\n            array[mainIndex++] = compResult <= 0 ? left[leftIndex++] : right[rightIndex++];\n        }\n\n        while (leftIndex < left.Length)\n        {\n            array[mainIndex++] = left[leftIndex++];\n        }\n\n        while (rightIndex < right.Length)\n        {\n            array[mainIndex++] = right[rightIndex++];\n        }\n    }\n\n    private static (T[] Left, T[] Right) Split(T[] array)\n    {\n        var mid = array.Length / 2;\n        return (array.Take(mid).ToArray(), array.Skip(mid).ToArray());\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/MiddlePointQuickSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Sorts arrays using quicksort (selecting middle point as a pivot).\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic sealed class MiddlePointQuickSorter<T> : QuickSorter<T>\n{\n    protected override T SelectPivot(T[] array, IComparer<T> comparer, int left, int right) =>\n        array[left + (right - left) / 2];\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/PancakeSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Class that implements pancake sort algorithm.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class PancakeSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts array using specified comparer,\n    ///     internal, in-place, stable,\n    ///     time complexity: O(n^2),\n    ///     space complexity: O(1),\n    ///     where n - array length.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        var n = array.Length;\n\n        // Start from the complete array and one by one\n        // reduce current size by one\n        for (var currSize = n; currSize > 1; --currSize)\n        {\n            // Find index of the maximum element in\n            // array[0..curr_size-1]\n            var mi = FindMax(array, currSize, comparer);\n\n            // Move the maximum element to end of current array\n            // if it's not already at  the end\n            if (mi != currSize - 1)\n            {\n                // To move to the end, first move maximum\n                // number to beginning\n                Flip(array, mi);\n\n                // Now move the maximum number to end by\n                // reversing current array\n                Flip(array, currSize - 1);\n            }\n        }\n    }\n\n    // Reverses array[0..i]\n    private void Flip(T[] array, int i)\n    {\n        T temp;\n        var start = 0;\n        while (start < i)\n        {\n            temp = array[start];\n            array[start] = array[i];\n            array[i] = temp;\n            start++;\n            i--;\n        }\n    }\n\n    // Returns index of the maximum element\n    // in array[0..n-1]\n    private int FindMax(T[] array, int n, IComparer<T> comparer)\n    {\n        var mi = 0;\n        for (var i = 0; i < n; i++)\n        {\n            if (comparer.Compare(array[i], array[mi]) == 1)\n            {\n                mi = i;\n            }\n        }\n\n        return mi;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/QuickSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Sorts arrays using quicksort.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic abstract class QuickSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts array using Hoare partition scheme,\n    ///     internal, in-place,\n    ///     time complexity average: O(n log(n)),\n    ///     time complexity worst: O(n^2),\n    ///     space complexity: O(log(n)),\n    ///     where n - array length.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer) => Sort(array, comparer, 0, array.Length - 1);\n\n    protected abstract T SelectPivot(T[] array, IComparer<T> comparer, int left, int right);\n\n    private void Sort(T[] array, IComparer<T> comparer, int left, int right)\n    {\n        if (left >= right)\n        {\n            return;\n        }\n\n        var p = Partition(array, comparer, left, right);\n        Sort(array, comparer, left, p);\n        Sort(array, comparer, p + 1, right);\n    }\n\n    private int Partition(T[] array, IComparer<T> comparer, int left, int right)\n    {\n        var pivot = SelectPivot(array, comparer, left, right);\n        var nleft = left;\n        var nright = right;\n        while (true)\n        {\n            while (comparer.Compare(array[nleft], pivot) < 0)\n            {\n                nleft++;\n            }\n\n            while (comparer.Compare(array[nright], pivot) > 0)\n            {\n                nright--;\n            }\n\n            if (nleft >= nright)\n            {\n                return nright;\n            }\n\n            var t = array[nleft];\n            array[nleft] = array[nright];\n            array[nright] = t;\n\n            nleft++;\n            nright--;\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/RandomPivotQuickSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Sorts arrays using quicksort (selecting random point as a pivot).\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic sealed class RandomPivotQuickSorter<T> : QuickSorter<T>\n{\n    private readonly Random random = new();\n\n    protected override T SelectPivot(T[] array, IComparer<T> comparer, int left, int right) =>\n        array[random.Next(left, right + 1)];\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/SelectionSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Class that implements selection sort algorithm.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class SelectionSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts array using specified comparer,\n    ///     internal, in-place, stable,\n    ///     time complexity: O(n^2),\n    ///     space complexity: O(1),\n    ///     where n - array length.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        for (var i = 0; i < array.Length - 1; i++)\n        {\n            var jmin = i;\n            for (var j = i + 1; j < array.Length; j++)\n            {\n                if (comparer.Compare(array[jmin], array[j]) > 0)\n                {\n                    jmin = j;\n                }\n            }\n\n            var t = array[i];\n            array[i] = array[jmin];\n            array[jmin] = t;\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/ShellSorter.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     Class that implements Shell sort algorithm.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class ShellSorter<T> : IComparisonSorter<T>\n{\n    /// <summary>\n    ///     Sorts array using specified comparer,\n    ///     based on bubble sort,\n    ///     internal, in-place, unstable,\n    ///     worst-case time complexity: O(n^2),\n    ///     space complexity: O(1),\n    ///     where n - array length.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        for (var step = array.Length / 2; step > 0; step /= 2)\n        {\n            for (var i = 0; i < step; i++)\n            {\n                GappedBubbleSort(array, comparer, i, step);\n            }\n        }\n    }\n\n    private static void GappedBubbleSort(T[] array, IComparer<T> comparer, int start, int step)\n    {\n        for (var j = start; j < array.Length - step; j += step)\n        {\n            var wasChanged = false;\n            for (var k = start; k < array.Length - j - step; k += step)\n            {\n                if (comparer.Compare(array[k], array[k + step]) > 0)\n                {\n                    var temp = array[k];\n                    array[k] = array[k + step];\n                    array[k + step] = temp;\n                    wasChanged = true;\n                }\n            }\n\n            if (!wasChanged)\n            {\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/TimSorter.cs",
    "content": "using Algorithms.Sorters.Utils;\n\nnamespace Algorithms.Sorters.Comparison;\n\n/// <summary>\n///     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.\n///     It was originally implemented by Tim Peters in 2002 for use in the Python programming language.\n///\n///     This class is based on a Java interpretation of Tim Peter's original work.\n///     Java class is viewable here:\n///     https://web.archive.org/web/20190119032242/http://cr.openjdk.java.net:80/~martin/webrevs/openjdk7/timsort/raw_files/new/src/share/classes/java/util/TimSort.java\n///\n///     Tim Peters's list sort for Python, is described in detail here:\n///     http://svn.python.org/projects/python/trunk/Objects/listsort.txt\n///\n///     Tim's C code may be found here: http://svn.python.org/projects/python/trunk/Objects/listobject.c\n///\n///     The underlying techniques are described in this paper (and may have even earlier origins):\n///     \"Optimistic Sorting and Information Theoretic Complexity\"\n///     Peter McIlroy\n///     SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms),\n///     pp 467-474, Austin, Texas, 25-27 January 1993.\n/// </summary>\n/// <typeparam name=\"T\">Type of array element.</typeparam>\npublic class TimSorter<T> : IComparisonSorter<T>\n{\n    private readonly int minMerge;\n    private readonly int initMinGallop;\n\n    private readonly int[] runBase;\n    private readonly int[] runLengths;\n\n    private int minGallop;\n    private int stackSize;\n\n    private IComparer<T> comparer = default!;\n\n    /// <summary>\n    /// Private class for handling gallop merges, allows for tracking array indexes and wins.\n    /// </summary>\n    /// <typeparam name=\"Tc\">Type of array element.</typeparam>\n    private class TimChunk<Tc>\n    {\n        public Tc[] Array { get; set; } = default!;\n\n        public int Index { get; set; }\n\n        public int Remaining { get; set; }\n\n        public int Wins { get; set; }\n    }\n\n    public TimSorter(TimSorterSettings settings, IComparer<T> comparer)\n    {\n        initMinGallop = minGallop;\n\n        // Using the worst case stack size from the C implementation.\n        // Based on the findings in the original listsort.txt:\n        // ... the stack can never grow larger than about log_base_phi(N) entries, where phi = (1 + sqrt(5)) / 2 ~= 1.618.\n        // Thus a small # of stack slots suffice for very large arrays ...\n        runBase = new int[85];\n        runLengths = new int[85];\n\n        stackSize = 0;\n\n        minGallop = settings.MinGallop;\n        minMerge = settings.MinMerge;\n\n        this.comparer = comparer ?? Comparer<T>.Default;\n    }\n\n    /// <summary>\n    ///     Sorts array using specified comparer\n    ///     worst case performance: O(n log(n)),\n    ///     best case performance:  O(n),\n    ///     See <a href=\"https://en.wikipedia.org/wiki/Timsort\">here</a> for more info.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"comparer\">Compares elements.</param>\n    public void Sort(T[] array, IComparer<T> comparer)\n    {\n        ArgumentNullException.ThrowIfNull(array);\n\n        var start = 0;\n        var remaining = array.Length;\n\n        if (remaining < minMerge)\n        {\n            if (remaining < 2)\n            {\n                // Arrays of size 0 or 1 are always sorted.\n                return;\n            }\n\n            // Don't need to merge, just binary sort\n            BinarySort(array, start, remaining, start);\n            return;\n        }\n\n        var minRun = MinRunLength(remaining, minMerge);\n\n        do\n        {\n            // Identify next run\n            var runLen = CountRunAndMakeAscending(array, start);\n\n            // If the run is too short extend to Min(MIN_RUN, remaining)\n            if (runLen < minRun)\n            {\n                var force = Math.Min(minRun, remaining);\n                BinarySort(array, start, start + force, start + runLen);\n                runLen = force;\n            }\n\n            runBase[stackSize] = start;\n            runLengths[stackSize] = runLen;\n            stackSize++;\n\n            MergeCollapse(array);\n\n            start += runLen;\n            remaining -= runLen;\n        }\n        while (remaining != 0);\n\n        MergeForceCollapse(array);\n    }\n\n    /// <summary>\n    /// Returns the minimum acceptable run length for an array of the specified\n    /// length.Natural runs shorter than this will be extended.\n    ///\n    /// Computation is:\n    ///   If total less than minRun, return n (it's too small to bother with fancy stuff).\n    ///   Else if total is an exact power of 2, return minRun/2.\n    ///   Else return an int k, where <![CDATA[minRun/2 <= k <= minRun]]>, such that total/k\n    ///     is close to, but strictly less than, an exact power of 2.\n    /// </summary>\n    /// <param name=\"total\">Total length remaining to sort.</param>\n    /// <returns>Minimum run length to be merged.</returns>\n    private static int MinRunLength(int total, int minRun)\n    {\n        var r = 0;\n        while (total >= minRun)\n        {\n            r |= total & 1;\n            total >>= 1;\n        }\n\n        return total + r;\n    }\n\n    /// <summary>\n    /// Reverse the specified range of the specified array.\n    /// </summary>\n    /// <param name=\"array\">the array in which a range is to be reversed.</param>\n    /// <param name=\"start\">the index of the first element in the range to be reversed.</param>\n    /// <param name=\"end\">the index after the last element in the range to be reversed.</param>\n    private static void ReverseRange(T[] array, int start, int end)\n    {\n        end--;\n        while (start < end)\n        {\n            var t = array[start];\n            array[start++] = array[end];\n            array[end--] = t;\n        }\n    }\n\n    /// <summary>\n    /// Check the chunks before getting in to a merge to make sure there's something to actually do.\n    /// </summary>\n    /// <param name=\"left\">TimChunk of the left hand side.</param>\n    /// <param name=\"right\">TimChunk of the right hand side.</param>\n    /// <param name=\"dest\">The current target point for the remaining values.</param>\n    /// <returns>If a merge is required.</returns>\n    private static bool NeedsMerge(TimChunk<T> left, TimChunk<T> right, ref int dest)\n    {\n        right.Array[dest++] = right.Array[right.Index++];\n        if (--right.Remaining == 0)\n        {\n            Array.Copy(left.Array, left.Index, right.Array, dest, left.Remaining);\n            return false;\n        }\n\n        if (left.Remaining == 1)\n        {\n            Array.Copy(right.Array, right.Index, right.Array, dest, right.Remaining);\n            right.Array[dest + right.Remaining] = left.Array[left.Index];\n            return false;\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    /// Moves over the last parts of the chunks.\n    /// </summary>\n    /// <param name=\"left\">TimChunk of the left hand side.</param>\n    /// <param name=\"right\">TimChunk of the right hand side.</param>\n    /// <param name=\"dest\">The current target point for the remaining values.</param>\n    private static void FinalizeMerge(TimChunk<T> left, TimChunk<T> right, int dest)\n    {\n        if (left.Remaining == 1)\n        {\n            Array.Copy(right.Array, right.Index, right.Array, dest, right.Remaining);\n            right.Array[dest + right.Remaining] = left.Array[left.Index];\n        }\n        else if (left.Remaining == 0)\n        {\n            throw new ArgumentException(\"Comparison method violates its general contract!\");\n        }\n        else\n        {\n            Array.Copy(left.Array, left.Index, right.Array, dest, left.Remaining);\n        }\n    }\n\n    /// <summary>\n    /// Returns the length of the run beginning at the specified position in\n    /// the specified array and reverses the run if it is descending (ensuring\n    /// that the run will always be ascending when the method returns).\n    ///\n    /// A run is the longest ascending sequence with:\n    ///\n    ///    <![CDATA[a[lo] <= a[lo + 1] <= a[lo + 2] <= ...]]>\n    ///\n    /// or the longest descending sequence with:\n    ///\n    ///    <![CDATA[a[lo] >  a[lo + 1] >  a[lo + 2] >  ...]]>\n    ///\n    /// For its intended use in a stable mergesort, the strictness of the\n    /// definition of \"descending\" is needed so that the call can safely\n    /// reverse a descending sequence without violating stability.\n    /// </summary>\n    /// <param name=\"array\">the array in which a run is to be counted and possibly reversed.</param>\n    /// <param name=\"start\">index of the first element in the run.</param>\n    /// <returns>the length of the run beginning at the specified position in the specified array.</returns>\n    private int CountRunAndMakeAscending(T[] array, int start)\n    {\n        var runHi = start + 1;\n        if (runHi == array.Length)\n        {\n            return 1;\n        }\n\n        // Find end of run, and reverse range if descending\n        if (comparer.Compare(array[runHi++], array[start]) < 0)\n        { // Descending\n            while (runHi < array.Length && comparer.Compare(array[runHi], array[runHi - 1]) < 0)\n            {\n                runHi++;\n            }\n\n            ReverseRange(array, start, runHi);\n        }\n        else\n        { // Ascending\n            while (runHi < array.Length && comparer.Compare(array[runHi], array[runHi - 1]) >= 0)\n            {\n                runHi++;\n            }\n        }\n\n        return runHi - start;\n    }\n\n    /// <summary>\n    /// Sorts the specified portion of the specified array using a binary\n    /// insertion sort. It requires O(n log n) compares, but O(n^2) data movement.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    /// <param name=\"start\">The index of the first element in the range to be sorted.</param>\n    /// <param name=\"end\">The index after the last element in the range to be sorted.</param>\n    /// <param name=\"first\">The index of the first element in the range that is not already known to be sorted, must be between start and end.</param>\n    private void BinarySort(T[] array, int start, int end, int first)\n    {\n        if (first >= end || first <= start)\n        {\n            first = start + 1;\n        }\n\n        for (; first < end; first++)\n        {\n            var target = array[first];\n            var targetInsertLocation = BinarySearch(array, start, first - 1, target);\n            Array.Copy(array, targetInsertLocation, array, targetInsertLocation + 1, first - targetInsertLocation);\n\n            array[targetInsertLocation] = target;\n        }\n    }\n\n    private int BinarySearch(T[] array, int left, int right, T target)\n    {\n        while (left < right)\n        {\n            var mid = (left + right) >> 1;\n            if (comparer.Compare(target, array[mid]) < 0)\n            {\n                right = mid;\n            }\n            else\n            {\n                left = mid + 1;\n            }\n        }\n\n        return comparer.Compare(target, array[left]) < 0\n            ? left\n            : left + 1;\n    }\n\n    private void MergeCollapse(T[] array)\n    {\n        while (stackSize > 1)\n        {\n            var n = stackSize - 2;\n            if (n > 0 && runLengths[n - 1] <= runLengths[n] + runLengths[n + 1])\n            {\n                if (runLengths[n - 1] < runLengths[n + 1])\n                {\n                    n--;\n                }\n\n                MergeAt(array, n);\n            }\n            else if (runLengths[n] <= runLengths[n + 1])\n            {\n                MergeAt(array, n);\n            }\n            else\n            {\n                break;\n            }\n        }\n    }\n\n    private void MergeForceCollapse(T[] array)\n    {\n        while (stackSize > 1)\n        {\n            var n = stackSize - 2;\n            if (n > 0 && runLengths[n - 1] < runLengths[n + 1])\n            {\n                n--;\n            }\n\n            MergeAt(array, n);\n        }\n    }\n\n    private void MergeAt(T[] array, int index)\n    {\n        var baseA = runBase[index];\n        var lenA = runLengths[index];\n        var baseB = runBase[index + 1];\n        var lenB = runLengths[index + 1];\n\n        runLengths[index] = lenA + lenB;\n\n        if (index == stackSize - 3)\n        {\n            runBase[index + 1] = runBase[index + 2];\n            runLengths[index + 1] = runLengths[index + 2];\n        }\n\n        stackSize--;\n\n        var k = GallopingStrategy<T>.GallopRight(array, array[baseB], baseA, lenA, comparer);\n\n        baseA += k;\n        lenA -= k;\n\n        if (lenA <= 0)\n        {\n            return;\n        }\n\n        lenB = GallopingStrategy<T>.GallopLeft(array, array[baseA + lenA - 1], baseB, lenB, comparer);\n\n        if (lenB <= 0)\n        {\n            return;\n        }\n\n        Merge(array, baseA, lenA, baseB, lenB);\n    }\n\n    private void Merge(T[] array, int baseA, int lenA, int baseB, int lenB)\n    {\n        var endA = baseA + lenA;\n        var dest = baseA;\n\n        TimChunk<T> left = new()\n        {\n            Array = array[baseA..endA],\n            Remaining = lenA,\n        };\n\n        TimChunk<T> right = new()\n        {\n            Array = array,\n            Index = baseB,\n            Remaining = lenB,\n        };\n\n        // Move first element of the right chunk and deal with degenerate cases.\n        if (!TimSorter<T>.NeedsMerge(left, right, ref dest))\n        {\n            // One of the chunks had 0-1 items in it, so no need to merge anything.\n            return;\n        }\n\n        var gallop = minGallop;\n\n        while (RunMerge(left, right, ref dest, ref gallop))\n        {\n            // Penalize for leaving gallop mode\n            gallop = gallop > 0\n                ? gallop + 2\n                : 2;\n        }\n\n        minGallop = gallop >= 1\n            ? gallop\n            : 1;\n\n        FinalizeMerge(left, right, dest);\n    }\n\n    private bool RunMerge(TimChunk<T> left, TimChunk<T> right, ref int dest, ref int gallop)\n    {\n        // Reset the number of times in row a run wins.\n        left.Wins = 0;\n        right.Wins = 0;\n\n        // Run a stable merge sort until (if ever) one run starts winning consistently.\n        if (StableMerge(left, right, ref dest, gallop))\n        {\n            // Stable merge sort completed with no viable gallops, time to exit.\n            return false;\n        }\n\n        // One run is winning so consistently that galloping may be a huge win.\n        // So try that, and continue galloping until (if ever) neither run appears to be winning consistently anymore.\n        do\n        {\n            if (GallopMerge(left, right, ref dest))\n            {\n                // Galloped all the way to the end, merge is complete.\n                return false;\n            }\n\n            // We had a bit of a run, so make it easier to get started again.\n            gallop--;\n        }\n        while (left.Wins >= initMinGallop || right.Wins >= initMinGallop);\n\n        return true;\n    }\n\n    private bool StableMerge(TimChunk<T> left, TimChunk<T> right, ref int dest, int gallop)\n    {\n        do\n        {\n            if (comparer.Compare(right.Array[right.Index], left.Array[left.Index]) < 0)\n            {\n                right.Array[dest++] = right.Array[right.Index++];\n                right.Wins++;\n                left.Wins = 0;\n                if (--right.Remaining == 0)\n                {\n                    return true;\n                }\n            }\n            else\n            {\n                right.Array[dest++] = left.Array[left.Index++];\n                left.Wins++;\n                right.Wins = 0;\n                if (--left.Remaining == 1)\n                {\n                    return true;\n                }\n            }\n        }\n        while ((left.Wins | right.Wins) < gallop);\n\n        return false;\n    }\n\n    private bool GallopMerge(TimChunk<T> left, TimChunk<T> right, ref int dest)\n    {\n        left.Wins = GallopingStrategy<T>.GallopRight(left.Array, right.Array[right.Index], left.Index, left.Remaining, comparer);\n        if (left.Wins != 0)\n        {\n            Array.Copy(left.Array, left.Index, right.Array, dest, left.Wins);\n            dest += left.Wins;\n            left.Index += left.Wins;\n            left.Remaining -= left.Wins;\n            if (left.Remaining <= 1)\n            {\n                return true;\n            }\n        }\n\n        right.Array[dest++] = right.Array[right.Index++];\n        if (--right.Remaining == 0)\n        {\n            return true;\n        }\n\n        right.Wins = GallopingStrategy<T>.GallopLeft(right.Array, left.Array[left.Index], right.Index, right.Remaining, comparer);\n        if (right.Wins != 0)\n        {\n            Array.Copy(right.Array, right.Index, right.Array, dest, right.Wins);\n            dest += right.Wins;\n            right.Index += right.Wins;\n            right.Remaining -= right.Wins;\n            if (right.Remaining == 0)\n            {\n                return true;\n            }\n        }\n\n        right.Array[dest++] = left.Array[left.Index++];\n        if (--left.Remaining == 1)\n        {\n            return true;\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Comparison/TimSorterSettings.cs",
    "content": "namespace Algorithms.Sorters.Comparison;\n\npublic class TimSorterSettings(int minMerge = 32, int minGallop = 7)\n{\n    public int MinMerge { get; } = minMerge;\n\n    public int MinGallop { get; } = minGallop;\n}\n"
  },
  {
    "path": "Algorithms/Sorters/External/ExternalMergeSorter.cs",
    "content": "namespace Algorithms.Sorters.External;\n\npublic class ExternalMergeSorter<T> : IExternalSorter<T>\n{\n    public void Sort(\n        ISequentialStorage<T> mainMemory,\n        ISequentialStorage<T> temporaryMemory,\n        IComparer<T> comparer)\n    {\n        var originalSource = mainMemory;\n        var source = mainMemory;\n        var temp = temporaryMemory;\n        var totalLength = mainMemory.Length;\n        for (var stripLength = 1L; stripLength < totalLength; stripLength *= 2)\n        {\n            using var left = source.GetReader();\n            using var right = source.GetReader();\n            using var output = temp.GetWriter();\n\n            for (var i = 0L; i < stripLength; i++)\n            {\n                right.Read();\n            }\n\n            Merge(left, right, output, stripLength, Math.Min(stripLength, totalLength - stripLength), comparer);\n            var step = 2 * stripLength;\n            long rightStripStart;\n            for (rightStripStart = stripLength + step; rightStripStart < mainMemory.Length; rightStripStart += step)\n            {\n                for (var i = 0L; i < stripLength; i++)\n                {\n                    left.Read();\n                    right.Read();\n                }\n\n                Merge(\n                    left,\n                    right,\n                    output,\n                    stripLength,\n                    Math.Min(stripLength, totalLength - rightStripStart),\n                    comparer);\n            }\n\n            for (var i = 0L; i < totalLength + stripLength - rightStripStart; i++)\n            {\n                output.Write(right.Read());\n            }\n\n            (source, temp) = (temp, source);\n        }\n\n        if (source == originalSource)\n        {\n            return;\n        }\n\n        using var sorted = source.GetReader();\n        using var dest = originalSource.GetWriter();\n        for (var i = 0; i < totalLength; i++)\n        {\n            dest.Write(sorted.Read());\n        }\n    }\n\n    private static void Merge(\n        ISequentialStorageReader<T> left,\n        ISequentialStorageReader<T> right,\n        ISequentialStorageWriter<T> output,\n        long leftLength,\n        long rightLength,\n        IComparer<T> comparer)\n    {\n        var leftIndex = 0L;\n        var rightIndex = 0L;\n\n        var l = left.Read();\n        var r = right.Read();\n        while (true)\n        {\n            if (comparer.Compare(l, r) < 0)\n            {\n                output.Write(l);\n                leftIndex++;\n                if (leftIndex == leftLength)\n                {\n                    break;\n                }\n\n                l = left.Read();\n            }\n            else\n            {\n                output.Write(r);\n                rightIndex++;\n                if (rightIndex == rightLength)\n                {\n                    break;\n                }\n\n                r = right.Read();\n            }\n        }\n\n        if (leftIndex < leftLength)\n        {\n            output.Write(l);\n            Copy(left, output, leftLength - leftIndex - 1);\n        }\n\n        if (rightIndex < rightLength)\n        {\n            output.Write(r);\n            Copy(right, output, rightLength - rightIndex - 1);\n        }\n    }\n\n    private static void Copy(ISequentialStorageReader<T> from, ISequentialStorageWriter<T> to, long count)\n    {\n        for (var i = 0; i < count; i++)\n        {\n            to.Write(from.Read());\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/External/IExternalSorter.cs",
    "content": "namespace Algorithms.Sorters.External;\n\npublic interface IExternalSorter<T>\n{\n    /// <summary>\n    ///     Sorts elements in sequential storage in ascending order.\n    /// </summary>\n    /// <param name=\"mainMemory\">Memory that contains array to sort and will contain the result.</param>\n    /// <param name=\"temporaryMemory\">Temporary memory for working purposes.</param>\n    void Sort(ISequentialStorage<T> mainMemory, ISequentialStorage<T> temporaryMemory, IComparer<T> comparer);\n}\n"
  },
  {
    "path": "Algorithms/Sorters/External/ISequentialStorage.cs",
    "content": "namespace Algorithms.Sorters.External;\n\npublic interface ISequentialStorage<T>\n{\n    public int Length { get; }\n\n    ISequentialStorageReader<T> GetReader();\n\n    ISequentialStorageWriter<T> GetWriter();\n}\n"
  },
  {
    "path": "Algorithms/Sorters/External/ISequentialStorageReader.cs",
    "content": "namespace Algorithms.Sorters.External;\n\npublic interface ISequentialStorageReader<out T> : IDisposable\n{\n    T Read();\n}\n"
  },
  {
    "path": "Algorithms/Sorters/External/ISequentialStorageWriter.cs",
    "content": "namespace Algorithms.Sorters.External;\n\npublic interface ISequentialStorageWriter<in T> : IDisposable\n{\n    void Write(T value);\n}\n"
  },
  {
    "path": "Algorithms/Sorters/External/Storages/IntFileStorage.cs",
    "content": "using System.IO;\n\nnamespace Algorithms.Sorters.External.Storages;\n\npublic class IntFileStorage(string filename, int length) : ISequentialStorage<int>\n{\n    private readonly string filename = filename;\n\n    public int Length { get; } = length;\n\n    public ISequentialStorageReader<int> GetReader() => new FileReader(filename);\n\n    public ISequentialStorageWriter<int> GetWriter() => new FileWriter(filename);\n\n    private class FileReader(string filename) : ISequentialStorageReader<int>\n    {\n        private readonly BinaryReader reader = new BinaryReader(File.OpenRead(filename));\n\n        public void Dispose() => reader.Dispose();\n\n        public int Read() => reader.ReadInt32();\n    }\n\n    private class FileWriter(string filename) : ISequentialStorageWriter<int>\n    {\n        private readonly BinaryWriter writer = new BinaryWriter(File.OpenWrite(filename));\n\n        public void Write(int value) => writer.Write(value);\n\n        public void Dispose() => writer.Dispose();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/External/Storages/IntInMemoryStorage.cs",
    "content": "namespace Algorithms.Sorters.External.Storages;\n\npublic class IntInMemoryStorage(int[] array) : ISequentialStorage<int>\n{\n    private readonly int[] storage = array;\n\n    public int Length => storage.Length;\n\n    public ISequentialStorageReader<int> GetReader() => new InMemoryReader(storage);\n\n    public ISequentialStorageWriter<int> GetWriter() => new InMemoryWriter(storage);\n\n    private class InMemoryReader(int[] storage) : ISequentialStorageReader<int>\n    {\n        private readonly int[] storage = storage;\n        private int offset;\n\n        public void Dispose()\n        {\n            // Nothing to dispose here\n        }\n\n        public int Read() => storage[offset++];\n    }\n\n    private class InMemoryWriter(int[] storage) : ISequentialStorageWriter<int>\n    {\n        private readonly int[] storage = storage;\n        private int offset;\n\n        public void Write(int value) => storage[offset++] = value;\n\n        public void Dispose()\n        {\n            // Nothing to dispose here\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Integer/BucketSorter.cs",
    "content": "namespace Algorithms.Sorters.Integer;\n\n/// <summary>\n///     Class that implements bucket sort algorithm.\n/// </summary>\npublic class BucketSorter : IIntegerSorter\n{\n    private const int NumOfDigitsInBase10 = 10;\n\n    /// <summary>\n    ///     Sorts array elements using BucketSort Algorithm.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    public void Sort(int[] array)\n    {\n        if (array.Length <= 1)\n        {\n            return;\n        }\n\n        // store maximum number of digits in numbers to sort\n        var totalDigits = NumberOfDigits(array);\n\n        // bucket array where numbers will be placed\n        var buckets = new int[NumOfDigitsInBase10, array.Length + 1];\n\n        // go through all digit places and sort each number\n        // according to digit place value\n        for (var pass = 1; pass <= totalDigits; pass++)\n        {\n            DistributeElements(array, buckets, pass); // distribution pass\n            CollectElements(array, buckets); // gathering pass\n\n            if (pass != totalDigits)\n            {\n                EmptyBucket(buckets); // set size of buckets to 0\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Determines the number of digits in the largest number.\n    /// </summary>\n    /// <param name=\"array\">Input array.</param>\n    /// <returns>Number of digits.</returns>\n    private static int NumberOfDigits(IEnumerable<int> array) => (int)Math.Floor(Math.Log10(array.Max()) + 1);\n\n    /// <summary>\n    ///     To distribute elements into buckets based on specified digit.\n    /// </summary>\n    /// <param name=\"data\">Input array.</param>\n    /// <param name=\"buckets\">Array of buckets.</param>\n    /// <param name=\"digit\">Digit.</param>\n    private static void DistributeElements(IEnumerable<int> data, int[,] buckets, int digit)\n    {\n        // determine the divisor used to get specific digit\n        var divisor = (int)Math.Pow(10, digit);\n\n        foreach (var element in data)\n        {\n            // bucketNumber example for hundreds digit:\n            // ( 1234 % 1000 ) / 100 --> 2\n            var bucketNumber = NumOfDigitsInBase10 * (element % divisor) / divisor;\n\n            // retrieve value in pail[ bucketNumber , 0 ] to\n            // determine the location in row to store element\n            var elementNumber = ++buckets[bucketNumber, 0]; // location in bucket to place element\n            buckets[bucketNumber, elementNumber] = element;\n        }\n    }\n\n    /// <summary>\n    ///     Return elements to original array.\n    /// </summary>\n    /// <param name=\"data\">Input array.</param>\n    /// <param name=\"buckets\">Array of buckets.</param>\n    private static void CollectElements(IList<int> data, int[,] buckets)\n    {\n        var subscript = 0; // initialize location in data\n\n        // loop over buckets\n        for (var i = 0; i < NumOfDigitsInBase10; i++)\n        {\n            // loop over elements in each bucket\n            for (var j = 1; j <= buckets[i, 0]; j++)\n            {\n                data[subscript++] = buckets[i, j]; // add element to array\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Sets size of all buckets to zero.\n    /// </summary>\n    /// <param name=\"buckets\">Array of buckets.</param>\n    private static void EmptyBucket(int[,] buckets)\n    {\n        for (var i = 0; i < NumOfDigitsInBase10; i++)\n        {\n            buckets[i, 0] = 0; // set size of bucket to 0\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Integer/CountingSorter.cs",
    "content": "namespace Algorithms.Sorters.Integer;\n\n/// <summary>\n///     Counting sort is an algorithm for sorting a collection of objects according to keys that are small integers; that\n///     is, it is an integer sorting algorithm. It operates by counting the number of objects that have each distinct key\n///     value, and using arithmetic on those counts to determine the positions of each key value in the output sequence.\n///     Its running time is linear in the number of items and the difference between the maximum and minimum key values, so\n///     it is only suitable for direct use in situations where the variation in keys is not significantly greater than the\n///     number of items. However, it is often used as a subroutine in another sorting algorithm, radix sort, that can\n///     handle larger keys more efficiently.\n/// </summary>\npublic class CountingSorter : IIntegerSorter\n{\n    /// <summary>\n    ///     <para>\n    ///         Sorts input array using counting sort algorithm.\n    ///     </para>\n    ///     <para>\n    ///         Time complexity: O(n+k), where k is the range of the non-negative key values.\n    ///     </para>\n    ///     <para>\n    ///         Space complexity: O(n+k), where k is the range of the non-negative key values.\n    ///     </para>\n    /// </summary>\n    /// <param name=\"array\">Input array.</param>\n    public void Sort(int[] array)\n    {\n        if (array.Length == 0)\n        {\n            return;\n        }\n\n        var max = array.Max();\n        var min = array.Min();\n        var count = new int[max - min + 1];\n        var output = new int[array.Length];\n        for (var i = 0; i < array.Length; i++)\n        {\n            count[array[i] - min]++;\n        }\n\n        for (var i = 1; i < count.Length; i++)\n        {\n            count[i] += count[i - 1];\n        }\n\n        for (var i = array.Length - 1; i >= 0; i--)\n        {\n            output[count[array[i] - min] - 1] = array[i];\n            count[array[i] - min]--;\n        }\n\n        Array.Copy(output, array, array.Length);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Integer/IIntegerSorter.cs",
    "content": "namespace Algorithms.Sorters.Integer;\n\n/// <summary>\n///     Sorts array of integers without comparing them.\n/// </summary>\npublic interface IIntegerSorter\n{\n    /// <summary>\n    ///     Sorts array in ascending order.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    void Sort(int[] array);\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Integer/RadixSorter.cs",
    "content": "namespace Algorithms.Sorters.Integer;\n\n/// <summary>\n///     Radix sort is a non-comparative integer sorting algorithm that sorts data with integer keys by grouping keys by the\n///     individual\n///     digits which share the same significant position and value. A positional notation is required, but because integers\n///     can represent\n///     strings of characters (e.g., names or dates) and specially formatted floating point numbers, radix sort is not\n///     limited to integers.\n/// </summary>\npublic class RadixSorter : IIntegerSorter\n{\n    /// <summary>\n    ///     Sorts array in ascending order.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    public void Sort(int[] array)\n    {\n        var bits = 4;\n        var b = new int[array.Length];\n        var rshift = 0;\n        for (var mask = ~(-1 << bits); mask != 0; mask <<= bits, rshift += bits)\n        {\n            var cntarray = new int[1 << bits];\n            foreach (var t in array)\n            {\n                var key = (t & mask) >> rshift;\n                ++cntarray[key];\n            }\n\n            for (var i = 1; i < cntarray.Length; ++i)\n            {\n                cntarray[i] += cntarray[i - 1];\n            }\n\n            for (var p = array.Length - 1; p >= 0; --p)\n            {\n                var key = (array[p] & mask) >> rshift;\n                --cntarray[key];\n                b[cntarray[key]] = array[p];\n            }\n\n            var temp = b;\n            b = array;\n            array = temp;\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/String/IStringSorter.cs",
    "content": "namespace Algorithms.Sorters.String;\n\n/// <summary>\n///     Sorts array of strings without comparing them.\n/// </summary>\npublic interface IStringSorter\n{\n    /// <summary>\n    ///     Sorts array in ascending order.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    void Sort(string[] array);\n}\n"
  },
  {
    "path": "Algorithms/Sorters/String/MsdRadixStringSorter.cs",
    "content": "namespace Algorithms.Sorters.String;\n\n/// <summary>\n///     Radix sort is a non-comparative sorting algorithm. It avoids comparison by creating\n///     and distributing elements into buckets according to their radix.\n///     Radix sorts can be implemented to start at either the most significant digit (MSD)\n///     or least significant digit (LSD).\n///     MSD radix sorts are most suitable for sorting array of strings with variable length\n///     in lexicographical order.\n/// </summary>\npublic class MsdRadixStringSorter : IStringSorter\n{\n    /// <summary>\n    ///     Sort array of strings using MSD radix sort algorithm.\n    /// </summary>\n    /// <param name=\"array\">Array to sort.</param>\n    public void Sort(string[] array) => Sort(array, 0, array.Length - 1, 0, new string[array.Length]);\n\n    private static void Sort(string[] array, int l, int r, int d, string[] temp)\n    {\n        if (l >= r)\n        {\n            return;\n        }\n\n        const int k = 256;\n\n        var count = new int[k + 2];\n        for (var i = l; i <= r; i++)\n        {\n            var j = Key(array[i]);\n            count[j + 2]++;\n        }\n\n        for (var i = 1; i < count.Length; i++)\n        {\n            count[i] += count[i - 1];\n        }\n\n        for (var i = l; i <= r; i++)\n        {\n            var j = Key(array[i]);\n            temp[count[j + 1]++] = array[i];\n        }\n\n        for (var i = l; i <= r; i++)\n        {\n            array[i] = temp[i - l];\n        }\n\n        for (var i = 0; i < k; i++)\n        {\n            Sort(array, l + count[i], l + count[i + 1] - 1, d + 1, temp);\n        }\n\n        int Key(string s) => d >= s.Length ? -1 : s[d];\n    }\n}\n"
  },
  {
    "path": "Algorithms/Sorters/Utils/GallopingStrategy.cs",
    "content": "namespace Algorithms.Sorters.Utils;\n\npublic static class GallopingStrategy<T>\n{\n    public static int GallopLeft(T[] array, T key, int baseIndex, int length, IComparer<T> comparer)\n    {\n        if (array.Length == 0)\n        {\n            return 0;\n        }\n\n        var (offset, lastOfs) = comparer.Compare(key, array[baseIndex]) > 0\n       ? RightRun(array, key, baseIndex, length, 0, comparer)\n       : LeftRun(array, key, baseIndex, 0, comparer);\n\n        return FinalOffset(array, key, baseIndex, offset, lastOfs, 1, comparer);\n    }\n\n    public static int GallopRight(T[] array, T key, int baseIndex, int length, IComparer<T> comparer)\n    {\n        if (array.Length == 0)\n        {\n            return 0;\n        }\n\n        var (offset, lastOfs) = comparer.Compare(key, array[baseIndex]) < 0\n        ? LeftRun(array, key, baseIndex, length, comparer)\n        : RightRun(array, key, baseIndex, length, 0, comparer);\n\n        return FinalOffset(array, key, baseIndex, offset, lastOfs, 0, comparer);\n    }\n\n    public static int BoundLeftShift(int shiftable) => (shiftable << 1) < 0\n    ? (shiftable << 1) + 1\n    : int.MaxValue;\n\n    private static (int Offset, int LastOfs) LeftRun(T[] array, T key, int baseIndex, int hint, IComparer<T> comparer)\n    {\n        var maxOfs = hint + 1;\n        var (offset, tmp) = (1, 0);\n\n        while (offset < maxOfs && comparer.Compare(key, array[baseIndex + hint - offset]) < 0)\n        {\n            tmp = offset;\n            offset = BoundLeftShift(offset);\n        }\n\n        if (offset > maxOfs)\n        {\n            offset = maxOfs;\n        }\n\n        var lastOfs = hint - offset;\n        offset = hint - tmp;\n\n        return (offset, lastOfs);\n    }\n\n    private static (int Offset, int LastOfs) RightRun(T[] array, T key, int baseIndex, int len, int hint, IComparer<T> comparer)\n    {\n        var (offset, lastOfs) = (1, 0);\n        var maxOfs = len - hint;\n        while (offset < maxOfs && comparer.Compare(key, array[baseIndex + hint + offset]) > 0)\n        {\n            lastOfs = offset;\n            offset = BoundLeftShift(offset);\n        }\n\n        if (offset > maxOfs)\n        {\n            offset = maxOfs;\n        }\n\n        offset += hint;\n        lastOfs += hint;\n\n        return (offset, lastOfs);\n    }\n\n    private static int FinalOffset(T[] array, T key, int baseIndex, int offset, int lastOfs, int lt, IComparer<T> comparer)\n    {\n        lastOfs++;\n        while (lastOfs < offset)\n        {\n            var m = lastOfs + (int)((uint)(offset - lastOfs) >> 1);\n\n            if (comparer.Compare(key, array[baseIndex + m]) < lt)\n            {\n                offset = m;\n            }\n            else\n            {\n                lastOfs = m + 1;\n            }\n        }\n\n        return offset;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Stack/BalancedParenthesesChecker.cs",
    "content": "namespace Algorithms.Stack;\n\n/// <summary>\n///     It checks if an expression has matching and balanced parentheses.\n/// @author Mohit Singh. <a href=\"https://github.com/mohit-gogitter\">mohit-gogitter</a>\n/// </summary>\npublic class BalancedParenthesesChecker\n{\n    private static readonly Dictionary<char, char> ParenthesesMap = new Dictionary<char, char>\n        {\n            { '(', ')' },\n            { '{', '}' },\n            { '[', ']' },\n        };\n\n    /// <summary>\n    /// Determines if a given string expression containing brackets is balanced.\n    /// A string is considered balanced if all opening brackets have corresponding closing brackets\n    /// in the correct order. The supported brackets are '()', '{}', and '[]'.\n    /// </summary>\n    /// <param name=\"expression\">\n    /// The input string expression containing the brackets to check for balance.\n    /// </param>\n    /// <returns>\n    /// <c>true</c> if the brackets in the expression are balanced; otherwise, <c>false</c>.\n    /// </returns>\n    /// <exception cref=\"ArgumentException\">\n    /// Thrown when the input expression contains invalid characters or is null/empty.\n    /// Only '(', ')', '{', '}', '[', ']' characters are allowed.\n    /// </exception>\n    public bool IsBalanced(string expression)\n    {\n        if (string.IsNullOrEmpty(expression))\n        {\n            throw new ArgumentException(\"The input expression cannot be null or empty.\");\n        }\n\n        Stack<char> stack = new Stack<char>();\n        foreach (char c in expression)\n        {\n            if (IsOpeningParenthesis(c))\n            {\n                stack.Push(c);\n            }\n            else if (IsClosingParenthesis(c))\n            {\n                if (!IsBalancedClosing(stack, c))\n                {\n                    return false;\n                }\n            }\n            else\n            {\n                throw new ArgumentException($\"Invalid character '{c}' found in the expression.\");\n            }\n        }\n\n        return stack.Count == 0;\n    }\n\n    private static bool IsOpeningParenthesis(char c)\n    {\n        return c == '(' || c == '{' || c == '[';\n    }\n\n    private static bool IsClosingParenthesis(char c)\n    {\n        return c == ')' || c == '}' || c == ']';\n    }\n\n    private static bool IsBalancedClosing(Stack<char> stack, char close)\n    {\n        if (stack.Count == 0)\n        {\n            return false;\n        }\n\n        char open = stack.Pop();\n        return IsMatchingPair(open, close);\n    }\n\n    private static bool IsMatchingPair(char open, char close)\n    {\n        return ParenthesesMap.ContainsKey(open) && ParenthesesMap[open] == close;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Stack/InfixToPostfix.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Algorithms.Stack\n{\n    /// <summary>\n    /// The Code focuses on Converting an Infix Expression to a Postfix Expression and Evaluates the value for the expression.\n    /// @author Aalok Choudhari. <a href=\"https://github.com/kaloa2025\">kaloa2025</a>\n    /// </summary>\n    public static class InfixToPostfix\n    {\n        /// <summary>\n        /// <param name=\"initialInfixExpression\"> Infix Expression String to Convert.</param>\n        /// <returns>Postfix Expression.</returns>\n        /// <exception cref=\"ArgumentException\">\n        /// Thrown when the input expression contains invalid characters or is null/empty.\n        /// Only following characters are allowed : Parentheses['(',')'], Operands[a-z,A-Z,0-9], Operators['+','-','*','/','^'].\n        /// </exception>\n        /// </summary>\n        public static string InfixToPostfixConversion(string initialInfixExpression)\n        {\n            ValidateInfix(initialInfixExpression);\n\n            Stack<char> stack = new Stack<char>();\n            StringBuilder postfixExpression = new StringBuilder();\n\n            foreach (char c in initialInfixExpression)\n            {\n                if (char.IsWhiteSpace(c))\n                {\n                    continue;\n                }\n\n                if (!IsValidCharacter(c))\n                {\n                    throw new ArgumentException($\"Invalid character {c}.\");\n                }\n\n                ProcessInfixCharacter(c, stack, postfixExpression);\n            }\n\n            EmptyRemainingStack(stack, postfixExpression);\n            return postfixExpression.ToString();\n        }\n\n        /// <summary>\n        /// <param name=\"postfixExpression\"> Postfix Expression String to Evaluate.</param>\n        /// <returns>Postfix Expression's Calculated value.</returns>\n        /// <exception cref=\"ArgumentException\">\n        /// Thrown when the input expression contains invalid characters or is null/empty.\n        /// </exception>\n        /// <exception cref=\"InvalidOperationException\">\n        /// Validates expression to have sufficient operands for performing operation.\n        /// </exception>\n        /// </summary>\n        public static int PostfixExpressionEvaluation(string postfixExpression)\n        {\n            ValidatePostfix(postfixExpression);\n\n            Stack<int> stack = new Stack<int>();\n            foreach (char ch in postfixExpression)\n            {\n                if(char.IsWhiteSpace(ch))\n                {\n                    continue;\n                }\n\n                if(char.IsDigit(ch))\n                {\n                    stack.Push(ch - '0');\n                    continue;\n                }\n\n                if (IsOperator(ch))\n                {\n                    EvaluateOperator(stack, ch);\n                    continue;\n                }\n\n                throw new InvalidOperationException($\"Invalid character in expression: {ch}\");\n            }\n\n            if (stack.Count != 1)\n            {\n                throw new InvalidOperationException(\"Invalid postfix expression: Leftover operands.\");\n            }\n\n            return stack.Pop();\n        }\n\n        private static void ProcessInfixCharacter(char c, Stack<char> stack, StringBuilder postfixExpression)\n        {\n            if (IsOperand(c))\n            {\n                postfixExpression.Append(c);\n                return;\n            }\n\n            if (c == '(')\n            {\n                stack.Push(c);\n                return;\n            }\n\n            if (c == ')')\n            {\n                ProcessClosingParenthesis(stack, postfixExpression);\n                return;\n            }\n\n            ProcessOperator(c, stack, postfixExpression);\n        }\n\n        private static void ProcessClosingParenthesis(Stack<char> stack, StringBuilder postfixExpression)\n        {\n            while (stack.Count > 0 && stack.Peek() != '(')\n            {\n                postfixExpression.Append(stack.Pop());\n            }\n\n            if (stack.Count == 0)\n            {\n                throw new InvalidOperationException(\"Mismatched parentheses in expression.\");\n            }\n\n            stack.Pop();\n        }\n\n        private static void ProcessOperator(char c, Stack<char> stack, StringBuilder postfixExpression)\n        {\n            while (stack.Count > 0 && stack.Peek() != '(' && Precedence(stack.Peek()) >= Precedence(c))\n            {\n                postfixExpression.Append(stack.Pop());\n            }\n\n            stack.Push(c);\n        }\n\n        private static void EmptyRemainingStack(Stack<char> stack, StringBuilder postfix)\n        {\n            while (stack.Count > 0)\n            {\n                if (stack.Peek() is '(' or ')')\n                {\n                    throw new InvalidOperationException(\"Mismatched parentheses.\");\n                }\n\n                postfix.Append(stack.Pop());\n            }\n        }\n\n        private static void EvaluateOperator(Stack<int> stack, char op)\n        {\n            if (stack.Count < 2)\n            {\n                throw new InvalidOperationException(\"Insufficient operands\");\n            }\n\n            int b = stack.Pop();\n            int a = stack.Pop();\n\n            if (op == '/' && b == 0)\n            {\n                throw new DivideByZeroException(\"Cannot divide by zero\");\n            }\n\n            int result = op switch\n            {\n                '+' => a + b,\n                '-' => a - b,\n                '*' => a * b,\n                '/' => a / b,\n                '^' => (int)Math.Pow(a, b),\n                _ => throw new InvalidOperationException($\"Unknown operator {op}\"),\n            };\n\n            stack.Push(result);\n        }\n\n        private static void ValidateInfix(string expr)\n        {\n            if (string.IsNullOrEmpty(expr) || string.IsNullOrWhiteSpace(expr))\n            {\n                throw new ArgumentException(\"Infix cannot be null or empty.\");\n            }\n        }\n\n        private static void ValidatePostfix(string expr)\n        {\n            if (string.IsNullOrEmpty(expr) || string.IsNullOrWhiteSpace(expr))\n            {\n                throw new ArgumentException(\"Postfix cannot be null or empty.\");\n            }\n        }\n\n        /// <summary>\n        /// Decided Operator Precedence.\n        /// <param name=\"operatorChar\"> Operator character whose precedence is asked.</param>\n        /// <returns>Precedence rank of parameter operator character.</returns>\n        /// </summary>\n        [ExcludeFromCodeCoverage]\n        private static int Precedence(char operatorChar)\n        {\n            if (operatorChar == '^')\n            {\n                return 3;\n            }\n\n            if (operatorChar == '*' || operatorChar == '/')\n            {\n                return 2;\n            }\n\n            if (operatorChar == '+' || operatorChar == '-')\n            {\n                return 1;\n            }\n\n            return 0;\n        }\n\n        /// <summary>\n        /// Checks for character if its an Operand.\n        /// <param name=\"ch\"> Character asked to verify whether its an operand.</param>\n        /// <returns>True if its a digit or a Letter.</returns>\n        /// </summary>\n        private static bool IsOperand(char ch) => char.IsLetterOrDigit(ch);\n\n        private static readonly HashSet<char> Operators = new() { '+', '-', '*', '/', '^' };\n\n        /// <summary>\n        /// Checks Operator.\n        /// <param name=\"ch\"> Character asked to verify whether its an operator.</param>\n        /// <returns>True if its allowded operator character.</returns>\n        /// </summary>\n        private static bool IsOperator(char ch) => Operators.Contains(ch);\n\n        /// <summary>\n        /// Checks Valid Character.\n        /// <param name=\"c\"> Character asked to verify whether its an valid Character for expression.</param>\n        /// <returns>True if its allowded character.</returns>\n        /// </summary>\n        private static bool IsValidCharacter(char c) => IsOperand(c) || IsOperator(c) || IsParenthesis(c);\n\n        private static bool IsParenthesis(char c) => c == '(' || c == ')';\n    }\n}\n"
  },
  {
    "path": "Algorithms/Stack/NextGreaterElement.cs",
    "content": "namespace Algorithms.Stack;\n\n/// <summary>\n///     For each element in an array, the utility finds the next greater element on the right side using a stack.\n/// @author Mohit Singh. <a href=\"https://github.com/mohit-gogitter\">mohit-gogitter</a>\n/// </summary>\npublic class NextGreaterElement\n{\n    /// <summary>\n    /// Finds the next greater element for each element in the input array.\n    /// The next greater element for an element x is the first element greater than x to its right.\n    /// If there is no greater element, -1 is returned for that element.\n    /// </summary>\n    /// <param name=\"nums\">The array of integers to find the next greater elements for.</param>\n    /// <returns>An array where each index contains the next greater element of the corresponding element in the input array, or -1 if no such element exists.</returns>\n    /// <exception cref=\"ArgumentNullException\">Thrown when the input array is null.</exception>\n    public int[] FindNextGreaterElement(int[] nums)\n    {\n        int[] result = new int[nums.Length];\n        Stack<int> stack = new Stack<int>();\n\n        // Initialize all elements in the result array to -1\n        for (int i = 0; i < nums.Length; i++)\n        {\n            result[i] = -1;\n        }\n\n        for (int i = 0; i < nums.Length; i++)\n        {\n            // While the stack is not empty and the current element is greater than the element\n            // corresponding to the index stored at the top of the stack\n            while (stack.Count > 0 && nums[i] > nums[stack.Peek()])\n            {\n                int index = stack.Pop();\n                result[index] = nums[i]; // Set the next greater element\n            }\n\n            stack.Push(i); // Push current index to stack\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Stack/ReverseStack.cs",
    "content": "namespace Algorithms.Stack;\n\n/// <summary>\n///     Reverses the elements in a stack using recursion.\n/// @author Mohit Singh. <a href=\"https://github.com/mohit-gogitter\">mohit-gogitter</a>\n/// </summary>\npublic class ReverseStack\n{\n    /// <summary>\n    /// Recursively reverses the elements of the specified stack.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of elements in the stack.</typeparam>\n    /// <param name=\"stack\">The stack to be reversed. This parameter cannot be null.</param>\n    /// <exception cref=\"ArgumentNullException\">Thrown when the stack parameter is null.</exception>\n    public void Reverse<T>(Stack<T> stack)\n    {\n        if (stack.Count == 0)\n        {\n            return;\n        }\n\n        T temp = stack.Pop();\n        Reverse(stack);\n        InsertAtBottom(stack, temp);\n    }\n\n    private void InsertAtBottom<T>(Stack<T> stack, T value)\n    {\n        if (stack.Count == 0)\n        {\n            stack.Push(value);\n        }\n        else\n        {\n            T temp = stack.Pop();\n            InsertAtBottom(stack, value);\n            stack.Push(temp);\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/GeneralStringAlgorithms.cs",
    "content": "namespace Algorithms.Strings;\n\n/// <summary>\n///     Implements simple algorithms on strings.\n/// </summary>\npublic static class GeneralStringAlgorithms\n{\n    /// <summary>\n    ///     Finds character that creates longest consecutive substring with single character.\n    /// </summary>\n    /// <param name=\"input\">String to find in.</param>\n    /// <returns>Tuple containing char and number of times it appeared in a row.</returns>\n    public static Tuple<char, int> FindLongestConsecutiveCharacters(string input)\n    {\n        var maxChar = input[0];\n\n        var max = 1;\n        var current = 1;\n\n        for (var i = 1; i < input.Length; i++)\n        {\n            if (input[i] == input[i - 1])\n            {\n                current++;\n                if (current > max)\n                {\n                    max = current;\n                    maxChar = input[i];\n                }\n            }\n            else\n            {\n                current = 1;\n            }\n        }\n\n        return new Tuple<char, int>(maxChar, max);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/ManachersAlgorithm.cs",
    "content": "namespace Algorithms.Strings;\n\n/// <summary>\n///     Manacher's Algorithm is used to find the longest palindromic substring in linear time O(n).\n///     This algorithm is significantly more efficient than the naive O(n²) approach.\n///\n///     KEY CONCEPTS:\n///     1. String Transformation: Inserts special characters to handle even/odd palindromes uniformly.\n///     2. Palindrome Radius: For each position, stores how far the palindrome extends.\n///     3. Center Expansion: Expands around each potential center to find palindromes.\n///     4. Symmetry Property: Uses previously computed palindrome information to skip redundant checks.\n///     5. Right Boundary Tracking: Maintains the rightmost boundary of any palindrome found.\n///\n///     WHY IT'S FAST:\n///     The algorithm achieves O(n) time by ensuring each character is examined at most twice:\n///     - Once when it's inside a known palindrome (using mirror property).\n///     - Once when expanding beyond the known boundary.\n///\n///     Reference: \"A New Linear-Time On-Line Algorithm for Finding the Smallest Initial Palindrome of a String\"\n///     by Glenn Manacher (1975), Journal of the ACM.\n/// </summary>\npublic static class ManachersAlgorithm\n{\n    /// <summary>\n    ///     Finds the longest palindromic substring using Manacher's Algorithm.\n    ///\n    ///     ALGORITHM STEPS:\n    ///     1. PREPROCESSING: Transform \"abc\" to \"^#a#b#c#$\" to handle even/odd palindromes uniformly.\n    ///        - ^ and $ are sentinels that prevent boundary checks.\n    ///        - # characters create uniform spacing.\n    ///\n    ///     2. INITIALIZATION: Set up tracking variables.\n    ///        - palindromeRadii[i]: How far palindrome extends from position i.\n    ///        - center: Center of rightmost palindrome found.\n    ///        - rightBoundary: Right edge of rightmost palindrome.\n    ///\n    ///     3. MAIN LOOP: For each position i in transformed string.\n    ///        a) If i is within rightBoundary, use mirror property:\n    ///           - mirror = 2 * center - i (symmetric position).\n    ///           - Start with min(palindromeRadii[mirror], rightBoundary - i).\n    ///        b) Expand palindrome by comparing characters on both sides.\n    ///        c) Update center and rightBoundary if palindrome extends further right.\n    ///        d) Track the longest palindrome found.\n    ///\n    ///     4. EXTRACTION: Convert transformed coordinates back to original string.\n    ///\n    ///     Time Complexity: O(n) - Each character examined at most twice.\n    ///     Space Complexity: O(n) - For transformed string and radius array.\n    /// </summary>\n    /// <param name=\"input\">The input string to search for palindromes.</param>\n    /// <returns>The longest palindromic substring found in the input.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown when the input string is null.</exception>\n    /// <example>\n    ///     Input: \"babad\".\n    ///     Output: \"bab\" or \"aba\" (both are valid longest palindromes with length 3).\n    ///\n    ///     Detailed Example:\n    ///     Input: \"abaxyz\".\n    ///     Transformed: \"^#a#b#a#x#y#z#$\".\n    ///     Process finds \"aba\" at indices 1-3 with radius 3 in transformed string.\n    ///     Maps back to indices 0-2 in original string.\n    ///     Output: \"aba\".\n    /// </example>\n    public static string FindLongestPalindrome(string input)\n    {\n        // Validate input\n        if (input == null)\n        {\n            throw new ArgumentException(\"Input string cannot be null.\", nameof(input));\n        }\n\n        // Handle edge cases\n        if (input.Length == 0)\n        {\n            return string.Empty;\n        }\n\n        if (input.Length == 1)\n        {\n            return input;\n        }\n\n        // STEP 1: Transform the string to handle even-length palindromes uniformly\n        // Example: \"abc\" becomes \"^#a#b#c#$\"\n        //\n        // WHY THIS WORKS:\n        // - Original \"aba\" (odd): Center is 'b' at index 1.\n        // - Original \"abba\" (even): No single center character.\n        // - Transformed \"#a#b#b#a#\": Both have clear centers (the middle #).\n        //\n        // SENTINELS (^ and $):\n        // - Prevent index out of bounds during expansion.\n        // - Never match any character, so expansion stops naturally.\n        string transformed = PreprocessString(input);\n        int n = transformed.Length;\n\n        // STEP 2: Initialize data structures\n\n        // palindromeRadii[i] = radius of palindrome centered at position i.\n        // Example: If transformed[i] is center of \"#a#b#a#\", radius = 3.\n        // (3 characters on each side match).\n        int[] palindromeRadii = new int[n];\n\n        // Track the rightmost palindrome boundary for optimization.\n        // center: Position of the palindrome that extends furthest right.\n        // rightBoundary: The rightmost index covered by that palindrome.\n        // These help us use symmetry to avoid redundant comparisons.\n        int center = 0;\n        int rightBoundary = 0;\n\n        // Track the longest palindrome found during the scan.\n        // maxLength: Radius of the longest palindrome.\n        // maxCenter: Position where the longest palindrome is centered.\n        int maxLength = 0;\n        int maxCenter = 0;\n\n        // STEP 3: Process each position in the transformed string.\n        // Skip first and last positions (sentinels ^ and $).\n        for (int i = 1; i < n - 1; i++)\n        {\n            // OPTIMIZATION: Use mirror property for positions within known palindrome\n            //\n            // If we have a palindrome centered at 'center' extending to 'rightBoundary':\n            //     center - radius ... center ... center + radius\n            //                 mirror    i\n            //\n            // The mirror position reflects i across the center:\n            // mirror = center - (i - center) = 2 * center - i.\n            int mirror = 2 * center - i;\n\n            // KEY INSIGHT: If i is within rightBoundary, we can use symmetry.\n            // The palindrome at position i might be similar to the one at mirror position.\n            if (i < rightBoundary)\n            {\n                // We can safely copy the radius from the mirror position, BUT:\n                // 1. palindromeRadii[mirror]: What we know from the mirror side.\n                // 2. rightBoundary - i: We can't assume anything beyond rightBoundary.\n                //\n                // Take the minimum because:\n                // - If mirror's palindrome fits within bounds, we can use it.\n                // - If it extends beyond, we only know up to rightBoundary.\n                palindromeRadii[i] = Math.Min(rightBoundary - i, palindromeRadii[mirror]);\n            }\n\n            // EXPANSION PHASE: Try to extend the palindrome further.\n            // We start from palindromeRadii[i] (not 0) to avoid redundant checks.\n            // This is why the algorithm is O(n) - we never re-check characters.\n            //\n            // Example: If palindromeRadii[i] = 2, we already know:\n            // transformed[i-2] == transformed[i+2] and\n            // transformed[i-1] == transformed[i+1].\n            // So we start checking at distance 3.\n            //\n            // The sentinels (^ and $) guarantee we never go out of bounds.\n            // Expansion stops naturally when characters don't match.\n            while (transformed[i + palindromeRadii[i] + 1] == transformed[i - palindromeRadii[i] - 1])\n            {\n                palindromeRadii[i]++;\n            }\n\n            // UPDATE TRACKING: If this palindrome extends further right than any before.\n            //\n            // WHY THIS MATTERS:\n            // By tracking the rightmost boundary, we can use the mirror property\n            // for future positions, avoiding redundant character comparisons.\n            //\n            // Example: If we find a large palindrome early, all positions within it\n            // can benefit from the symmetry property.\n            if (i + palindromeRadii[i] > rightBoundary)\n            {\n                center = i;  // This position is now our reference center.\n                rightBoundary = i + palindromeRadii[i];  // Update the rightmost boundary.\n            }\n\n            // TRACK MAXIMUM: Remember the longest palindrome found so far.\n            // We need both the length and position to extract it later.\n            if (palindromeRadii[i] > maxLength)\n            {\n                maxLength = palindromeRadii[i];  // Radius of longest palindrome.\n                maxCenter = i;  // Where it's centered in transformed string.\n            }\n        }\n\n        // STEP 4: Extract the longest palindrome from the original string.\n        //\n        // COORDINATE MAPPING:\n        // Transformed string has format: ^#a#b#c#$.\n        // Position in transformed -> Position in original: (pos - 1) / 2.\n        //\n        // Example: \"aba\" -> \"^#a#b#a#$\".\n        // - maxCenter = 4 (the middle 'b' in transformed).\n        // - maxLength = 3 (radius).\n        // - Original center = (4 - 1) / 2 = 1 (index of 'b' in \"aba\").\n        // - Start = (maxCenter - maxLength) / 2 = (4 - 3) / 2 = 0.\n        // - Length = maxLength = 3.\n        // - Result: input.Substring(0, 3) = \"aba\".\n        int start = (maxCenter - maxLength) / 2;\n        return input.Substring(start, maxLength);\n    }\n\n    /// <summary>\n    ///     Finds the longest palindromic substring and returns detailed information.\n    ///     This method provides more detailed information than FindLongestPalindrome,\n    ///     including the exact starting position and length in the original string.\n    ///\n    ///     USE CASE:\n    ///     When you need to know WHERE the palindrome is located, not just what it is.\n    ///     Useful for highlighting, replacing, or further processing the palindrome.\n    /// </summary>\n    /// <param name=\"input\">The input string to search for palindromes.</param>\n    /// <returns>\n    ///     A tuple containing:\n    ///     - The longest palindromic substring\n    ///     - The starting index of the longest palindrome in the original string\n    ///     - The length of the longest palindrome.\n    /// </returns>\n    /// <exception cref=\"ArgumentException\">Thrown when the input string is null.</exception>\n    /// <example>\n    ///     Input: \"babad\".\n    ///     Output: (Palindrome: \"bab\", StartIndex: 0, Length: 3).\n    /// </example>\n    public static (string Palindrome, int StartIndex, int Length) FindLongestPalindromeWithDetails(string input)\n    {\n        // Validate input\n        if (input == null)\n        {\n            throw new ArgumentException(\"Input string cannot be null.\", nameof(input));\n        }\n\n        // Handle edge cases\n        if (input.Length == 0)\n        {\n            return (string.Empty, 0, 0);\n        }\n\n        if (input.Length == 1)\n        {\n            return (input, 0, 1);\n        }\n\n        // Apply the same algorithm as FindLongestPalindrome.\n        // (See detailed comments in that method for step-by-step explanation).\n        string transformed = PreprocessString(input);\n        int n = transformed.Length;\n        int[] palindromeRadii = new int[n];\n        int center = 0;\n        int rightBoundary = 0;\n        int maxLength = 0;\n        int maxCenter = 0;\n\n        // Main algorithm loop\n        for (int i = 1; i < n - 1; i++)\n        {\n            // Use mirror property if within known palindrome.\n            int mirror = 2 * center - i;\n\n            if (i < rightBoundary)\n            {\n                palindromeRadii[i] = Math.Min(rightBoundary - i, palindromeRadii[mirror]);\n            }\n\n            // Expand palindrome.\n            // Sentinels guarantee no out-of-bounds access.\n            while (transformed[i + palindromeRadii[i] + 1] == transformed[i - palindromeRadii[i] - 1])\n            {\n                palindromeRadii[i]++;\n            }\n\n            // Update rightmost boundary.\n            if (i + palindromeRadii[i] > rightBoundary)\n            {\n                center = i;\n                rightBoundary = i + palindromeRadii[i];\n            }\n\n            // Track maximum.\n            if (palindromeRadii[i] > maxLength)\n            {\n                maxLength = palindromeRadii[i];\n                maxCenter = i;\n            }\n        }\n\n        // Calculate the start index and extract the palindrome.\n        // Map from transformed coordinates to original string coordinates.\n        int startIndex = (maxCenter - maxLength) / 2;\n        string palindrome = input.Substring(startIndex, maxLength);\n\n        // Return all three pieces of information.\n        return (palindrome, startIndex, maxLength);\n    }\n\n    /// <summary>\n    ///     Checks if the entire string is a palindrome using Manacher's Algorithm.\n    ///\n    ///     EFFICIENCY:\n    ///     - This approach: O(n) time using Manacher's algorithm.\n    ///     - Naive approach: O(n) time for reversing + O(n) for comparison.\n    ///     - Both are O(n), but this avoids creating a reversed copy.\n    ///\n    ///     LOGIC:\n    ///     If the longest palindrome in the string equals the string length,\n    ///     then the entire string must be a palindrome.\n    /// </summary>\n    /// <param name=\"input\">The string to check.</param>\n    /// <returns>True if the entire string is a palindrome, false otherwise.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown when the input string is null.</exception>\n    /// <example>\n    ///     Input: \"racecar\".\n    ///     Output: true.\n    /// </example>\n    public static bool IsPalindrome(string input)\n    {\n        if (input == null)\n        {\n            throw new ArgumentException(\"Input string cannot be null.\", nameof(input));\n        }\n\n        // Strings of length 0 or 1 are always palindromes.\n        if (input.Length <= 1)\n        {\n            return true;\n        }\n\n        // Find the longest palindrome in the string.\n        // If it spans the entire string, then the string is a palindrome.\n        var (_, _, length) = FindLongestPalindromeWithDetails(input);\n        return length == input.Length;\n    }\n\n    /// <summary>\n    ///     Preprocesses the input string by inserting special characters.\n    ///     This transformation is the KEY to making Manacher's algorithm work efficiently.\n    ///\n    ///     PROBLEM IT SOLVES:\n    ///     - Odd-length palindromes (\"aba\") have a center character.\n    ///     - Even-length palindromes (\"abba\") have a center between characters.\n    ///     - Without transformation, we'd need separate logic for each case.\n    ///\n    ///     SOLUTION:\n    ///     Insert '#' between every character, making all palindromes odd-length.\n    ///\n    ///     EXAMPLES:\n    ///     - \"aba\" (odd) -> \"^#a#b#a#$\" (center is 'b').\n    ///     - \"abba\" (even) -> \"^#a#b#b#a#$\" (center is '#' between the two 'b's).\n    ///\n    ///     SENTINELS (^ and $):\n    ///     - Placed at start and end.\n    ///     - Never match any character (including each other).\n    ///     - Automatically stop expansion without explicit boundary checks.\n    ///     - Prevent IndexOutOfBoundsException.\n    ///\n    ///     COORDINATE MAPPING:\n    ///     - Original index i maps to transformed index (2*i + 2).\n    ///     - Transformed index j maps to original index (j - 1) / 2.\n    /// </summary>\n    /// <param name=\"input\">The original input string.</param>\n    /// <returns>The transformed string with inserted special characters.</returns>\n    private static string PreprocessString(string input)\n    {\n        // Calculate the size of transformed string.\n        // Original: n characters.\n        // Transformed: ^ + # + (n chars with # between each) + # + $.\n        // Total: 1 + 1 + n + (n-1) + 1 + 1 = 2n + 3.\n        int n = input.Length;\n        char[] transformed = new char[n * 2 + 3];\n\n        // Place sentinels at boundaries.\n        transformed[0] = '^'; // Start sentinel (never matches anything).\n        transformed[n * 2 + 2] = '$'; // End sentinel (never matches anything).\n\n        // Build the transformed string: #a#b#c#.\n        // For input \"abc\":\n        // Position 0: ^ (sentinel).\n        // Position 1: # (separator).\n        // Position 2: a (input[0]).\n        // Position 3: # (separator).\n        // Position 4: b (input[1]).\n        // Position 5: # (separator).\n        // Position 6: c (input[2]).\n        // Position 7: # (separator).\n        // Position 8: $ (sentinel).\n        for (int i = 0; i < n; i++)\n        {\n            transformed[2 * i + 1] = '#';  // Separator before character.\n            transformed[2 * i + 2] = input[i];  // Original character.\n        }\n\n        transformed[n * 2 + 1] = '#';  // Final separator.\n\n        return new string(transformed);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/Palindrome.cs",
    "content": "namespace Algorithms.Strings;\n\n/// <summary>\n///     Palindrome a series of characters or a string that when reversed,\n///     equals the original string.\n/// </summary>\npublic static class Palindrome\n{\n    /// <summary>\n    ///     Function to check if a string is a palindrome.\n    /// </summary>\n    /// <param name=\"word\">String being checked.</param>\n    public static bool IsStringPalindrome(string word) =>\n        TypifyString(word).Equals(TypifyString(ReverseString(word)));\n\n    /// <summary>\n    ///     Typify string to lower and remove white spaces.\n    /// </summary>\n    /// <param name=\"word\">String to remove spaces.</param>\n    /// <returns>Returns original string without spaces.</returns>\n    private static string TypifyString(string word) =>\n        Regex.Replace(word.ToLowerInvariant(), @\"\\s+\", string.Empty);\n\n    /// <summary>\n    ///     Helper function that returns a reversed string inputed.\n    /// </summary>\n    /// <param name=\"s\">String to be reversed.</param>\n    /// <returns>Returns s reversed.</returns>\n    private static string ReverseString(string s)\n    {\n        var arr = s.ToCharArray();\n        Array.Reverse(arr);\n        return new string(arr);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/PatternMatching/Bitap.cs",
    "content": "﻿namespace Algorithms.Strings.PatternMatching;\n\n/// <summary>\n/// The Bitap algorithm is a fuzzy string matching technique. It ains to find approximate matches of a pattern within a\n/// text, allowing for a certain degree of mismatch (e.g., mistypes, minor variations etc.). It's knowd for its efficiency,\n/// using bitwise operations for fast comparisons.\n///\n/// <para>\n/// <b>How it works:</b>\n/// <list type=\"number\">\n/// <item>\n/// <term>Initialization</term>\n/// <description>\n/// Bitmasks are created for each character in the pattern. These bitmasks are essentially binary numbers where each bit\n/// represents a specific character's position within the pattern. An initial state variable <c>R</c> is set to all 1s,\n/// indicating that all characters in the pattern are initially unmatched.\n/// </description>\n/// </item>\n/// <item>\n/// <term>Iteration</term>\n/// <description>\n/// The algorithm iterates through each character in the text. For each character, the state <c>R</c> is updated using\n/// bitwise operations (shifts and logical ORs). This update reflects whether the current character in the text matches\n/// the corresponding character in the pattern.\n/// </description>\n/// </item>\n/// <item>\n/// <term>Matching</term>\n/// <description>\n/// After each iteration, the algorithm checks if the least significant bit of <c>R</c> is set to 1.\n/// If it is, it means there's a potential match at that position, with a mismatch distance that's within the allowed\n/// threshold.\n/// </description>\n/// </item>\n/// </list>\n/// </para>\n/// <para>\n/// <b> Finding Matches </b>\n/// </para>\n/// <para>\n/// If the least significant bit of <c>R</c> is 1, it means a potential match is found.\n/// The number of leading zeros in <c>R</c> indicates the mismatch distance.\n/// If this distance is within the allowed threshold, it's considered a valid match.\n/// </para>\n/// </summary>\npublic static class Bitap\n{\n    /// <summary>\n    /// <para>\n    /// This function implements the Bitap algorithm for finding exact matches of a pattern within a text.\n    /// It aims to find the first occurrence of the pattern in the text, allowing for no mismatches.\n    /// </para>\n    /// <para>\n    /// The algorithm iterates through each character in the text. For each character, the state <c>R</c> is updated using\n    /// bitwise operations (shifts and logical ORs). This update reflects whether the current character in the text matches\n    /// the corresponding character in the pattern.\n    /// </para>\n    /// <para>\n    /// After each iteration, the algorithm checks if the least significant bit of <c>R</c> is set to 1.\n    /// If it is, it means there's a potential match at that position, with a mismatch distance of 0.\n    /// The function returns the index of the first occurrence of the pattern in the text, or -1 if not found.\n    /// </para>\n    /// <para>\n    /// The function throws an <see cref=\"ArgumentException\"/> if the pattern is longer than 31 characters.\n    /// This is because the maximum length of the pattern is 31, because if it's longer than that,\n    /// we won't be able to represent the pattern mask in an int.\n    /// </para>\n    /// </summary>\n    /// <param name=\"text\">The text to search in.</param>\n    /// <param name=\"pattern\">The pattern to search for.</param>\n    /// <returns>The index of the first occurrence of the pattern in the text, or -1 if not found.</returns>\n    /// <exception cref=\"ArgumentException\">The pattern is longer than 31 characters.</exception>\n    public static int FindExactPattern(string text, string pattern)\n    {\n        // The length of the pattern.\n        var len = pattern.Length;\n\n        // An array of integers that will be used to mask the pattern.\n        // The pattern mask is a bitmask that we will use to search for the pattern characters\n        // in the text. We'll set the bit corresponding to the character in the pattern\n        // to 0, and then use bitwise operations to check for the pattern.\n        var patternMask = new int[128];\n        int index;\n\n        // Check if the pattern is empty.\n        if (string.IsNullOrEmpty(pattern))\n        {\n            return 0;\n        }\n\n        // Check if the pattern is longer than 31 characters.\n        if (len > 31)\n        {\n            throw new ArgumentException(\"The pattern is longer than 31 characters.\");\n        }\n\n        // Initialize the register <c>R</c> to all 1s.\n        var r = ~1;\n\n        // Initialize the pattern mask to all 1s.\n        for (index = 0; index <= 127; ++index)\n        {\n            patternMask[index] = ~0;\n        }\n\n        // Set the bits corresponding to the characters in the pattern to 0 in the pattern mask.\n        for (index = 0; index < len; ++index)\n        {\n            patternMask[pattern[index]] &= ~(1 << index);\n        }\n\n        // Iterate through each character in the text.\n        for (index = 0; index < text.Length; ++index)\n        {\n            // Update the state <c>R</c> by ORing the pattern mask with the character in the text,\n            // and then shift it to the left by 1.\n            r |= patternMask[text[index]];\n            r <<= 1;\n\n            // Check if the least significant bit of <c>R</c> is set to 1.\n            // If there's a potential match at that position, with a mismatch distance of 0,\n            // return the index of the first occurrence of the pattern in the text.\n            if ((r & 1 << len) == 0)\n            {\n                return index - len + 1;\n            }\n        }\n\n        // If no match is found, return -1.\n        return -1;\n    }\n\n    /// <summary>\n    /// Finds the first occurrence of a pattern in a given text with a given threshold for mismatches.\n    /// </summary>\n    /// <param name=\"text\">The text to search in.</param>\n    /// <param name=\"pattern\">The pattern to search for.</param>\n    /// <param name=\"threshold\">The maximum number of mismatches allowed.</param>\n    /// <returns>The index of the first occurrence of the pattern in the text, or -1 if not found.</returns>\n    public static int FindFuzzyPattern(string text, string pattern, int threshold)\n    {\n        // Create a pattern mask for each character in the pattern.\n        // The pattern mask is a bitmask that we will use to search for the pattern characters\n        // in the text. We'll set the bit corresponding to the character in the pattern\n        // to 0, and then use bitwise operations to check for the pattern.\n        var patternMask = new int[128];\n\n        // Create a register array.\n        // The register array is used to keep track of the pattern mask as we search for the pattern.\n        // We'll start with a register that has all bits set to 1, because all bits in the pattern mask\n        // will be set to 1 initially.\n        var r = new int[(threshold + 1) * sizeof(int)];\n\n        var len = pattern.Length;\n\n        // Check for empty strings.\n        // If the text is empty, return 0.\n        // If the pattern is empty, return 0.\n        if (string.IsNullOrEmpty(text))\n        {\n            return 0;\n        }\n\n        if (string.IsNullOrEmpty(pattern))\n        {\n            return 0;\n        }\n\n        // Check for a pattern that is too long.\n        // If the pattern is longer than 31 characters, return -1.\n        // The maximum length of the pattern is 31, because if it's longer than that,\n        // we won't be able to represent the pattern mask in an int.\n        if (len > 31)\n        {\n            return -1;\n        }\n\n        // Initialize the register.\n        // Set the least significant bit in the register to 0 or 1\n        // depending on whether the current character in the text matches the pattern.\n        // This will make it easier to check for the pattern later.\n        for (var i = 0; i <= threshold; ++i)\n        {\n            r[i] = ~1;\n        }\n\n        // Initialize the pattern mask.\n        // Set the bit corresponding to each character in the pattern to 0 in the pattern mask.\n        // This will make it easier to check for the pattern later.\n        for (var i = 0; i <= 127; i++)\n        {\n            patternMask[i] = ~0;\n        }\n\n        // Set the pattern mask for each character in the pattern.\n        // Use bitwise AND to clear the bit corresponding to the current character.\n        for (var i = 0; i < len; ++i)\n        {\n            patternMask[pattern[i]] &= ~(1 << i);\n        }\n\n        // Search for the pattern in the text.\n        // Loop through each character in the text.\n        for (var i = 0; i < text.Length; ++i)\n        {\n            // Update the register.\n            // Set the least significant bit in the register to 0 or 1\n            // depending on whether the current character in the text matches the pattern.\n            // This will make it easier to check for the pattern later.\n            var oldR = r[0];\n\n            r[0] |= patternMask[text[i]];\n            r[0] <<= 1;\n\n            // Update the other registers.\n            // Set the least significant bit in each register to 0 or 1\n            // depending on whether the current character in the text matches the pattern.\n            // This will make it easier to check for the pattern later.\n            for (var j = 1; j <= threshold; ++j)\n            {\n                var tmp = r[j];\n\n                r[j] = (oldR & (r[j] | patternMask[text[i]])) << 1;\n                oldR = tmp;\n            }\n\n            // If the pattern has been found, return the index.\n            // Check the most significant bit in the register.\n            // If it's 0, then the pattern has been found.\n            if ((r[threshold] & 1 << len) == 0)\n            {\n                // The pattern has been found.\n                // Return the index of the first character in the pattern.\n                return i - len + 1;\n            }\n        }\n\n        // The pattern has not been found.\n        return -1;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/PatternMatching/BoyerMoore.cs",
    "content": "namespace Algorithms.Strings.PatternMatching;\n\n/// <summary>\n///     The idea:   You compare the pattern with the text from right to left.\n///     If the text symbol that is compared with the rightmost pattern symbol\n///     does not occur in the pattern at all, then the pattern can be shifted\n///     by m positions behind this text symbol.\n///     Complexity:\n///     Time:   Preprocessing: O(m²)\n///     Comparison: O(mn)\n///     Space:  O(m + a)\n///     where   m - pattern length\n///     n - text length\n///     a - alphabet length.\n///     Source:     https://www.inf.hs-flensburg.de/lang/algorithmen/pattern/bmen.htm\n///     https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string-search_algorithm.\n/// </summary>\npublic static class BoyerMoore\n{\n    /// <summary>\n    ///     Finds the index of the first occurrence of the pattern <c>p</c> in <c>t</c>.\n    /// </summary>\n    /// <param name=\"t\">Input text.</param>\n    /// <param name=\"p\">Search pattern.</param>\n    /// <returns>Index of the pattern in text or -1 if the pattern  was not found.</returns>\n    public static int FindFirstOccurrence(string t, string p)\n    {\n        // Pattern length\n        var m = p.Length;\n\n        // Text length\n        var n = t.Length;\n\n        // For each symbol of the alphabet, the position of its rightmost occurrence in the pattern,\n        // or -1 if the symbol does not occur in the pattern.\n        int[] badChar = BadCharacterRule(p, m);\n\n        // Each entry goodSuffix[i] contains the shift distance of the pattern\n        // if a mismatch at position i – 1 occurs, i.e. if the suffix of the pattern starting at position i has matched.\n        int[] goodSuffix = GoodSuffixRule(p, m);\n\n        // Index in text\n        var i = 0;\n\n        // Index in pattern\n        int j;\n\n        while (i <= n - m)\n        {\n            // Starting at end of pattern\n            j = m - 1;\n\n            // While matching\n            while (j >= 0 && p[j] == t[i + j])\n            {\n                j--;\n            }\n\n            // Pattern found\n            if (j < 0)\n            {\n                return i;\n            }\n\n            // Pattern is shifted by the maximum of the values\n            // given by the good-suffix and the bad-character heuristics\n            i += Math.Max(goodSuffix[j + 1], j - badChar[t[i + j]]);\n        }\n\n        // Pattern not found\n        return -1;\n    }\n\n    /// <summary>\n    ///     Finds out the position of its rightmost occurrence in the pattern for each symbol of the alphabet,\n    ///     or -1 if the symbol does not occur in the pattern.\n    /// </summary>\n    /// <param name=\"p\">Search pattern.</param>\n    /// <param name=\"m\">Length of the pattern.</param>\n    /// <returns>Array of the named postition for each symbol of the alphabet.</returns>\n    private static int[] BadCharacterRule(string p, int m)\n    {\n        // For each character (note that there are more than 256 characters)\n        int[] badChar = new int[256];\n        Array.Fill(badChar, -1);\n\n        // Iterate from left to right over the pattern\n        for (var j = 0; j < m; j++)\n        {\n            badChar[p[j]] = j;\n        }\n\n        return badChar;\n    }\n\n    /// <summary>\n    ///     Finds out the shift distance of the pattern if a mismatch at position i – 1 occurs\n    ///     for each character of the pattern, i.e. if the suffix of the pattern starting at position i has matched.\n    /// </summary>\n    /// <param name=\"p\">Search pattern.</param>\n    /// <param name=\"m\">Length of the pattern.</param>\n    /// <returns>Array of the named shift distance for each character of the pattern.</returns>\n    private static int[] GoodSuffixRule(string p, int m)\n    {\n        // CASE 1\n        // The matching suffix occurs somewhere else in the pattern\n        // --> matching suffix is a border of a suffix of the pattern\n\n        // f[i] contains starting position of the widest border of the suffix of the pattern beginning at position i\n        int[] f = new int[p.Length + 1];\n\n        // Suffix of p[m] has no border --> f[m] = m+1\n        f[m] = m + 1;\n\n        // Corresponding shift distance\n        int[] s = new int[p.Length + 1];\n\n        // Start of suffix including border of the pattern\n        // (hint: https://www.inf.hs-flensburg.de/lang/algorithmen/pattern/kmpen.htm#section2)\n        var i = m;\n\n        // Start of suffix of the pattern\n        var j = m + 1;\n\n        while (i > 0)\n        {\n            // checking if a shorter border that is already known can be extended to the left by the same symbol\n            while (j <= m && p[i - 1] != p[j - 1])\n            {\n                if (s[j] == 0)\n                {\n                    s[j] = j - i;\n                }\n\n                j = f[j];\n            }\n\n            --i;\n            --j;\n            f[i] = j;\n        }\n\n        // CASE 2\n        // Only a part of the matching suffix occurs at the beginning of the pattern\n        // (filling remaining entries)\n        j = f[0];\n        for (i = 0; i <= m; i++)\n        {\n            // Starting postition of the greates border\n            if (s[i] == 0)\n            {\n                s[i] = j;\n            }\n\n            // From position i = j, it switches to the next narrower border f[j]\n            if (i == j)\n            {\n                j = f[j];\n            }\n        }\n\n        return s;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs",
    "content": "namespace Algorithms.Strings.PatternMatching;\n\npublic class KnuthMorrisPrattSearcher\n{\n    /// <summary>\n    ///     An implementation of Knuth–Morris–Pratt Algorithm.\n    ///     Worst case time complexity: O(n + k)\n    ///     where n - text length, k - pattern length.\n    /// </summary>\n    /// <param name=\"str\">The string to look in.</param>\n    /// <param name=\"pat\">The pattern to look for.</param>\n    /// <returns>\n    ///     The zero-based positions of all occurrences of <paramref name=\"pat\" /> in <paramref name=\"str\" />.\n    /// </returns>\n    public IEnumerable<int> FindIndexes(string str, string pat)\n    {\n        var lps = FindLongestPrefixSuffixValues(pat);\n\n        for (int i = 0, j = 0; i < str.Length;)\n        {\n            if (pat[j] == str[i])\n            {\n                j++;\n                i++;\n            }\n\n            if (j == pat.Length)\n            {\n                yield return i - j;\n                j = lps[j - 1];\n                continue;\n            }\n\n            if (i < str.Length && pat[j] != str[i])\n            {\n                if (j != 0)\n                {\n                    j = lps[j - 1];\n                }\n                else\n                {\n                    i += 1;\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Return the longest prefix suffix values for pattern.\n    /// </summary>\n    /// <param name=\"pat\">pattern to seek.</param>\n    /// <returns>The longest prefix suffix values for <paramref name=\"pat\" />.</returns>\n    public int[] FindLongestPrefixSuffixValues(string pat)\n    {\n        var lps = new int[pat.Length];\n        for (int i = 1, len = 0; i < pat.Length;)\n        {\n            if (pat[i] == pat[len])\n            {\n                len++;\n                lps[i] = len;\n                i++;\n                continue;\n            }\n\n            if (len != 0)\n            {\n                len = lps[len - 1];\n            }\n            else\n            {\n                lps[i] = 0;\n                i++;\n            }\n        }\n\n        return lps;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/PatternMatching/NaiveStringSearch.cs",
    "content": "// Implements the traditional naive string matching algorithm in C# for TheAlgorithms/C-Sharp.\nnamespace Algorithms.Strings.PatternMatching;\n\n/// <summary>\n///     Implements the traditional naive string matching algorithm in C#.\n/// </summary>\npublic static class NaiveStringSearch\n{\n    /// <summary>\n    ///     NaiveSearch(Content, Pattern) will return an array containing each index of Content in which Pattern appears.\n    ///     Cost:  O(n*m).\n    /// </summary>\n    /// <param name=\"content\">The text body across which to search for a given pattern.</param>\n    /// <param name=\"pattern\">The pattern against which to check the given text body.</param>\n    /// <returns>Array containing each index of Content in which Pattern appears.</returns>\n    public static int[] NaiveSearch(string content, string pattern)\n    {\n        var m = pattern.Length;\n        var n = content.Length;\n        List<int> indices = [];\n        for (var e = 0; e <= n - m; e++)\n        {\n            int j;\n            for (j = 0; j < m; j++)\n            {\n                if (content[e + j] != pattern[j])\n                {\n                    break;\n                }\n            }\n\n            if (j == m)\n            {\n                indices.Add(e);\n            }\n        }\n\n        return indices.ToArray();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/PatternMatching/RabinKarp.cs",
    "content": "namespace Algorithms.Strings.PatternMatching;\n\n/// <summary>\n///     The idea: You calculate the hash for the pattern <c>p</c> and the hash values for all the prefixes of the text\n///     <c>t</c>.\n///     Now, you can compare a substring in constant time using the calculated hashes.\n///     time complexity: O(p + t),\n///     space complexity: O(t),\n///     where   t - text length\n///     p - pattern length.\n/// </summary>\npublic static class RabinKarp\n{\n    /// <summary>\n    ///     Finds the index of all occurrences of the pattern <c>p</c> int <c>t</c>.\n    /// </summary>\n    /// <returns>List of starting indices of the pattern in the text.</returns>\n    public static List<int> FindAllOccurrences(string text, string pattern)\n    {\n        // Prime number\n        const ulong p = 65537;\n\n        // Modulo coefficient\n        const ulong m = (ulong)1e9 + 7;\n\n        // p_pow[i] = P^i mod M\n        ulong[] pPow = new ulong[Math.Max(pattern.Length, text.Length)];\n        pPow[0] = 1;\n        for (var i = 1; i < pPow.Length; i++)\n        {\n            pPow[i] = pPow[i - 1] * p % m;\n        }\n\n        // hash_t[i] is the sum of the previous hash values of the letters (t[0], t[1], ..., t[i-1]) and the hash value of t[i] itself (mod M).\n        // The hash value of a letter t[i] is equal to the product of t[i] and p_pow[i] (mod M).\n        ulong[] hashT = new ulong[text.Length + 1];\n        for (var i = 0; i < text.Length; i++)\n        {\n            hashT[i + 1] = (hashT[i] + text[i] * pPow[i]) % m;\n        }\n\n        // hash_s is equal to sum of the hash values of the pattern (mod M).\n        ulong hashS = 0;\n        for (var i = 0; i < pattern.Length; i++)\n        {\n            hashS = (hashS + pattern[i] * pPow[i]) % m;\n        }\n\n        // In the next step you iterate over the text with the pattern.\n        List<int> occurrences = [];\n        for (var i = 0; i + pattern.Length - 1 < text.Length; i++)\n        {\n            // In each step you calculate the hash value of the substring to be tested.\n            // By storing the hash values of the letters as a prefixes you can do this in constant time.\n            var currentHash = (hashT[i + pattern.Length] + m - hashT[i]) % m;\n\n            // Now you can compare the hash value of the substring with the product of the hash value of the pattern and p_pow[i].\n            if (currentHash == hashS * pPow[i] % m)\n            {\n                // If the hash values are identical, do a double-check in case a hash collision occurs.\n                var j = 0;\n                while (j < pattern.Length && text[i + j] == pattern[j])\n                {\n                    ++j;\n                }\n\n                if (j == pattern.Length)\n                {\n                    // If the hash values are identical and the double-check passes, a substring was found that matches the pattern.\n                    // In this case you add the index i to the list of occurences.\n                    occurrences.Add(i);\n                }\n            }\n        }\n\n        return occurrences;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/PatternMatching/WildCardMatcher.cs",
    "content": "namespace Algorithms.Strings.PatternMatching;\n\n/// <summary>\n///     Implentation of regular expression matching with support for '.' and '*'.\n///     '.' Matches any single character.\n///     '*' Matches zero or more of the preceding element.\n///     The matching should cover the entire input string (not partial).\n/// </summary>\npublic static class WildCardMatcher\n{\n    /// <summary>\n    ///    Using bottom-up dynamic programming for matching the input string with the pattern.\n    ///\n    ///    Time complexity: O(n*m), where n is the length of the input string and m is the length of the pattern.\n    ///\n    ///    Constrain: The pattern cannot start with '*'.\n    /// </summary>\n    /// <param name=\"inputString\">The input string to match.</param>\n    /// <param name=\"pattern\">The pattern to match.</param>\n    /// <returns>True if the input string matches the pattern, false otherwise.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown when the pattern starts with '*'.</exception>\n    public static bool MatchPattern(string inputString, string pattern)\n    {\n        if (pattern.Length > 0 && pattern[0] == '*')\n        {\n            throw new ArgumentException(\"Pattern cannot start with *\");\n        }\n\n        var inputLength = inputString.Length + 1;\n        var patternLength = pattern.Length + 1;\n\n        // DP 2d matrix, where dp[i, j] is true if the first i characters in the input string match the first j characters in the pattern\n        // This DP is initialized to all falses, as it is the default value for a boolean.\n        var dp = new bool[inputLength, patternLength];\n\n        // Empty string and empty pattern are a match\n        dp[0, 0] = true;\n\n        // Since the empty string can only match a pattern that has a * in it, we need to initialize the first row of the DP matrix\n        for (var j = 1; j < patternLength; j++)\n        {\n            if (pattern[j - 1] == '*')\n            {\n                dp[0, j] = dp[0, j - 2];\n            }\n        }\n\n        // Now using bottom-up approach to find for all remaining lenghts of input and pattern\n        for (var i = 1; i < inputLength; i++)\n        {\n            for (var j = 1; j < patternLength; j++)\n            {\n                MatchRemainingLenghts(inputString, pattern, dp, i, j);\n            }\n        }\n\n        return dp[inputLength - 1, patternLength - 1];\n    }\n\n    // Helper method to match the remaining lengths of the input string and the pattern\n    // This method is called for all i and j where i > 0 and j > 0\n    private static void MatchRemainingLenghts(string inputString, string pattern, bool[,] dp, int i, int j)\n    {\n        // If the characters match or the pattern has a ., then the result is the same as the previous positions.\n        if (inputString[i - 1] == pattern[j - 1] || pattern[j - 1] == '.')\n        {\n            dp[i, j] = dp[i - 1, j - 1];\n        }\n        else if (pattern[j - 1] == '*')\n        {\n            MatchForZeroOrMore(inputString, pattern, dp, i, j);\n        }\n        else\n        {\n            // If the characters do not match, then the result is false, which is the default value.\n        }\n    }\n\n    // Helper method to match for the \"*\" pattern.\n    private static void MatchForZeroOrMore(string inputString, string pattern, bool[,] dp, int i, int j)\n    {\n        if (dp[i, j - 2])\n        {\n            dp[i, j] = true;\n        }\n        else if (inputString[i - 1] == pattern[j - 2] || pattern[j - 2] == '.')\n        {\n            dp[i, j] = dp[i - 1, j];\n        }\n        else\n        {\n            // Leave the default value of false\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/PatternMatching/ZblockSubstringSearch.cs",
    "content": "namespace Algorithms.Strings.PatternMatching;\n\n/// <summary>Implementation Z-block substring search.\n/// </summary>\npublic static class ZblockSubstringSearch\n{\n    /// <summary>\n    ///     This algorithm finds all occurrences of a pattern in a text in linear time - O(m+n).\n    /// </summary>\n    public static int FindSubstring(string pattern, string text)\n    {\n        var concatStr = $\"{pattern}${text}\";\n        var patternLength = pattern.Length;\n        var n = concatStr.Length;\n        var zArray = new int[n];\n\n        var left = 0;\n        var right = 0;\n\n        for(var i = 1; i < n; i++)\n        {\n            if(i > right)\n            {\n                left = i;\n                right = ComputeNewRightValue(concatStr, n, left, i);\n\n                zArray[i] = right - left;\n                right--;\n            }\n            else\n            {\n                var k = i - left;\n                if (zArray[k] < (right - i + 1))\n                {\n                    zArray[i] = zArray[k];\n                }\n                else\n                {\n                    left = i;\n                    right = ComputeNewRightValue(concatStr, n, left, right);\n                    zArray[i] = right - left;\n                    right--;\n                }\n            }\n        }\n\n        var found = 0;\n        foreach(var z_value in zArray)\n        {\n            if(z_value == patternLength)\n            {\n                found++;\n            }\n        }\n\n        return found;\n    }\n\n    private static int ComputeNewRightValue(string concatStr, int n, int left, int right)\n    {\n        while (right < n && concatStr[right - left].Equals(concatStr[right]))\n        {\n            right++;\n        }\n\n        return right;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/Permutation.cs",
    "content": "namespace Algorithms.Strings;\n\npublic static class Permutation\n{\n    /// <summary>\n    /// Returns every anagram of a given word.\n    /// </summary>\n    /// <returns>List of anagrams.</returns>\n    public static List<string> GetEveryUniquePermutation(string word)\n    {\n        if (word.Length < 2)\n        {\n            return\n            [\n                word,\n            ];\n        }\n\n        var result = new HashSet<string>();\n\n        for (var i = 0; i < word.Length; i++)\n        {\n            var temp = GetEveryUniquePermutation(word.Remove(i, 1));\n\n            result.UnionWith(temp.Select(subPerm => word[i] + subPerm));\n        }\n\n        return result.ToList();\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/Similarity/CosineSimilarity.cs",
    "content": "﻿namespace Algorithms.Strings.Similarity;\n\npublic static class CosineSimilarity\n{\n    /// <summary>\n    /// Calculates the Cosine Similarity between two strings.\n    /// Cosine Similarity is a measure of similarity between two non-zero vectors of an inner product space.\n    /// It measures the cosine of the angle between the two vectors.\n    /// </summary>\n    /// <param name=\"left\">The first string.</param>\n    /// <param name=\"right\">The second string.</param>\n    /// <returns>\n    /// A double value between 0 and 1 that represents the similarity\n    /// of the two strings.\n    /// </returns>\n    public static double Calculate(string left, string right)\n    {\n        // Step 1: Get the vectors for the two strings\n        // Each vector represents the frequency of each character in the string.\n        var vectors = GetVectors(left.ToLowerInvariant(), right.ToLowerInvariant());\n        var leftVector = vectors.LeftVector;\n        var rightVector = vectors.RightVector;\n\n        // Step 2: Calculate the intersection of the two vectors\n        // The intersection is the set of characters that appear in both strings.\n        var intersection = GetIntersection(leftVector, rightVector);\n\n        // Step 3: Calculate the dot product of the two vectors\n        // The dot product is the sum of the products of the corresponding values of the characters in the intersection.\n        var dotProduct = DotProduct(leftVector, rightVector, intersection);\n\n        // Step 4: Calculate the square magnitude of each vector\n        // The magnitude is the square root of the sum of the squares of the values in the vector.\n        var mLeft = 0.0;\n        foreach (var value in leftVector.Values)\n        {\n            mLeft += value * value;\n        }\n\n        var mRight = 0.0;\n        foreach (var value in rightVector.Values)\n        {\n            mRight += value * value;\n        }\n\n        // Step 5: Check if either vector is zero\n        // If either vector is zero (i.e., all characters are unique), the Cosine Similarity is 0.\n        if (mLeft <= 0 || mRight <= 0)\n        {\n            return 0.0;\n        }\n\n        // Step 6: Calculate and return the Cosine Similarity\n        // The Cosine Similarity is the dot product divided by the product of the magnitudes.\n        return dotProduct / (Math.Sqrt(mLeft) * Math.Sqrt(mRight));\n    }\n\n    /// <summary>\n    /// Calculates the vectors for the given strings.\n    /// </summary>\n    /// <param name=\"left\">The first string.</param>\n    /// <param name=\"right\">The second string.</param>\n    /// <returns>A tuple containing the vectors for the two strings.</returns>\n    private static (Dictionary<char, int> LeftVector, Dictionary<char, int> RightVector) GetVectors(string left, string right)\n    {\n        var leftVector = new Dictionary<char, int>();\n        var rightVector = new Dictionary<char, int>();\n\n        // Calculate the frequency of each character in the left string\n        foreach (var character in left)\n        {\n            leftVector.TryGetValue(character, out var frequency);\n            leftVector[character] = ++frequency;\n        }\n\n        // Calculate the frequency of each character in the right string\n        foreach (var character in right)\n        {\n            rightVector.TryGetValue(character, out var frequency);\n            rightVector[character] = ++frequency;\n        }\n\n        return (leftVector, rightVector);\n    }\n\n    /// <summary>\n    /// Calculates the dot product between two vectors represented as dictionaries of character frequencies.\n    /// The dot product is the sum of the products of the corresponding values of the characters in the intersection of the two vectors.\n    /// </summary>\n    /// <param name=\"leftVector\">The vector of the left string.</param>\n    /// <param name=\"rightVector\">The vector of the right string.</param>\n    /// <param name=\"intersection\">The intersection of the two vectors, represented as a set of characters.</param>\n    /// <returns>The dot product of the two vectors.</returns>\n    private static double DotProduct(Dictionary<char, int> leftVector, Dictionary<char, int> rightVector, HashSet<char> intersection)\n    {\n        // Initialize the dot product to 0\n        double dotProduct = 0;\n\n        // Iterate over each character in the intersection of the two vectors\n        foreach (var character in intersection)\n        {\n            // Calculate the product of the corresponding values of the characters in the left and right vectors\n            dotProduct += leftVector[character] * rightVector[character];\n        }\n\n        // Return the dot product\n        return dotProduct;\n    }\n\n    /// <summary>\n    /// Calculates the intersection of two vectors, represented as dictionaries of character frequencies.\n    /// </summary>\n    /// <param name=\"leftVector\">The vector of the left string.</param>\n    /// <param name=\"rightVector\">The vector of the right string.</param>\n    /// <returns>A HashSet containing the characters that appear in both vectors.</returns>\n    private static HashSet<char> GetIntersection(Dictionary<char, int> leftVector, Dictionary<char, int> rightVector)\n    {\n        // Initialize a HashSet to store the intersection of the two vectors.\n        var intersection = new HashSet<char>();\n\n        // Iterate over each key-value pair in the left vector.\n        foreach (var kvp in leftVector)\n        {\n            // If the right vector contains the same key, add it to the intersection.\n            if (rightVector.ContainsKey(kvp.Key))\n            {\n                intersection.Add(kvp.Key);\n            }\n        }\n\n        return intersection;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs",
    "content": "﻿namespace Algorithms.Strings.Similarity;\n\npublic static class DamerauLevenshteinDistance\n{\n    /// <summary>\n    /// Calculates the Damerau-Levenshtein distance between two strings.\n    /// The Damerau-Levenshtein distance is a string metric for measuring the difference between two sequences.\n    /// It is calculated as the minimum number of operations needed to transform one sequence into the other.\n    /// The possible operations are insertion, deletion, substitution, and transposition.\n    /// </summary>\n    /// <param name=\"left\">The first string.</param>\n    /// <param name=\"right\">The second string.</param>\n    /// <returns>The Damerau-Levenshtein distance between the two strings.</returns>\n    public static int Calculate(string left, string right)\n    {\n        // Get the lengths of the input strings.\n        var leftSize = left.Length;\n        var rightSize = right.Length;\n\n        // Initialize a matrix of distances between the two strings.\n        var distances = InitializeDistanceArray(leftSize, rightSize);\n\n        // Iterate over each character in the left string.\n        for (var i = 1; i < leftSize + 1; i++)\n        {\n            // Iterate over each character in the right string.\n            for (var j = 1; j < rightSize + 1; j++)\n            {\n                // Calculate the cost of the current operation.\n                // If the characters at the current positions are the same, the cost is 0.\n                // Otherwise, the cost is 1.\n                var cost = left[i - 1] == right[j - 1] ? 0 : 1;\n\n                // Calculate the minimum distance by considering three possible operations:\n                // deletion, insertion, and substitution.\n                distances[i, j] = Math.Min(\n                    Math.Min(// deletion\n                        distances[i - 1, j] + 1, // delete the character from the left string\n                        distances[i, j - 1] + 1), // insert the character into the right string\n                    distances[i - 1, j - 1] + cost); // substitute the character in the left string with the character in the right string\n\n                // If the current character in the left string is the same as the character\n                // two positions to the left in the right string and the current character\n                // in the right string is the same as the character one position to the right\n                // in the left string, then we can also consider a transposition operation.\n                if (i > 1 && j > 1 && left[i - 1] == right[j - 2] && left[i - 2] == right[j - 1])\n                {\n                    distances[i, j] = Math.Min(\n                        distances[i, j], // current minimum distance\n                        distances[i - 2, j - 2] + cost); // transpose the last two characters\n                }\n            }\n        }\n\n        // Return the distance between the two strings.\n        return distances[leftSize, rightSize];\n    }\n\n    /// <summary>\n    /// Initializes a matrix of distances between two string representations.\n    ///\n    /// This method creates a matrix of distances where the dimensions are one larger\n    /// than the input strings. The first row of the matrix represents the distances\n    /// when the left string is empty, and the first column represents the distances\n    /// when the right string is empty. The values in the first row and first column\n    /// are the lengths of the corresponding strings.\n    ///\n    /// The matrix is used by the Damerau-Levenshtein algorithm to calculate the\n    /// minimum number of single-character edits (insertions, deletions, or substitutions)\n    /// required to change one word into the other.\n    /// The matrix is initialized with dimensions one larger than the input strings.\n    /// The first row of the matrix represents the distances when the left string is empty.\n    /// The first column of the matrix represents the distances when the right string is empty.\n    /// The values in the first row and first column are the lengths of the corresponding strings.\n    /// Initializes a matrix of distances between two strings representations.\n    /// </summary>\n    /// <param name=\"leftSize\">The size of the left string.</param>\n    /// <param name=\"rightSize\">The size of the right string.</param>\n    /// <returns>A matrix of distances.</returns>\n    private static int[,] InitializeDistanceArray(int leftSize, int rightSize)\n    {\n        // Initialize a matrix of distances with dimensions one larger than the input strings.\n        var matrix = new int[leftSize + 1, rightSize + 1];\n\n        // Set the values in the first row to the lengths of the left string.\n        // This represents the distance when the left string is empty.\n        for (var i = 1; i < leftSize + 1; i++)\n        {\n            matrix[i, 0] = i;\n        }\n\n        // Set the values in the first column to the lengths of the right string.\n        // This represents the distance when the right string is empty.\n        for (var i = 1; i < rightSize + 1; i++)\n        {\n            matrix[0, i] = i;\n        }\n\n        // Return the initialized matrix of distances.\n        return matrix;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/Similarity/HammingDistance.cs",
    "content": "namespace Algorithms.Strings.Similarity;\n\n/// <summary>\n///     <para>\n///         Hamming distance between two strings of equal length is the number of positions at which the corresponding symbols are different.\n///         Time complexity is O(n) where n is the length of the string.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Hamming_distance.\n///     </para>\n/// </summary>\npublic static class HammingDistance\n{\n    /// <summary>\n    ///     Calculates Hamming distance between two strings of equal length.\n    /// </summary>\n    /// <param name=\"s1\">First string.</param>\n    /// <param name=\"s2\">Second string.</param>\n    /// <returns>Levenshtein distance between source and target strings.</returns>\n    public static int Calculate(string s1, string s2)\n    {\n        if (s1.Length != s2.Length)\n        {\n            throw new ArgumentException(\"Strings must be equal length.\");\n        }\n\n        var distance = 0;\n        for (var i = 0; i < s1.Length; i++)\n        {\n            distance += s1[i] != s2[i] ? 1 : 0;\n        }\n\n        return distance;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/Similarity/JaccardDistance.cs",
    "content": "﻿namespace Algorithms.Strings.Similarity;\n\n/// <summary>\n///  <para>\n/// Jaccard distance is a measure of two sets of data are. It is calculated by subtracting the Jaccard similarity\n/// coefficient from 1, or, equivalently by dividing the difference of the sizes of the union and intersection of two sets\n/// by the size of the union.\n/// </para>\n/// <para>\n/// For example, suppose we have two sets of words:\n/// <list type=\"bullet\">\n/// <item>\n/// A = {apple, banana, cherry, date}\n/// </item>\n/// <item>\n/// B = {banana, cherry, elderberry, fig}\n/// </item>\n/// </list>\n/// </para>\n/// <para>\n/// The number of common elements in both sets is 2 (banana and cherry). The number of elements in either set is 6\n/// (apple, banana, cherry, date, elderberry, fig).\n/// </para>\n/// <para>\n/// The Jaccard similarity coefficient is 2 / 6 = 0.333333 or 33.333% similarity.\n/// </para>\n/// <para>\n/// The Jaccard distance is 1 - 0.33333 = 0.66667. This means that the two sets are about 67% different.\n/// </para>\n/// <para>\n/// Jaccard distance is commonly used to calculate a matrix of clustering and multidimensional scaling of sample tests.\n/// </para>\n/// </summary>\npublic class JaccardDistance\n{\n    private readonly JaccardSimilarity jaccardSimilarity = new();\n\n    /// <summary>\n    /// Calculate the Jaccard distance between to strings.\n    /// </summary>\n    /// <param name=\"left\">The first string.</param>\n    /// <param name=\"right\">The second string.</param>\n    /// <returns>The Jaccard distance.</returns>\n    public double Calculate(string left, string right)\n    {\n        return 1.0 - jaccardSimilarity.Calculate(left, right);\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/Similarity/JaccardSimilarity.cs",
    "content": "﻿namespace Algorithms.Strings.Similarity;\n\n/// <summary>\n///  <para>\n/// Jaccard similarity is a statistic that measures how similar two sets of data are. It is calculated by dividing\n/// the number of common elements in both sets by the number of elements in either set. More formally, it is the\n/// quotient of the division of the size of the size of the intersection divided by the size of the union of two sets.\n/// </para>\n/// <para>\n/// The result is a value between 0 and 1, where 0 means no similarity and 1 means perfect similarity.\n/// </para>\n/// <para>\n/// For example, suppose we have two sets of words:\n/// <list type=\"bullet\">\n/// <item>\n/// A = {apple, banana, cherry, date}\n/// </item>\n/// <item>\n/// B = {banana, cherry, elderberry, fig}\n/// </item>\n/// </list>\n/// </para>\n/// <para>\n/// The number of common elements in both sets is 2 (banana and cherry). The number of elements in either set is 6\n/// (apple, banana, cherry, date, elderberry, fig).\n/// </para>\n/// <para>\n/// The Jaccard similarity coefficient is 2 / 6 = 0.333333 or 33.333% similarity.\n/// </para>\n/// </summary>\npublic class JaccardSimilarity\n{\n    /// <summary>\n    /// Calculates the Jaccard similarity coefficient between two strings.\n    /// </summary>\n    /// <param name=\"left\">The first string to compare.</param>\n    /// <param name=\"right\">The second string to compare.</param>\n    /// <returns>A double value between 0 and 1 that represents the similarity of the two strings.</returns>\n    /// <exception cref=\"ArgumentNullException\">Thrown when either the input is null.</exception>\n    /// <remarks>\n    /// This method uses a HashSet to represent the sets of characters in the input strings.\n    /// </remarks>\n    public double Calculate(string left, string right)\n    {\n        // Validate the input strings before proceeding.\n        ValidateInput(left, right);\n\n        // Get the lengths of the input strings.\n        var leftLength = left.Length;\n        var rightLength = right.Length;\n\n        // If both strings are empty, return 1.0 as the similarity coefficient.\n        if (leftLength == 0 && rightLength == 0)\n        {\n            return 1.0d;\n        }\n\n        // If either string is empty, return 0.0 as the similarity coefficient.\n        if (leftLength == 0 || rightLength == 0)\n        {\n            return 0.0d;\n        }\n\n        // Get the unique characters in each string.\n        var leftSet = new HashSet<char>(left);\n        var rightSet = new HashSet<char>(right);\n\n        // Get the union of the two strings.\n        var unionSet = new HashSet<char>(leftSet);\n        foreach (var c in rightSet)\n        {\n            unionSet.Add(c);\n        }\n\n        // Calculate the intersection size of the two strings.\n        var intersectionSize = leftSet.Count + rightSet.Count - unionSet.Count;\n\n        // Return the Jaccard similarity coefficient as the ratio of intersection to union.\n        return 1.0d * intersectionSize / unionSet.Count;\n    }\n\n    /// <summary>\n    /// Validates the input strings and throws an exception if either is null.\n    /// </summary>\n    /// <param name=\"left\">The first string to validate.</param>\n    /// <param name=\"right\">The second string to validate.</param>\n    private void ValidateInput(string left, string right)\n    {\n        if (left == null || right == null)\n        {\n            var paramName = left == null ? nameof(left) : nameof(right);\n            throw new ArgumentNullException(paramName, \"Input cannot be null\");\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/Similarity/JaroSimilarity.cs",
    "content": "namespace Algorithms.Strings.Similarity;\n\n/// <summary>\n///     <para>\n///         Jaro Similarity measures how similar two strings are.\n///         Result is between 0 and 1 where 0 represnts that there is no similarity between strings and 1 represents equal strings.\n///         Time complexity is O(a*b) where a is the length of the first string and b is the length of the second string.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance#Jaro_similarity.\n///     </para>\n/// </summary>\npublic static class JaroSimilarity\n{\n    /// <summary>\n    ///     Calculates Jaro Similarity between two strings.\n    /// </summary>\n    /// <param name=\"s1\">First string.</param>\n    /// <param name=\"s2\">Second string.</param>\n    public static double Calculate(string s1, string s2)\n    {\n        if (s1 == s2)\n        {\n            return 1;\n        }\n\n        var longerString = s1.Length > s2.Length ? s1 : s2;\n        var shorterString = s1.Length < s2.Length ? s1 : s2;\n\n        // will look for matching characters in this range\n        var matchingCharacterRange = Math.Max((longerString.Length / 2) - 1, 0);\n        var matches = 0d;\n\n        // true if i-th index of s1 was matched in s2\n        var s1MatchedIndeces = new bool[s1.Length];\n\n        // true if i-th index of s2 was matched in s1\n        var s2MatchedIndeces = new bool[s2.Length];\n\n        for (var i = 0; i < longerString.Length; i++)\n        {\n            var startIndex = Math.Max(i - matchingCharacterRange, 0);\n            var endIndex = Math.Min(i + matchingCharacterRange, shorterString.Length - 1);\n            for (var j = startIndex; j <= endIndex; j++)\n            {\n                if (s1[i] == s2[j] && !s2MatchedIndeces[j])\n                {\n                    matches++;\n                    s1MatchedIndeces[i] = true;\n                    s2MatchedIndeces[j] = true;\n                    break;\n                }\n            }\n        }\n\n        if (matches == 0)\n        {\n            return 0;\n        }\n\n        var transpositions = CalculateTranspositions(s1, s2, s1MatchedIndeces, s2MatchedIndeces);\n\n        return ((matches / s1.Length) + (matches / s2.Length) + ((matches - transpositions) / matches)) / 3;\n    }\n\n    /// <summary>\n    ///     Calculates number of matched characters that are not in the right order.\n    /// </summary>\n    private static int CalculateTranspositions(string s1, string s2, bool[] s1MatchedIndeces, bool[] s2MatchedIndeces)\n    {\n        var transpositions = 0;\n        var s2Index = 0;\n        for (var s1Index = 0; s1Index < s1.Length; s1Index++)\n        {\n            if (s1MatchedIndeces[s1Index])\n            {\n                while (!s2MatchedIndeces[s2Index])\n                {\n                    s2Index++;\n                }\n\n                if (s1[s1Index] != s2[s2Index])\n                {\n                    transpositions++;\n                }\n\n                s2Index++;\n            }\n        }\n\n        transpositions /= 2;\n        return transpositions;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/Similarity/JaroWinklerDistance.cs",
    "content": "namespace Algorithms.Strings.Similarity;\n\n/// <summary>\n///     <para>\n///         Jaro–Winkler distance is a string metric measuring an edit distance between two sequences.\n///         The score is normalized such that 1 means an exact match and 0 means there is no similarity.\n///         Time complexity is O(a*b) where a is the length of the first string and b is the length of the second string.\n///     </para>\n///     <para>\n///         Wikipedia: https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance.\n///     </para>\n/// </summary>\npublic static class JaroWinklerDistance\n{\n    /// <summary>\n    ///     Calculates Jaro–Winkler distance.\n    /// </summary>\n    /// <param name=\"s1\">First string.</param>\n    /// <param name=\"s2\">Second string.</param>\n    /// <param name=\"scalingFactor\">Scaling factor for how much the score is adjusted upwards for having common prefixes. Default is 0.1.</param>\n    /// <returns>Distance between two strings.</returns>\n    public static double Calculate(string s1, string s2, double scalingFactor = 0.1)\n    {\n        var jaroSimilarity = JaroSimilarity.Calculate(s1, s2);\n        var commonPrefixLength = s1.Zip(s2).Take(4).TakeWhile(x => x.First == x.Second).Count();\n        var jaroWinklerSimilarity = jaroSimilarity + commonPrefixLength * scalingFactor * (1 - jaroSimilarity);\n\n        return 1 - jaroWinklerSimilarity;\n    }\n}\n"
  },
  {
    "path": "Algorithms/Strings/Similarity/OptimalStringAlignment.cs",
    "content": "namespace Algorithms.Strings.Similarity\n{\n    /// <summary>\n    /// Provides methods to calculate the Optimal String Alignment distance between two strings.\n    ///\n    /// The Optimal String Alignment distance, also known as the restricted Damerau-Levenshtein distance,\n    /// is a string metric used to measure the difference between two sequences. It is similar to the\n    /// Levenshtein distance, but it also considers transpositions (swapping of two adjacent characters)\n    /// as a single operation. This metric is particularly useful when adjacent characters are commonly\n    /// transposed, such as in typographical errors.\n    ///\n    /// The OSA distance between two strings is defined as the minimum number of operations required to\n    /// transform one string into the other, where the operations include:\n    ///\n    /// 1. Insertion: Adding a single character.\n    /// 2. Deletion: Removing a single character.\n    /// 3. Substitution: Replacing one character with another.\n    /// 4. Transposition: Swapping two adjacent characters (this is what distinguishes OSA from the\n    ///    traditional Levenshtein distance).\n    ///\n    /// The OSA distance algorithm ensures that no operation is applied more than once to the same\n    /// character in the same position. This is the main difference between the OSA and the more general\n    /// Damerau-Levenshtein distance, which does not have this restriction.\n    ///\n    /// <example>\n    /// Example Usage:\n    /// <code>\n    /// int distance = OptimalStringAlignmentDistance(\"example\", \"exmaple\");\n    /// Console.WriteLine(distance); // Output: 1\n    /// </code>\n    /// In this example, the strings \"example\" and \"exmaple\" differ by one transposition of adjacent characters ('a' and 'm'),\n    /// so the OSA distance is 1.\n    ///\n    /// <code>\n    /// int distance = OptimalStringAlignmentDistance(\"kitten\", \"sitting\");\n    /// Console.WriteLine(distance); // Output: 3\n    /// </code>\n    /// Here, the strings \"kitten\" and \"sitting\" have three differences (substitutions 'k' to 's', 'e' to 'i', and insertion of 'g'),\n    /// resulting in an OSA distance of 3.\n    /// </example>\n    /// </summary>\n    /// <remarks>\n    /// This algorithm has a time complexity of O(n * m), where n and m are the lengths of the two input strings.\n    /// It is efficient for moderate-sized strings but may become computationally expensive for very long strings.\n    /// </remarks>\n    public static class OptimalStringAlignment\n    {\n        /// <summary>\n        /// Calculates the Optimal String Alignment distance between two strings.\n        /// </summary>\n        /// <param name=\"firstString\">The first string.</param>\n        /// <param name=\"secondString\">The second string.</param>\n        /// <returns>The Optimal String Alignment distance between the two strings.</returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when either of the input strings is null.</exception>\n        public static double Calculate(string firstString, string secondString)\n        {\n            ArgumentNullException.ThrowIfNull(nameof(firstString));\n            ArgumentNullException.ThrowIfNull(nameof(secondString));\n\n            if (firstString == secondString)\n            {\n                return 0.0;\n            }\n\n            if (firstString.Length == 0)\n            {\n                return secondString.Length;\n            }\n\n            if (secondString.Length == 0)\n            {\n                return firstString.Length;\n            }\n\n            var distanceMatrix = GenerateDistanceMatrix(firstString.Length, secondString.Length);\n            distanceMatrix = CalculateDistance(firstString, secondString, distanceMatrix);\n\n            return distanceMatrix[firstString.Length, secondString.Length];\n        }\n\n        /// <summary>\n        /// Generates the initial distance matrix for the given lengths of the two strings.\n        /// </summary>\n        /// <param name=\"firstLength\">The length of the first string.</param>\n        /// <param name=\"secondLength\">The length of the second string.</param>\n        /// <returns>The initialized distance matrix.</returns>\n        private static int[,] GenerateDistanceMatrix(int firstLength, int secondLength)\n        {\n            var distanceMatrix = new int[firstLength + 2, secondLength + 2];\n\n            for (var i = 0; i <= firstLength; i++)\n            {\n                distanceMatrix[i, 0] = i;\n            }\n\n            for (var j = 0; j <= secondLength; j++)\n            {\n                distanceMatrix[0, j] = j;\n            }\n\n            return distanceMatrix;\n        }\n\n        /// <summary>\n        /// Calculates the distance matrix for the given strings using the Optimal String Alignment algorithm.\n        /// </summary>\n        /// <param name=\"firstString\">The first string.</param>\n        /// <param name=\"secondString\">The second string.</param>\n        /// <param name=\"distanceMatrix\">The initial distance matrix.</param>\n        /// <returns>The calculated distance matrix.</returns>\n        private static int[,] CalculateDistance(string firstString, string secondString, int[,] distanceMatrix)\n        {\n            for (var i = 1; i <= firstString.Length; i++)\n            {\n                for (var j = 1; j <= secondString.Length; j++)\n                {\n                    var cost = 1;\n\n                    if (firstString[i - 1] == secondString[j - 1])\n                    {\n                        cost = 0;\n                    }\n\n                    distanceMatrix[i, j] = Minimum(\n                        distanceMatrix[i - 1, j - 1] + cost, // substitution\n                        distanceMatrix[i, j - 1] + 1, // insertion\n                        distanceMatrix[i - 1, j] + 1); // deletion\n\n                    if (i > 1 && j > 1\n                        && firstString[i - 1] == secondString[j - 2]\n                        && firstString[i - 2] == secondString[j - 1])\n                    {\n                        distanceMatrix[i, j] = Math.Min(\n                            distanceMatrix[i, j],\n                            distanceMatrix[i - 2, j - 2] + cost); // transposition\n                    }\n                }\n            }\n\n            return distanceMatrix;\n        }\n\n        /// <summary>\n        /// Returns the minimum of three integers.\n        /// </summary>\n        /// <param name=\"a\">The first integer.</param>\n        /// <param name=\"b\">The second integer.</param>\n        /// <param name=\"c\">The third integer.</param>\n        /// <returns>The minimum of the three integers.</returns>\n        private static int Minimum(int a, int b, int c)\n        {\n            return Math.Min(a, Math.Min(b, c));\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Algorithms.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <IsPackable>false</IsPackable>\n    <CodeAnalysisRuleSet>..\\stylecop.ruleset</CodeAnalysisRuleSet>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <AdditionalFiles Include=\"..\\stylecop.json\" />\n    <ProjectReference Include=\"..\\Algorithms\\Algorithms.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.0\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"FluentAssertions\" Version=\"6.12.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.8.0\" />\n    <PackageReference Include=\"Moq\" Version=\"4.20.72\" />\n    <PackageReference Include=\"nunit\" Version=\"4.0.1\" />\n    <PackageReference Include=\"NUnit3TestAdapter\" Version=\"4.5.0\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Algorithms.Tests/AssemblyInfo.cs",
    "content": "﻿using NUnit.Framework;\n\n[assembly: Parallelizable(ParallelScope.Children)]\n"
  },
  {
    "path": "Algorithms.Tests/Compressors/BurrowsWheelerTransformTests.cs",
    "content": "using Algorithms.DataCompression;\n\nnamespace Algorithms.Tests.Compressors;\n\npublic class BurrowsWheelerTransformTests\n{\n    [TestCase(\"banana\", \"nnbaaa\", 3)]\n    [TestCase(\"SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES\", \"TEXYDST.E.IXIXIXXSSMPPS.B..E.S.EUSFXDIIOIIIT\", 29)]\n    [TestCase(\"\", \"\", 0)]\n    public void Encode(string input, string expectedString, int expectedIndex)\n    {\n        var bwt = new BurrowsWheelerTransform();\n\n        var (encoded, index) = bwt.Encode(input);\n\n        Assert.That(encoded, Is.EqualTo(expectedString));\n        Assert.That(index, Is.EqualTo(expectedIndex));\n    }\n\n    [TestCase(\"nnbaaa\", 3, \"banana\")]\n    [TestCase(\"TEXYDST.E.IXIXIXXSSMPPS.B..E.S.EUSFXDIIOIIIT\", 29, \"SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES\")]\n    [TestCase(\"\", 0, \"\")]\n    public void Decode(string encoded, int index, string expected)\n    {\n        var bwt = new BurrowsWheelerTransform();\n\n        var result = bwt.Decode(encoded, index);\n\n        Assert.That(result, Is.EqualTo(expected));\n    }\n\n    [Test]\n    [Repeat(100)]\n    public void RandomEncodeDecode()\n    {\n        var bwt = new BurrowsWheelerTransform();\n        var random = new Randomizer();\n        var inputString = random.GetString();\n\n        var (encoded, index) = bwt.Encode(inputString);\n        var result = bwt.Decode(encoded, index);\n\n        Assert.That(result, Is.EqualTo(inputString));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Compressors/HuffmanCompressorTests.cs",
    "content": "using Algorithms.DataCompression;\nusing Algorithms.Sorters.Comparison;\n\nnamespace Algorithms.Tests.Compressors;\n\npublic static class HuffmanCompressorTests\n{\n    [TestCase(\"This is a string\", \"101010110111011101110111100011111010010010010011000\")]\n    [TestCase(\"Hello\", \"1101110010\")]\n    [TestCase(\"dddddddddd\", \"1111111111\")]\n    [TestCase(\"a\", \"1\")]\n    [TestCase(\"\", \"\")]\n    public static void CompressingPhrase(string uncompressedText, string expectedCompressedText)\n    {\n        //Arrange\n        var sorter = new BubbleSorter<HuffmanCompressor.ListNode>();\n        var translator = new Translator();\n        var huffman = new HuffmanCompressor(sorter, translator);\n\n        //Act\n        var (compressedText, decompressionKeys) = huffman.Compress(uncompressedText);\n        var decompressedText = translator.Translate(compressedText, decompressionKeys);\n\n        //Assert\n        Assert.That(compressedText, Is.EqualTo(expectedCompressedText));\n        Assert.That(decompressedText, Is.EqualTo(uncompressedText));\n    }\n\n    [Test]\n    public static void DecompressedTextTheSameAsOriginal(\n        [Random(0, 1000, 100, Distinct = true)]\n        int length)\n    {\n        //Arrange\n        var sorter = new BubbleSorter<HuffmanCompressor.ListNode>();\n        var translator = new Translator();\n        var huffman = new HuffmanCompressor(sorter, translator);\n        var text = Randomizer.CreateRandomizer().GetString(length);\n\n        //Act\n        var (compressedText, decompressionKeys) = huffman.Compress(text);\n        var decompressedText = translator.Translate(compressedText, decompressionKeys);\n\n        //Assert\n        Assert.That(decompressedText, Is.EqualTo(text));\n    }\n\n    [Test]\n    public static void ListNodeComparer_NullIsUnordered()\n    {\n        var comparer = new HuffmanCompressor.ListNodeComparer();\n        var node = new HuffmanCompressor.ListNode('a', 0.1);\n\n        comparer.Compare(node, null).Should().Be(0);\n        comparer.Compare(null, node).Should().Be(0);\n        comparer.Compare(null, null).Should().Be(0);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Compressors/ShannonFanoCompressorTests.cs",
    "content": "using Algorithms.DataCompression;\nusing Algorithms.Knapsack;\n\nnamespace Algorithms.Tests.Compressors;\n\npublic static class ShannonFanoCompressorTests\n{\n    [TestCase(\"dddddddddd\", \"1111111111\")]\n    [TestCase(\"a\", \"1\")]\n    [TestCase(\"\", \"\")]\n    public static void CompressingPhrase(string uncompressedText, string expectedCompressedText)\n    {\n        //Arrange\n        var solver = new NaiveKnapsackSolver<(char, double)>();\n        var translator = new Translator();\n        var shannonFanoCompressor = new ShannonFanoCompressor(solver, translator);\n\n        //Act\n        var (compressedText, decompressionKeys) = shannonFanoCompressor.Compress(uncompressedText);\n        var decompressedText = translator.Translate(compressedText, decompressionKeys);\n\n        //Assert\n        Assert.That(compressedText, Is.EqualTo(expectedCompressedText));\n        Assert.That(decompressedText, Is.EqualTo(uncompressedText));\n    }\n\n    [Test]\n    public static void DecompressedTextTheSameAsOriginal([Random(0, 1000, 100)] int length)\n    {\n        //Arrange\n        var solver = new NaiveKnapsackSolver<(char, double)>();\n        var translator = new Translator();\n        var shannonFanoCompressor = new ShannonFanoCompressor(solver, translator);\n        var text = Randomizer.CreateRandomizer().GetString(length);\n\n        //Act\n        var (compressedText, decompressionKeys) = shannonFanoCompressor.Compress(text);\n        var decompressedText = translator.Translate(compressedText, decompressionKeys);\n\n        //Assert\n        Assert.That(decompressedText, Is.EqualTo(text));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Compressors/TranslatorTests.cs",
    "content": "using Algorithms.DataCompression;\n\nnamespace Algorithms.Tests.Compressors;\n\npublic static class TranslatorTests\n{\n    [Test]\n    public static void TranslateCorrectly()\n    {\n        // Arrange\n        var translator = new Translator();\n        var dict = new Dictionary<string, string>\n        {\n            { \"Hey\", \"Good day\" },\n            { \" \", \" \" },\n            { \"man\", \"sir\" },\n            { \"!\", \".\" },\n        };\n\n        // Act\n        var translatedText = translator.Translate(\"Hey man!\", dict);\n\n        // Assert\n        Assert.That(translatedText, Is.EqualTo(\"Good day sir.\"));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Digests/AsconDigestTests.cs",
    "content": "using Algorithms.Crypto.Digests;\nusing Algorithms.Crypto.Exceptions;\n\nnamespace Algorithms.Tests.Crypto.Digests;\n\n[NonParallelizable]\npublic class AsconDigestTests\n{\n    private readonly AsconDigest asconHash = new AsconDigest(AsconDigest.AsconParameters.AsconHash);\n    private readonly AsconDigest asconHashA = new AsconDigest(AsconDigest.AsconParameters.AsconHashA);\n\n    [TestCase(\"a\", \"02a9d471afab12914197af7090f00d16c41b6e30be0a63bbfd00bc13064de548\")]\n    [TestCase(\"abc\", \"d37fe9f1d10dbcfad8408a6804dbe91124a8912693322bb23ec1701e19e3fd51\")]\n    [TestCase(\"Hello\", \"d80f38d94ad72bd18718879f753a44870e8446925ff64bd7441db5fe020b6c0c\")]\n    [TestCase(\"message digest\", \"e8848979c5adfd21bfcf29e54be1dd085ee523d251e8e6876f2654d6368da0ca\")]\n    [TestCase(\"abcdefghijklmnopqrstuvwxyz\", \"c62368674e1b2301f19f46c50bb7f87a988a3e41205d68ab9d7882d2a15e917b\")]\n    [TestCase(\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\", \"4ff71928d740524735b5ab12bb1598463054f88089f3c5f9760b6bdcd23f897b\")]\n    [TestCase(\"12345678901234567890123456789012345678901234567890123456789012345678901234567890\", \"2dae8b553b93841120e88ee77b9ccb8b512a32318db6012025f3f1c482b1def8\")]\n    public void AsconHash_ReturnsCorrectValue(string input, string expected)\n    {\n        var inputBytes = Encoding.ASCII.GetBytes(input);\n        var result = asconHash.Digest(inputBytes);\n\n        result.Should().Be(expected);\n    }\n\n    [TestCase(\"a\", \"062bb0346671da00da4f460308b4d2c4d9877c3e2827d6229ff5361332d36527\")]\n    [TestCase(\"abc\", \"836a5ddba0142b011ce3425ea9789fd6a21628d619195a48c1540f847667a84e\")]\n    [TestCase(\"Hello\", \"15f245df8af697dc540e86083822809ab7299575d8ad6c2e17ecc603a7ab79dd\")]\n    [TestCase(\"message digest\", \"3f18a1f398a40a77e0e9477aa6cb50e9e1abecff651c1874f9717c02c8a165ba\")]\n    [TestCase(\"abcdefghijklmnopqrstuvwxyz\", \"406b809260f361e12dcf0bf924bfe1ffd2f987fc18d90b94fc544ff80dc2946b\")]\n    [TestCase(\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\", \"5c6c69ff3ee83361391b7236c8eb6718f52df43de5a61a4f4d2819d40430dc19\")]\n    [TestCase(\"12345678901234567890123456789012345678901234567890123456789012345678901234567890\", \"d8e38fc50d682550cd176decda61adb7fd1c793cdafa825f17f3a002d65847be\")]\n    public void AsconHashA_ReturnsCorrectValue(string input, string expected)\n    {\n        var inputBytes = Encoding.ASCII.GetBytes(input);\n        var result = asconHashA.Digest(inputBytes);\n\n        result.Should().Be(expected);\n    }\n\n    [Test]\n    public void BlockUpdate_WithValidOffsetAndLength_ShouldProcessCorrectly()\n    {\n        // Arrange\n        var input = new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 };\n        var offset = 2;\n        var length = 6; // Picking 6 bytes starting from offset 2\n\n        // Act\n        var act = () => asconHash.BlockUpdate(input, offset, length);\n\n        // Assert\n        act.Should().NotThrow(); // Ensure no exceptions are thrown during processing\n\n        // Finalize the hash and check the output size\n        var output = new byte[asconHash.GetDigestSize()];\n        asconHash.DoFinal(output, 0);\n        output.Should().HaveCount(32); // Ascon hash size is 32 bytes\n    }\n\n    [Test]\n    public void BlockUpdate_WithInvalidOffset_ShouldThrowDataLengthException()\n    {\n        // Arrange\n        var input = new byte[] { 0x00, 0x11, 0x22, 0x33 };\n        var offset = 3; // Offset goes too close to the end\n        var length = 3; // Length would exceed buffer size\n\n        // Act\n        var act = () => asconHash.BlockUpdate(input, offset, length);\n\n        // Assert\n        act.Should().Throw<DataLengthException>()\n            .WithMessage(\"input buffer too short\");\n    }\n\n    [Test]\n    public void BlockUpdate_WithInvalidLength_ShouldThrowDataLengthException()\n    {\n        // Arrange\n        var input = new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };\n        var offset = 1; // Valid offset\n        var length = 10; // Invalid length (exceeds buffer)\n\n        // Act\n        var act = () => asconHash.BlockUpdate(input, offset, length);\n\n        // Assert\n        act.Should().Throw<DataLengthException>()\n            .WithMessage(\"input buffer too short\");\n    }\n\n    [Test]\n    public void BlockUpdate_WithPartialBlock_ShouldProcessCorrectly()\n    {\n        // Arrange\n        var input = new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44 };\n        var offset = 0;\n        var length = 5; // Less than 8 bytes, partial block\n\n        // Act\n        asconHash.BlockUpdate(input, offset, length);\n\n        // Assert\n        var output = new byte[asconHash.GetDigestSize()];\n        asconHash.DoFinal(output, 0);\n        output.Should().HaveCount(32); // Ensure valid hash output\n    }\n\n    [Test]\n    public void BlockUpdate_WithFullBlock_ShouldProcessCorrectly()\n    {\n        // Arrange\n        var input = new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };\n        var offset = 0;\n        var length = 8; // Full block\n\n        // Act\n        asconHash.BlockUpdate(input, offset, length);\n\n        // Assert\n        var output = new byte[asconHash.GetDigestSize()];\n        asconHash.DoFinal(output, 0);\n        output.Should().HaveCount(32); // Ensure valid hash output\n    }\n\n    [Test]\n    public void BlockUpdate_MultipleCalls_ShouldProcessCorrectly()\n    {\n        // Arrange\n        var input1 = new byte[] { 0x00, 0x11, 0x22 };\n        var input2 = new byte[] { 0x33, 0x44, 0x55, 0x66, 0x77 };\n\n        // Act\n        asconHash.BlockUpdate(input1, 0, input1.Length);\n        asconHash.BlockUpdate(input2, 0, input2.Length);\n\n        // Assert\n        var output = new byte[asconHash.GetDigestSize()];\n        asconHash.DoFinal(output, 0);\n        output.Should().HaveCount(32); // Ensure valid hash output\n    }\n\n    [Test]\n    public void AsconHash_WhenGetNameIsCalled_ReturnsCorrectValue()\n    {\n        asconHash.AlgorithmName.Should().Be(\"Ascon-Hash\");\n        asconHashA.AlgorithmName.Should().Be(\"Ascon-HashA\");\n    }\n\n    [Test]\n    public void AsconHash_WhenGetByteLengthIsCalled_ReturnsCorrectValue()\n    {\n        asconHash.GetByteLength().Should().Be(8);\n    }\n\n    [Test]\n    public void Update_ShouldProcessByte_WhenBufferIsFull()\n    {\n        // Arrange\n        byte[] inputBytes = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77]; // 8 bytes to fill the buffer\n\n        // Act\n        foreach (var input in inputBytes)\n        {\n            asconHashA.Update(input);\n        }\n\n        // Assert\n        // Since the buffer is full after 8 updates, we expect the state to have been processed.\n        var output = new byte[asconHashA.GetDigestSize()];\n        asconHashA.DoFinal(output, 0);\n        output.Should().HaveCount(32); // Ascon hash size is 32 bytes\n    }\n\n    [Test]\n    public void Update_ShouldNotProcess_WhenBufferIsNotFull()\n    {\n        // Arrange\n        byte[] inputBytes = [0x00, 0x11, 0x22, 0x33]; // Only 4 bytes (buffer is not full)\n\n        // Act\n        foreach (var input in inputBytes)\n        {\n            asconHashA.Update(input);\n        }\n\n        // Assert\n        // Even though the buffer has received input, it should not process until it is full (8 bytes).\n        // We can check that DoFinal still completes, but the buffer has not been processed yet.\n        var output = new byte[asconHashA.GetDigestSize()];\n        asconHashA.DoFinal(output, 0);\n        output.Should().HaveCount(32); // Ensure valid hash output\n    }\n\n    [Test]\n    public void Update_ShouldProcessMultipleBlocks()\n    {\n        // Arrange\n        var inputBytes = new byte[16]; // Enough to fill two full blocks (16 bytes)\n\n        // Act\n        foreach (var input in inputBytes)\n        {\n            asconHashA.Update(input);\n        }\n\n        // Assert\n        // Ensure that the state is processed twice since 16 bytes were passed (2 blocks of 8 bytes).\n        var output = new byte[asconHashA.GetDigestSize()];\n        asconHashA.DoFinal(output, 0);\n        output.Should().HaveCount(32); // Ensure valid hash output\n    }\n\n    [Test]\n    public void Update_ShouldHandleSingleByteCorrectly()\n    {\n        // Arrange\n        byte input = 0xFF; // Single byte input\n\n        // Act\n        asconHashA.Update(input);\n\n        // Assert\n        // Even though one byte is provided, it should not process the state (waiting for 8 bytes).\n        var output = new byte[asconHashA.GetDigestSize()];\n        asconHashA.DoFinal(output, 0);\n        output.Should().HaveCount(32); // Ensure valid hash output\n    }\n\n    [Test]\n    public void Update_ShouldAccumulateStateWithMultipleUpdates()\n    {\n        // Arrange\n        byte[] inputBytes = [0x00, 0x11, 0x22]; // Partial input\n\n        // Act\n        foreach (var input in inputBytes)\n        {\n            asconHashA.Update(input);\n        }\n\n        // Add more data to fill the buffer.\n        byte[] additionalBytes = [0x33, 0x44, 0x55, 0x66, 0x77];\n        foreach (var input in additionalBytes)\n        {\n            asconHashA.Update(input);\n        }\n\n        // Assert\n        // Ensure that the state is correctly updated after multiple partial updates.\n        var output = new byte[asconHashA.GetDigestSize()];\n        asconHashA.DoFinal(output, 0);\n        output.Should().HaveCount(32); // Ensure valid hash output\n    }\n\n    private static string ToHexString(byte[] bytes)\n    {\n        return BitConverter.ToString(bytes).Replace(\"-\", \"\").ToLowerInvariant();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Digests/Md2DigestTests.cs",
    "content": "﻿using Algorithms.Crypto.Digests;\n\nnamespace Algorithms.Tests.Crypto.Digesters;\n\n[NonParallelizable]\npublic class Md2DigestTests\n{\n    private readonly Md2Digest digest = new Md2Digest();\n\n    [TestCase(\"\", \"8350E5A3E24C153DF2275C9F80692773\")]\n    [TestCase(\"a\", \"32EC01EC4A6DAC72C0AB96FB34C0B5D1\")]\n    [TestCase(\"abc\", \"DA853B0D3F88D99B30283A69E6DED6BB\")]\n    [TestCase(\"message digest\", \"AB4F496BFB2A530B219FF33031FE06B0\")]\n    [TestCase(\"abcdefghijklmnopqrstuvwxyz\", \"4E8DDFF3650292AB5A4108C3AA47940B\")]\n    [TestCase(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\", \"DA33DEF2A42DF13975352846C30338CD\")]\n    [TestCase(\"12345678901234567890123456789012345678901234567890123456789012345678901234567890\", \"D5976F79D83D3A0DC9806C3C66F3EFD8\")]\n    [TestCase(\"123456789012345678901234567890123456789012345678901234567890123456789012345678901\", \"6FAD0685C4A3D03E3D352D12BBAD6BE3\")]\n    public void Digest_ReturnsCorrectValue(string input, string expected)\n    {\n        var inputBytes = Encoding.ASCII.GetBytes(input);\n\n        var result = digest.Digest(inputBytes);\n\n        var output = Convert.ToHexString(result);\n\n        output.Should().Be(expected);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Exceptions/CryptoExceptionTests.cs",
    "content": "using Algorithms.Crypto.Exceptions;\n\nnamespace Algorithms.Tests.Crypto.Exceptions\n{\n    [TestFixture]\n    public class CryptoExceptionTests\n    {\n        [Test]\n        public void CryptoException_ShouldBeCreatedWithoutMessageOrInnerException()\n        {\n            // Act\n            var exception = new CryptoException();\n\n            // Assert\n            exception.Should().BeOfType<CryptoException>()\n                .And.Subject.As<CryptoException>()\n                .Message.Should().NotBeNullOrEmpty();\n            exception.InnerException.Should().BeNull();\n        }\n\n        [Test]\n        public void CryptoException_ShouldSetMessage()\n        {\n            // Arrange\n            var expectedMessage = \"This is a custom cryptographic error.\";\n\n            // Act\n            var exception = new CryptoException(expectedMessage);\n\n            // Assert\n            exception.Should().BeOfType<CryptoException>()\n                .And.Subject.As<CryptoException>()\n                .Message.Should().Be(expectedMessage);\n            exception.InnerException.Should().BeNull();\n        }\n\n        [Test]\n        public void CryptoException_ShouldSetMessageAndInnerException()\n        {\n            // Arrange\n            var expectedMessage = \"An error occurred during encryption.\";\n            var innerException = new InvalidOperationException(\"Invalid operation\");\n\n            // Act\n            var exception = new CryptoException(expectedMessage, innerException);\n\n            // Assert\n            exception.Should().BeOfType<CryptoException>()\n                .And.Subject.As<CryptoException>()\n                .Message.Should().Be(expectedMessage);\n            exception.InnerException.Should().Be(innerException);\n        }\n\n        [Test]\n        public void CryptoException_MessageShouldNotBeNullWhenUsingDefaultConstructor()\n        {\n            // Act\n            var exception = new CryptoException();\n\n            // Assert\n            exception.Message.Should().NotBeNullOrEmpty(); // Even the default Exception message is not null or empty.\n        }\n    }\n}\n\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Exceptions/DataLengthExceptionTests.cs",
    "content": "using Algorithms.Crypto.Exceptions;\n\nnamespace Algorithms.Tests.Crypto.Exceptions\n{\n    [TestFixture]\n    public class DataLengthExceptionTests\n    {\n        [Test]\n        public void DataLengthException_ShouldBeCreatedWithoutMessageOrInnerException()\n        {\n            // Act\n            var exception = new DataLengthException();\n\n            // Assert\n            exception.Should().BeOfType<DataLengthException>()\n                .And.Subject.As<DataLengthException>()\n                .Message.Should().NotBeNullOrEmpty();\n            exception.InnerException.Should().BeNull();\n        }\n\n        [Test]\n        public void DataLengthException_ShouldSetMessage()\n        {\n            // Arrange\n            var expectedMessage = \"Data length is invalid.\";\n\n            // Act\n            var exception = new DataLengthException(expectedMessage);\n\n            // Assert\n            exception.Should().BeOfType<DataLengthException>()\n                .And.Subject.As<DataLengthException>()\n                .Message.Should().Be(expectedMessage);\n            exception.InnerException.Should().BeNull();\n        }\n\n        [Test]\n        public void DataLengthException_ShouldSetMessageAndInnerException()\n        {\n            // Arrange\n            var expectedMessage = \"An error occurred due to incorrect data length.\";\n            var innerException = new ArgumentException(\"Invalid argument\");\n\n            // Act\n            var exception = new DataLengthException(expectedMessage, innerException);\n\n            // Assert\n            exception.Should().BeOfType<DataLengthException>()\n                .And.Subject.As<DataLengthException>()\n                .Message.Should().Be(expectedMessage);\n            exception.InnerException.Should().Be(innerException);\n        }\n\n        [Test]\n        public void DataLengthException_MessageShouldNotBeNullWhenUsingDefaultConstructor()\n        {\n            // Act\n            var exception = new DataLengthException();\n\n            // Assert\n            exception.Message.Should().NotBeNullOrEmpty(); // Even the default Exception message is not null or empty.\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Exceptions/OutputLengthExceptionTests.cs",
    "content": "using Algorithms.Crypto.Exceptions;\n\nnamespace Algorithms.Tests.Crypto.Exceptions\n{\n    [TestFixture]\n    public class OutputLengthExceptionTests\n    {\n        [Test]\n        public void OutputLengthException_ShouldBeCreatedWithoutMessageOrInnerException()\n        {\n            // Act\n            var exception = new OutputLengthException();\n\n            // Assert\n            exception.Should().BeOfType<OutputLengthException>()\n                .And.Subject.As<OutputLengthException>()\n                .Message.Should().NotBeNullOrEmpty();\n            exception.InnerException.Should().BeNull();\n        }\n\n        [Test]\n        public void OutputLengthException_ShouldSetMessage()\n        {\n            // Arrange\n            var expectedMessage = \"Output buffer is too short.\";\n\n            // Act\n            var exception = new OutputLengthException(expectedMessage);\n\n            // Assert\n            exception.Should().BeOfType<OutputLengthException>()\n                .And.Subject.As<OutputLengthException>()\n                .Message.Should().Be(expectedMessage);\n            exception.InnerException.Should().BeNull();\n        }\n\n        [Test]\n        public void OutputLengthException_ShouldSetMessageAndInnerException()\n        {\n            // Arrange\n            var expectedMessage = \"Output length error.\";\n            var innerException = new ArgumentException(\"Invalid argument\");\n\n            // Act\n            var exception = new OutputLengthException(expectedMessage, innerException);\n\n            // Assert\n            exception.Should().BeOfType<OutputLengthException>()\n                .And.Subject.As<OutputLengthException>()\n                .Message.Should().Be(expectedMessage);\n            exception.InnerException.Should().Be(innerException);\n        }\n\n        [Test]\n        public void OutputLengthException_MessageShouldNotBeNullWhenUsingDefaultConstructor()\n        {\n            // Act\n            var exception = new OutputLengthException();\n\n            // Assert\n            exception.Message.Should().NotBeNullOrEmpty(); // Even the default Exception message is not null or empty.\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Paddings/Iso10126D2PaddingTests.cs",
    "content": "﻿using Algorithms.Crypto.Paddings;\n\nnamespace Algorithms.Tests.Crypto.Paddings;\n\npublic class Iso10126D2PaddingTests\n{\n    private readonly Iso10126D2Padding padding = new Iso10126D2Padding();\n\n    [Test]\n    public void AddPadding_WhenInputOffsetIsLessThanInputDataLength_ShouldNotThrowException()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 5;\n\n        Action act = () => padding.AddPadding(inputData, inputOffset);\n\n        act.Should().NotThrow<ArgumentException>();\n    }\n\n    [Test]\n    public void AddPadding_WhenInputOffsetIsEqualToInputDataLength_ShouldThrowException()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 10;\n\n        Action act = () => padding.AddPadding(inputData, inputOffset);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Not enough space in input array for padding\");\n    }\n\n    [Test]\n    public void AddPadding_WhenInputOffsetIsGreaterThanInputDataLength_ShouldThrowException()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 128;\n\n        Action act = () => padding.AddPadding(inputData, inputOffset);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Not enough space in input array for padding\");\n    }\n\n    [Test]\n    public void AddPadding_WhenInputArrayIsValid_ShouldReturnCorrectPaddingSize()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 5;\n\n        var result = padding.AddPadding(inputData, inputOffset);\n\n        result.Should().Be(5);\n    }\n\n    [Test]\n    public void RemovePadding_WhenLengthIsLessThanOne_ShouldThrowATantrum()\n    {\n        var inputData = new byte[] { 0 };\n\n        Action act = () => padding.RemovePadding(inputData);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Invalid padding length\");\n    }\n\n    [Test]\n    public void RemovePadding_WhenPaddingLengthIsGreaterThanInputDataLength_ShouldThrowAnException()\n    {\n        var inputData = new byte[] { 2 };\n\n        Action act = () => padding.RemovePadding(inputData);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Invalid padding length\");\n    }\n\n    [Test]\n    public void RemovePadding_WhenInputDataIsValid_ShouldReturnCorrectData()\n    {\n        var inputData = new byte[] { 1, 2, 3, 1 };\n        var expected = new byte[] { 1, 2, 3 };\n\n        var result = padding.RemovePadding(inputData);\n\n        result.Should().Equal(expected);\n    }\n\n    [Test]\n    public void GetPaddingCount_WhenInputIsNull_ShouldThrowAnException()\n    {\n        byte[]? input = null;\n\n        Action act = () => padding.GetPaddingCount(input!);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Input cannot be null (Parameter 'input')\");\n    }\n\n    [Test]\n    public void GetPaddingCount_WhenPaddingBlockIsCorrupted_ShouldThrowAnException()\n    {\n        var input = new byte[] { 1, 2, 3, 4, 5, 7 };\n\n        Action act = () => padding.GetPaddingCount(input);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Padding block is corrupted\");\n    }\n\n    [Test]\n    public void GetPaddingCount_WhenInputDataIsValid_ShouldReturnCorrectPaddingCount()\n    {\n        var input = new byte[] { 1, 2, 3, 4, 1 };\n\n        var result = padding.GetPaddingCount(input);\n\n        result.Should().Be(1);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Paddings/Iso7816D4PaddingTests.cs",
    "content": "using Algorithms.Crypto.Paddings;\n\nnamespace Algorithms.Tests.Crypto.Paddings;\n\npublic class Iso7816D4PaddingTests\n{\n    private readonly Iso7816D4Padding padding = new Iso7816D4Padding();\n\n    [Test]\n    public void AddPadding_WhenCalledWithValidInput_ShouldReturnCorrectPadding()\n    {\n        var inputData = new byte[10];\n        var inputOffset = 5;\n\n        var result = padding.AddPadding(inputData, inputOffset);\n\n        result.Should().Be(5);\n        inputData[5].Should().Be(80);\n        inputData.Skip(6).Should().AllBeEquivalentTo(0);\n    }\n\n    [Test]\n    public void AddPadding_WhenCalledWithInvalidInput_ShouldThrowArgumentException()\n    {\n        var inputData = new byte[10];\n        var inputOffset = 11;\n\n        Action act = () => padding.AddPadding(inputData, inputOffset);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"not enough space in input array for padding\");\n    }\n\n    [Test]\n    public void AddPadding_WhenCalledWithZeroOffset_ShouldReturnCorrectPadding()\n    {\n        var inputData = new byte[10];\n        var inputOffset = 0;\n\n        var result = padding.AddPadding(inputData, inputOffset);\n\n        result.Should().Be(10);\n        inputData[0].Should().Be(80);\n        inputData.Skip(1).Should().AllBeEquivalentTo(0);\n    }\n\n    [Test]\n    public void AddPadding_WhenCalledWithOffsetEqualToLength_ShouldThrowArgumentException()\n    {\n        var inputData = new byte[10];\n        var inputOffset = 10;\n\n        Action act = () => padding.AddPadding(inputData, inputOffset);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Not enough space in input array for padding\");\n    }\n\n    [Test]\n    public void AddPadding_WhenCalledWithEmptyArray_ShouldThrowArgumentException()\n    {\n        var inputData = new byte[0];\n        var inputOffset = 0;\n\n        Action act = () => padding.AddPadding(inputData, inputOffset);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Not enough space in input array for padding\");\n    }\n\n    [Test]\n    public void RemovePadding_WhenCalledWithValidInput_shouldReturnCorrectData()\n    {\n        var inputData = new byte[] { 1, 2, 3, 4, 5, 0x80, 0, 0, 0 };\n\n        var result = padding.RemovePadding(inputData);\n\n        result.Should().Equal([1, 2, 3, 4, 5]);\n    }\n\n    [Test]\n    public void RemovePadding_WhenCalledWithInvalidInput_ShouldThrowArgumentException()\n    {\n        var inputData = new byte[] { 1, 2, 3, 4, 5 };\n\n        Action act = () => padding.RemovePadding(inputData);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Invalid padding\");\n    }\n\n    [Test]\n    public void RemovePadding_WhenCalledWithArrayContainingOnlyPadding_ShouldReturnEmptyArray()\n    {\n        var inputData = new byte[] { 0x80, 0, 0, 0, 0 };\n\n        var result = padding.RemovePadding(inputData);\n\n        result.Should().BeEmpty();\n    }\n\n    [Test]\n    public void RemovePadding_WhenCalledWithArrayNotContainingStartOfPadding_ShouldThrowArgumentException()\n    {\n        var input = new byte[] { 1, 2, 3, 4, 5, 0, 0, 0, 0 };\n\n        Action act = () => padding.RemovePadding(input);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Invalid padding\");\n    }\n\n    [Test]\n    public void GetPaddingCount_WhenCalledWithValidInput_ShouldReturnCorrectCount()\n    {\n        var inputData = new byte[] { 1, 2, 3, 4, 5, 0x80, 0, 0, 0 };\n\n        var result = padding.GetPaddingCount(inputData);\n\n        result.Should().Be(4);\n    }\n\n    [Test]\n    public void GetPaddingCount_WhenCalledWithInvalidInput_ShouldThrowArgumentException()\n    {\n        var inputData = new byte[] { 1, 2, 3, 4, 5 };\n\n        Action act = () => padding.GetPaddingCount(inputData);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Pad block corrupted\");\n    }\n\n    [Test]\n    public void GetPaddingCount_WhenCalledWithEmptyArray_ShouldThrowArgumentException()\n    {\n        var inputData = Array.Empty<byte>();\n\n        Action act = () => padding.GetPaddingCount(inputData);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Pad block corrupted\");\n    }\n\n    [Test]\n    public void GetPaddingCount_WhenCalledWithArrayContainingOnlyPadding_ShouldReturnCorrectCount()\n    {\n        var inputData = new byte[] { 0x80, 0x00, 0x00 };\n\n        var result = padding.GetPaddingCount(inputData);\n\n        result.Should().Be(3);\n    }\n\n    [Test]\n    public void GetPaddingCount_WhenCalledWithArrayNotContainingStartOfPadding_ShouldThrowAnException()\n    {\n        var inputData = new byte[] { 1, 2, 3, 4, 5, 0, 0, 0, 0 };\n\n        Action act = () => padding.GetPaddingCount(inputData);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Pad block corrupted\");\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Paddings/Pkcs7PaddingTests.cs",
    "content": "﻿using Algorithms.Crypto.Paddings;\n\nnamespace Algorithms.Tests.Crypto.Paddings;\n\npublic class Pkcs7PaddingTests\n{\n    private const int DefaultBlockSize = 16;\n\n    [Test]\n    public void Constructor_WhenBlockSizeIsLessThanOne_ShouldThrowArgumentOutOfRangeException()\n    {\n        const int blockSize = 0;\n\n        Action act = () => new Pkcs7Padding(blockSize);\n\n        act.Should().Throw<ArgumentOutOfRangeException>()\n            .WithMessage(\"Invalid block size: 0 (Parameter 'blockSize')\");\n    }\n\n    [Test]\n    public void Constructor_WhenBlockSizeIsMoreThan255_ShouldThrowArgumentOutOfRangeException()\n    {\n        const int blockSize = 256;\n\n        Action act = () => new Pkcs7Padding(blockSize);\n\n        act.Should().Throw<ArgumentOutOfRangeException>()\n            .WithMessage(\"Invalid block size: 256 (Parameter 'blockSize')\");\n    }\n\n    [Test]\n    public void Constructor_WhenBlockSizeIsWithinValidRange_ShouldNotThrowAFit()\n    {\n        const int blockSize = 128;\n\n        Action act = () => new Pkcs7Padding(blockSize);\n\n        act.Should().NotThrow();\n    }\n\n    [Test]\n    public void AddPadding_WhenNotEnoughSpaceInInputArrayForPadding_ShouldThrowArgumentException()\n    {\n        var padding = new Pkcs7Padding(DefaultBlockSize);\n        const int inputOffset = 1;\n\n        var size16Input = new byte[16];\n\n        Action act = () => padding.AddPadding(size16Input, inputOffset);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Not enough space in input array for padding\");\n    }\n\n    [Test]\n    public void AddPadding_WhenInputArrayHasEnoughSpace_ShouldReturnCorrectPaddingSize()\n    {\n        var padding = new Pkcs7Padding(DefaultBlockSize);\n        const int inputOffset = DefaultBlockSize;\n\n        var size32Input = new byte[32];\n\n        var result = padding.AddPadding(size32Input, inputOffset);\n\n        result.Should().Be(DefaultBlockSize);\n    }\n\n    [Test]\n    public void AddPadding_WhenAppliedToAnInputArray_ShouldAddCorrectPKCS7Padding()\n    {\n        var padding = new Pkcs7Padding(DefaultBlockSize);\n        const int inputOffset = DefaultBlockSize;\n\n        var size32Input = new byte[32];\n\n        padding.AddPadding(size32Input, inputOffset);\n\n        for (var i = 0; i < DefaultBlockSize - 1; i++)\n        {\n            size32Input[inputOffset + i].Should().Be(DefaultBlockSize);\n        }\n    }\n\n    [Test]\n    public void RemovePadding_WhenAppliedToAValidInputArray_ShouldRemovePKCS7PaddingCorrectly()\n    {\n        var paddingSize = 5;\n        var size32Input = new byte[32];\n        for (var i = 0; i < paddingSize; i++)\n        {\n            size32Input[size32Input.Length - 1 - i] = (byte)paddingSize;\n        }\n\n        var padding = new Pkcs7Padding(DefaultBlockSize);\n\n        var output = padding.RemovePadding(size32Input);\n\n        output.Length.Should().Be(size32Input.Length - paddingSize);\n    }\n\n    [Test]\n    public void RemovePadding_WhenInputLengthNotMultipleOfBlockSize_ShouldThrowArgumentException()\n    {\n        var input = new byte[DefaultBlockSize + 1]; // Length is not a multiple of blockSize\n        var padding = new Pkcs7Padding(DefaultBlockSize);\n\n        Action act = () => padding.RemovePadding(input);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Input length must be a multiple of block size\");\n    }\n\n    [Test]\n    public void RemovePadding_WhenInvalidPaddingLength_ShouldThrowArgumentException()\n    {\n        var size32Input = new byte[32];\n\n        size32Input[^1] = (byte)(DefaultBlockSize + 1); // Set invalid padding length\n        var padding = new Pkcs7Padding(DefaultBlockSize);\n\n        Action act = () => padding.RemovePadding(size32Input);\n\n        act.Should().Throw<ArgumentException>().WithMessage(\"Invalid padding length\");\n    }\n\n    [Test]\n    public void RemovePadding_WhenInvalidPadding_ShouldThrowArgumentException()\n    {\n        var size32Input = new byte[32];\n\n        size32Input[^1] = (byte)(DefaultBlockSize); // Set valid padding length\n        size32Input[^2] = (byte)(DefaultBlockSize - 1); // Set invalid padding byte\n        var padding = new Pkcs7Padding(DefaultBlockSize);\n\n        Action act = () => padding.RemovePadding(size32Input);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Invalid padding\");\n    }\n\n    [Test]\n    public void GetPaddingCount_WhenArrayIsNull_ShouldThrowArgumentNullException()\n    {\n        var padding = new Pkcs7Padding(DefaultBlockSize);\n\n        Action act = () => padding.GetPaddingCount(null!);\n\n        act.Should().Throw<ArgumentNullException>();\n    }\n\n    [Test]\n    public void GetPaddingCount_WhenInputArrayIsValid_ShouldReturnCorrectPaddingCount()\n    {\n        const int paddingSize = 5;\n        var size32Input = new byte[32];\n\n        for (var i = 0; i < paddingSize; i++)\n        {\n            size32Input[size32Input.Length - 1 - i] = (byte)paddingSize; // Add padding bytes at the end of the array\n        }\n\n        var padding = new Pkcs7Padding(DefaultBlockSize);\n\n        var output = padding.GetPaddingCount(size32Input);\n\n        output.Should().Be(paddingSize);\n    }\n\n    [Test]\n    public void GetPaddingCount_WhenInvalidPadding_ShouldThrowArgumentException()\n    {\n        var size32Input = new byte[32];\n\n        size32Input[^1] = DefaultBlockSize;\n        size32Input[^2] = DefaultBlockSize - 1;\n\n        var padding = new Pkcs7Padding(DefaultBlockSize);\n\n        Action act = () => padding.GetPaddingCount(size32Input);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Padding block is corrupted\");\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Paddings/TbcPaddingTests.cs",
    "content": "﻿using Algorithms.Crypto.Paddings;\n\nnamespace Algorithms.Tests.Crypto.Paddings;\n\npublic class TbcPaddingTests\n{\n    private readonly TbcPadding padding = new TbcPadding();\n\n    [Test]\n    public void AddPadding_WhenInputOffsetIsZero_ShouldPadWithLastBit()\n    {\n        var input = new byte[] { 0x01, 0x02, 0x03, 0x04 };\n        var inputOffset = 0;\n\n        var result = padding.AddPadding(input, inputOffset);\n\n        result.Should().Be(4);\n        input.Should().BeEquivalentTo(new byte[] { 0xff, 0xff, 0xff, 0xff });\n    }\n\n    [Test]\n    public void AddPadding_WhenInputOffsetIsPositive_ShouldPadWithPreviousBit()\n    {\n        var input = new byte[] { 0x01, 0x02, 0x03, 0x04 };\n        var inputOffset = 2;\n\n        var result = padding.AddPadding(input, inputOffset);\n\n        result.Should().Be(2);\n        input.Should().BeEquivalentTo(new byte[] { 0x01, 0x02, 0xff, 0xff });\n    }\n\n    [Test]\n    public void AddPadding_WhenInputOffsetIsGreaterThanLength_ShouldThrowArgumentException()\n    {\n        var input = new byte[] { 0x01, 0x02, 0x03, 0x04 };\n        var inputOffset = 5;\n\n        Action act = () => padding.AddPadding(input, inputOffset);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Not enough space in input array for padding\");\n    }\n\n    [Test]\n    public void AddPadding_WhenLastBitIsZero_ShouldPadWith0xFF()\n    {\n        var input = new byte[] { 0x02 };\n        const int inputOffset = 0;\n\n        var result = padding.AddPadding(input, inputOffset);\n\n        result.Should().Be(1);\n        input.Should().BeEquivalentTo(new byte[] { 0xFF });\n    }\n\n    [Test]\n    public void AddPadding_WhenLastBitIsOne_ShouldPadWith0x00()\n    {\n        var input = new byte[] { 0x03 };\n        const int inputOffset = 0;\n\n        var result = padding.AddPadding(input, inputOffset);\n\n        result.Should().Be(1);\n        input.Should().BeEquivalentTo(new byte[] { 0x00 });\n    }\n\n    [Test]\n    public void RemovePadding_WhenCalledWithPaddedData_ShouldReturnUnpaddedData()\n    {\n        var paddedData = new byte[] { 0x01, 0x02, 0x03, 0xff, 0xff };\n        var expectedData = new byte[] { 0x01, 0x02, 0x03 };\n\n        var result = padding.RemovePadding(paddedData);\n\n        result.Should().BeEquivalentTo(expectedData);\n    }\n\n    [Test]\n    public void RemovePadding_WhenCalledWithUnpaddedData_ShouldReturnsSameData()\n    {\n        var unpaddedData = new byte[] { 0x01, 0x02, 0x03 };\n\n        var result = padding.RemovePadding(unpaddedData);\n\n        result.Should().BeEquivalentTo(unpaddedData);\n    }\n\n    [Test]\n    public void RemovePadding_WhenCalledWithEmptyArray_ShouldReturnEmptyArray()\n    {\n        var emptyData = Array.Empty<byte>();\n\n        var result = padding.RemovePadding(emptyData);\n\n        result.Should().BeEquivalentTo(emptyData);\n    }\n\n    [Test]\n    public void RemovePadding_WhenCalledWithSingleBytePaddedData_ShouldReturnEmptyArray()\n    {\n        var singleBytePaddedData = new byte[] { 0xff };\n\n        var result = padding.RemovePadding(singleBytePaddedData);\n\n        result.Should().BeEmpty();\n    }\n\n    [Test]\n    public void RemovePadding_WhenCalledWitAllBytesPadded_ShouldReturnEmptyArray()\n    {\n        var allBytesPaddedData = new byte[] { 0xff, 0xff, 0xff };\n        var emptyData = Array.Empty<byte>();\n\n        var result = padding.RemovePadding(allBytesPaddedData);\n\n        result.Should().BeEquivalentTo(emptyData);\n    }\n\n    [Test]\n    public void GetPaddingBytes_WhenCalledWithPaddedData_ShouldReturnCorrectPaddingCount()\n    {\n\n        var paddedData = new byte[] { 0x01, 0x02, 0x03, 0xff, 0xff };\n        const int expectedPaddingCount = 2;\n\n        var result = padding.GetPaddingCount(paddedData);\n\n        result.Should().Be(expectedPaddingCount);\n    }\n\n    [Test]\n    public void GetPaddingBytes_WhenCalledWithUnpaddedData_ShouldReturnZero()\n    {\n        var unpaddedData = new byte[] { 0x01, 0x02, 0x03 };\n\n        Action action = () => padding.GetPaddingCount(unpaddedData);\n\n        action.Should().Throw<ArgumentException>()\n            .WithMessage(\"No padding found\");\n    }\n\n    [Test]\n    public void GetPaddingBytes_WhenCalledWithEmptyArray_ShouldReturnZero()\n    {\n        var emptyData = Array.Empty<byte>();\n\n        Action action = () => padding.GetPaddingCount(emptyData);\n\n        action.Should().Throw<ArgumentException>()\n            .WithMessage(\"No padding found.\");\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Paddings/X932PaddingTests.cs",
    "content": "﻿using Algorithms.Crypto.Paddings;\n\nnamespace Algorithms.Tests.Crypto.Paddings;\n\npublic class X932PaddingTests\n{\n    private readonly X932Padding zeroPadding = new X932Padding(false);\n    private readonly X932Padding randomPadding = new X932Padding(true);\n\n    [Test]\n    public void AddPadding_WhenCalledWithZeroPadding_ShouldReturnCorrectCode()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 5;\n\n        var result = zeroPadding.AddPadding(inputData, inputOffset);\n\n        result.Should().Be(5);\n    }\n\n    [Test]\n    public void AddPadding_WhenCalledWithZeroPaddingAndOffsetIsEqualToDataLength_ShouldThrowArgumentException()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 10;\n\n        Action action = () => zeroPadding.AddPadding(inputData, inputOffset);\n\n        action.Should().Throw<ArgumentException>()\n            .WithMessage(\"Not enough space in input array for padding\");\n    }\n\n    [Test]\n    public void AddPadding_WhenCalledWithZeroPaddingAndOffsetIsGreaterThanDataLength_ShouldThrowArgumentException()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 11;\n\n        Action action = () => zeroPadding.AddPadding(inputData, inputOffset);\n\n        action.Should().Throw<ArgumentException>()\n            .WithMessage(\"Not enough space in input array for padding\");\n    }\n\n\n    [Test]\n    public void AddPadding_WhenCalledWithRandomPadding_ShouldReturnCorrectCode()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 5;\n\n        var result = randomPadding.AddPadding(inputData, inputOffset);\n\n        result.Should().Be(5);\n    }\n\n    [Test]\n    public void AddPadding_WhenCalledWithRandomPaddingAndOffsetIsEqualToDataLength_ShouldThrowArgumentException()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 10;\n\n        Action action = () => randomPadding.AddPadding(inputData, inputOffset);\n\n        action.Should().Throw<ArgumentException>()\n            .WithMessage(\"Not enough space in input array for padding\");\n    }\n\n    [Test]\n    public void AddPadding_WhenCalledWithRandomPaddingAndOffsetIsGreaterThanDataLength_ShouldThrowArgumentException()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 11;\n\n        Action action = () => randomPadding.AddPadding(inputData, inputOffset);\n\n        action.Should().Throw<ArgumentException>()\n            .WithMessage(\"Not enough space in input array for padding\");\n    }\n\n    [Test]\n    public void AddPadding_WhenCalledWithZeroPaddingAndOffsetIsZero_ShouldReturnLengthOfInputData()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 0;\n\n        var result = zeroPadding.AddPadding(inputData, inputOffset);\n\n        result.Should().Be(10);\n    }\n\n    [Test]\n    public void AddPadding_WhenCalledWithRandomPaddingAndOffsetIsZero_ShouldReturnLengthOfInputData()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 0;\n\n        var result = randomPadding.AddPadding(inputData, inputOffset);\n\n        result.Should().Be(10);\n    }\n\n    [Test]\n    public void AddPadding_WhenCalledWithRandomPadding_ShouldFillThePaddingWithRandomValues()\n    {\n        var inputData = new byte[10];\n        const int inputOffset = 5;\n\n        var result = randomPadding.AddPadding(inputData, inputOffset);\n\n        for (var i = inputOffset; i < inputData.Length - 1; i++)\n        {\n            inputData[i].Should().BeInRange(0, 255);\n        }\n\n        inputData[^1].Should().Be((byte)result);\n    }\n\n    [Test]\n    public void RemovePadding_WhenCalledInEmptyArray_ShouldReturnAnEmptyArray()\n    {\n        var result = zeroPadding.RemovePadding(Array.Empty<byte>());\n\n        result.Should().AllBeEquivalentTo(Array.Empty<byte>());\n    }\n\n    [Test]\n    public void RemovePadding_WhenCalledOnArrayWithValidPadding_ShouldRemovePadding()\n    {\n        var inputData = new byte[] { 1, 2, 3, 2 };\n        var expectedOutput = new byte[] { 1, 2 };\n\n        var result = zeroPadding.RemovePadding(inputData);\n\n        result.Should().BeEquivalentTo(expectedOutput);\n    }\n\n    [Test]\n    public void RemovePadding_WithInvalidPadding_ThrowsArgumentException()\n    {\n        var inputData = new byte[] { 1, 2, 3, 5 };\n\n        Action act = () => zeroPadding.RemovePadding(inputData);\n\n        act.Should().Throw<ArgumentException>()\n            .WithMessage(\"Invalid padding length\");\n    }\n\n    [Test]\n    public void GetPaddingCount_WithValidPadding_ReturnsCorrectCount()\n    {\n        var inputData = new byte[] { 1, 2, 3, 2 };\n\n        var result = zeroPadding.GetPaddingCount(inputData);\n\n        result.Should().Be(2);\n    }\n\n    [Test]\n    public void GetPaddingCount_WithInvalidPadding_ThrowsArgumentException()\n    {\n        var inputData = new byte[] { 1, 2, 3, 5 };\n\n        Action action = () => zeroPadding.GetPaddingCount(inputData);\n\n        action.Should().Throw<ArgumentException>()\n            .WithMessage(\"Pad block corrupted\");\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Utils/ByteEncodingUtils.cs",
    "content": "using Algorithms.Crypto.Utils;\n\nnamespace Algorithms.Tests.Crypto.Utils\n{\n    [TestFixture]\n    public class ByteEncodingUtilsTests\n    {\n        [Test]\n        public void BigEndianToUint64_ByteArray_ShouldConvertCorrectly()\n        {\n            // Arrange\n            byte[] input = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF];\n            var expected = 0x0123456789ABCDEFUL;\n\n            // Act\n            var result = ByteEncodingUtils.BigEndianToUint64(input, 0);\n\n            // Assert\n            result.Should().Be(expected);\n        }\n\n        [Test]\n        public void BigEndianToUint64_ByteArray_WithOffset_ShouldConvertCorrectly()\n        {\n            // Arrange\n            byte[] input = [0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF];\n            var expected = 0x0123456789ABCDEFUL;\n\n            // Act\n            var result = ByteEncodingUtils.BigEndianToUint64(input, 2);\n\n            // Assert\n            result.Should().Be(expected);\n        }\n\n        [Test]\n        public void BigEndianToUint64_Span_ShouldConvertCorrectly()\n        {\n            // Arrange\n            Span<byte> input = stackalloc byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };\n            var expected = 0x0123456789ABCDEFUL;\n\n            // Act\n            var result = ByteEncodingUtils.BigEndianToUint64(input);\n\n            // Assert\n            result.Should().Be(expected);\n        }\n\n        [Test]\n        public void UInt64ToBigEndian_ShouldWriteCorrectly()\n        {\n            // Arrange\n            var value = 0x0123456789ABCDEFUL;\n            Span<byte> output = stackalloc byte[8];\n            byte[] expected = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF];\n\n            // Act\n            ByteEncodingUtils.UInt64ToBigEndian(value, output);\n\n            // Assert\n            output.ToArray().Should().Equal(expected);\n        }\n\n        [Test]\n        public void BigEndianToUint64_InvalidOffset_ShouldThrowException()\n        {\n            // Arrange\n            byte[] input = [0x01, 0x23];\n\n            // Act\n            Action act = () => ByteEncodingUtils.BigEndianToUint64(input, 1);\n\n            // Assert\n            act.Should().Throw<ArgumentOutOfRangeException>();\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Utils/LongUtilsTests.cs",
    "content": "using Algorithms.Crypto.Utils;\n\nnamespace Algorithms.Tests.Crypto.Utils\n{\n    [TestFixture]\n    public class LongUtilsTests\n    {\n        [Test]\n        public void RotateLeft_Long_ShouldRotateCorrectly()\n        {\n            // Arrange\n            var input = 0x0123456789ABCDEF;\n            var distance = 8;\n            var expected = 0x23456789ABCDEF01L;  // The expected result is a signed long value.\n\n            // Act\n            var result = LongUtils.RotateLeft(input, distance);\n\n            // Assert\n            result.Should().Be(expected);\n        }\n\n        [Test]\n        public void RotateLeft_Ulong_ShouldRotateCorrectly()\n        {\n            // Arrange\n            var input = 0x0123456789ABCDEFUL;\n            var distance = 8;\n            var expected = 0x23456789ABCDEF01UL;  // The expected result is an unsigned ulong value.\n\n            // Act\n            var result = LongUtils.RotateLeft(input, distance);\n\n            // Assert\n            result.Should().Be(expected);\n        }\n\n        [Test]\n        public void RotateRight_Long_ShouldRotateCorrectly()\n        {\n            // Arrange\n            var input = 0x0123456789ABCDEF;\n            var distance = 8;\n            var expected = unchecked((long)0xEF0123456789ABCD);  // Using unchecked to correctly represent signed long.\n\n            // Act\n            var result = LongUtils.RotateRight(input, distance);\n\n            // Assert\n            result.Should().Be(expected);\n        }\n\n        [Test]\n        public void RotateRight_Ulong_ShouldRotateCorrectly()\n        {\n            // Arrange\n            var input = 0x0123456789ABCDEFUL;\n            var distance = 8;\n            var expected = 0xEF0123456789ABCDUL;  // The expected result is an unsigned ulong value.\n\n            // Act\n            var result = LongUtils.RotateRight(input, distance);\n\n            // Assert\n            result.Should().Be(expected);\n        }\n\n        [Test]\n        public void RotateLeft_Long_ShouldHandleZeroRotation()\n        {\n            // Arrange\n            var input = 0x0123456789ABCDEF;\n            var distance = 0;\n\n            // Act\n            var result = LongUtils.RotateLeft(input, distance);\n\n            // Assert\n            result.Should().Be(input);  // No rotation, result should be the same as input.\n        }\n\n        [Test]\n        public void RotateRight_Ulong_ShouldHandleFullRotation()\n        {\n            // Arrange\n            var input = 0x0123456789ABCDEFUL;\n            var distance = 64;\n\n            // Act\n            var result = LongUtils.RotateRight(input, distance);\n\n            // Assert\n            result.Should().Be(input);  // Full 64-bit rotation should result in the same value.\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Crypto/Utils/ValidationUtilsTests.cs",
    "content": "using Algorithms.Crypto.Utils;\nusing Algorithms.Crypto.Exceptions;\n\nnamespace Algorithms.Tests.Crypto.Utils\n{\n    [TestFixture]\n    public class ValidationUtilsTests\n    {\n        [Test]\n        public void CheckDataLength_WithBufferOutOfBounds_ShouldThrowDataLengthException()\n        {\n            // Arrange\n            var buffer = new byte[5];  // A byte array of length 5\n            var offset = 3;               // Starting at index 3\n            var length = 4;               // Expecting to read 4 bytes (which will exceed the buffer size)\n            var errorMessage = \"Buffer is too short\";\n\n            // Act\n            var act = () => ValidationUtils.CheckDataLength(buffer, offset, length, errorMessage);\n\n            // Assert\n            act.Should().Throw<DataLengthException>()\n                .WithMessage(errorMessage);\n        }\n\n        [Test]\n        public void CheckOutputLength_WithCondition_ShouldThrowOutputLengthException()\n        {\n            // Arrange\n            var condition = true;\n            var errorMessage = \"Output length is invalid\";\n\n            // Act\n            var act = () => ValidationUtils.CheckOutputLength(condition, errorMessage);\n\n            // Assert\n            act.Should().Throw<OutputLengthException>()\n               .WithMessage(errorMessage);\n        }\n\n        [Test]\n        public void CheckOutputLength_WithCondition_ShouldNotThrowOutputLengthException()\n        {\n            // Arrange\n            var condition = false;\n            var errorMessage = \"Output length is invalid\";\n\n            // Act\n            var act = () => ValidationUtils.CheckOutputLength(condition, errorMessage);\n\n            // Assert\n            act.Should().NotThrow<OutputLengthException>();\n        }\n\n        [Test]\n        public void CheckOutputLength_WithBufferOutOfBounds_ShouldThrowOutputLengthException()\n        {\n            // Arrange\n            var buffer = new byte[5];\n            var offset = 3;\n            var length = 4;\n            var errorMessage = \"Output buffer is too short\";\n\n            // Act\n            var act = () => ValidationUtils.CheckOutputLength(buffer, offset, length, errorMessage);\n\n            // Assert\n            act.Should().Throw<OutputLengthException>()\n               .WithMessage(errorMessage);\n        }\n\n        [Test]\n        public void CheckOutputLength_WithBProperBufferSize_ShouldThrowOutputLengthException()\n        {\n            // Arrange\n            var buffer = new byte[5];\n            var offset = 0;\n            var length = 4;\n            var errorMessage = \"Output buffer is too short\";\n\n            // Act\n            var act = () => ValidationUtils.CheckOutputLength(buffer, offset, length, errorMessage);\n\n            // Assert\n            act.Should().NotThrow<OutputLengthException>();\n        }\n\n        [Test]\n        public void CheckOutputLength_SpanExceedsLimit_ShouldThrowOutputLengthException()\n        {\n            // Arrange\n            Span<byte> output = new byte[10];\n            var outputLength = output.Length;\n            var maxLength = 5;\n            var errorMessage = \"Output exceeds maximum length\";\n\n            // Act\n            var act = () => ValidationUtils.CheckOutputLength(outputLength > maxLength, errorMessage); // Capture the length\n\n            // Assert\n            act.Should().Throw<OutputLengthException>()\n                .WithMessage(errorMessage);\n        }\n\n        [Test]\n        public void CheckOutputLength_SpanDoesNotExceedLimit_ShouldThrowOutputLengthException()\n        {\n            // Arrange\n            Span<byte> output = new byte[10];\n            var outputLength = output.Length;\n            var maxLength = 15;\n            var errorMessage = \"Output exceeds maximum length\";\n\n            // Act\n            var act = () => ValidationUtils.CheckOutputLength(outputLength > maxLength, errorMessage); // Capture the length\n\n            // Assert\n            act.Should().NotThrow<OutputLengthException>();\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Encoders/AutokeyEncoderTests.cs",
    "content": "using Algorithms.Encoders;\n\nnamespace Algorithms.Tests.Encoders\n{\n    public static class AutokeyEncoderTests\n    {\n        [Test]\n        public static void DecodedStringIsTheSame()\n        {\n            // Arrange\n            var plainText = \"PLAINTEXT\";\n            var keyword = \"KEYWORD\";\n            var encoder = new AutokeyEncorder();\n\n            // Act\n            var encoded = encoder.Encode(plainText, keyword);\n            var decoded = encoder.Decode(encoded, keyword);\n\n            // Assert\n            Assert.That(decoded, Is.EqualTo(plainText));\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Encoders/BlowfishEncoderTests.cs",
    "content": "﻿using Algorithms.Encoders;\n\nnamespace Algorithms.Tests.Encoders;\n\n// Tests ported from the Java Algorithms repository\n\npublic class BlowfishEncoderTests\n{\n    private const string Key = \"aabb09182736ccdd\";\n\n    [Test]\n    public void BlowfishEncoder_Encryption_ShouldWorkCorrectly()\n    {\n        // Arrange\n        var encoder = new BlowfishEncoder();\n        encoder.GenerateKey(Key);\n\n        const string plainText = \"123456abcd132536\";\n        const string cipherText = \"d748ec383d3405f7\";\n\n        // Act\n        var result = encoder.Encrypt(plainText);\n\n        // Assert\n        result.Should().Be(cipherText);\n    }\n\n    [Test]\n    public void BlowfishEncoder_Decryption_ShouldWorkCorrectly()\n    {\n        // Arrange\n        var encoder = new BlowfishEncoder();\n        encoder.GenerateKey(Key);\n\n        const string cipherText = \"d748ec383d3405f7\";\n        const string plainText = \"123456abcd132536\";\n\n        // Act\n        var result = encoder.Decrypt(cipherText);\n\n        // Assert\n        result.Should().Be(plainText);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Encoders/CaesarEncoderTests.cs",
    "content": "using Algorithms.Encoders;\n\nnamespace Algorithms.Tests.Encoders;\n\npublic static class CaesarEncoderTests\n{\n    [Test]\n    public static void DecodedStringIsTheSame([Random(100)] int key)\n    {\n        // Arrange\n        var encoder = new CaesarEncoder();\n        var random = new Randomizer();\n        var message = random.GetString();\n\n        // Act\n        var encoded = encoder.Encode(message, key);\n        var decoded = encoder.Decode(encoded, key);\n\n        // Assert\n        Assert.That(decoded, Is.EqualTo(message));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Encoders/FeistelCipherTest.cs",
    "content": "using Algorithms.Encoders;\n\nnamespace Algorithms.Tests.Encoders;\n\npublic static class FeistelCipherTests\n{\n    [Test]\n    public static void DecodedStringIsTheSame([Random(100)] uint key)\n    {\n        // Arrange\n        var encoder = new FeistelCipher();\n        var random = new Randomizer();\n\n        int lenOfString = random.Next(1000);\n\n        string message = random.GetString(lenOfString);\n\n        // Act\n        var encoded = encoder.Encode(message, key);\n        var decoded = encoder.Decode(encoded, key);\n\n        // Assert\n        Assert.That(decoded, Is.EqualTo(message));\n    }\n\n    [TestCase(\"00001111\", (uint)0x12345678)]\n    [TestCase(\"00001111222233334444555566667\", (uint)0x12345678)]\n    [TestCase(\"000011112222333344445555666677\", (uint)0x12345678)]\n    [TestCase(\"0000111122223333444455556666777\", (uint)0x12345678)]\n    // The plain text will be padded to fill the size of block (16 bytes), so the encoded message should be aligned with the rule\n    // (text.Length % 16 == 0)\n    public static void TestEncodedMessageSize(string testCase, uint key)\n    {\n        // Arrange\n        var encoder = new FeistelCipher();\n\n        // Assert\n        Assert.Throws<ArgumentException>(() => encoder.Decode(testCase, key));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Encoders/HillEnconderTests.cs",
    "content": "using Algorithms.Encoders;\n\nnamespace Algorithms.Tests.Encoders;\n\npublic static class HillEnconderTests\n{\n    [Test]\n    [Repeat(100)]\n    public static void DecodedStringIsTheSame()\n    {\n        // Arrange\n        var encoder = new HillEncoder();\n        var random = new Randomizer();\n        var message = random.GetString();\n\n        var key = new double[,] { { 0, 4, 5 }, { 9, 2, -1 }, { 3, 17, 7 } };\n\n        // Act\n        var encodedText = encoder.Encode(message, key);\n        var decodeText = encoder.Decode(encodedText, key);\n\n        // Assert\n        Assert.That(decodeText, Is.EqualTo(message));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Encoders/NysiisEncoderTests.cs",
    "content": "using Algorithms.Encoders;\n\nnamespace Algorithms.Tests.Encoders;\n\npublic class NysiisEncoderTests\n{\n    private static readonly string[] Names =\n    [\n        \"Jay\", \"John\", \"Jane\", \"Zayne\", \"Guerra\", \"Iga\", \"Cowan\", \"Louisa\", \"Arnie\", \"Olsen\", \"Corban\", \"Nava\",\n        \"Cynthia Malone\", \"Amiee MacKee\", \"MacGyver\", \"Yasmin Edge\",\n    ];\n\n    private static readonly string[] Expected =\n    [\n        \"JY\", \"JAN\", \"JAN\", \"ZAYN\", \"GAR\", \"IG\", \"CAN\", \"LAS\", \"ARNY\", \"OLSAN\", \"CARBAN\", \"NAV\", \"CYNTANALAN\",\n        \"ANANACY\", \"MCGYVAR\", \"YASNANADG\",\n    ];\n\n    private static IEnumerable<string[]> TestData => Names.Zip(Expected, (l, r) => new[] { l, r });\n\n    [TestCaseSource(nameof(TestData))]\n    public void AttemptNysiis(string source, string expected)\n    {\n        var enc = new NysiisEncoder();\n        var nysiis = enc.Encode(source);\n        Assert.That(nysiis, Is.EqualTo(expected));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Encoders/SoundexEncoderTest.cs",
    "content": "using Algorithms.Encoders;\n\nnamespace Algorithms.Tests.Encoders;\n\npublic static class SoundexEncoderTest\n{\n    private static readonly string[] Names =\n    [\n        \"Robert\", \"Rupert\", \"Rubin\", \"Ashcraft\", \"Ashcroft\", \"Tymczak\", \"Pfister\", \"Honeyman\",\n    ];\n\n    private static readonly string[] Expected = [\"R163\", \"R163\", \"R150\", \"A261\", \"A261\", \"T522\", \"P236\", \"H555\"];\n\n    private static IEnumerable<string[]> TestData => Names.Zip(Expected, (l, r) => new[] { l, r });\n\n    [TestCaseSource(nameof(TestData))]\n    public static void AttemptSoundex(string source, string encoded)\n    {\n        SoundexEncoder enc = new();\n        var nysiis = enc.Encode(source);\n        Assert.That(encoded, Is.EqualTo(nysiis));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Encoders/VigenereEncoderTests.cs",
    "content": "using Algorithms.Encoders;\n\nnamespace Algorithms.Tests.Encoders;\n\npublic static class VigenereEncoderTests\n{\n    [Test]\n    [Repeat(100)]\n    public static void DecodedStringIsTheSame()\n    {\n        // Arrange\n        var random = new Randomizer();\n        var encoder = new VigenereEncoder();\n        var message = random.GetString();\n        var key = random.GetString(random.Next(1, 1000));\n\n        // Act\n        var encoded = encoder.Encode(message, key);\n        var decoded = encoder.Decode(encoded, key);\n\n        // Assert\n        Assert.That(decoded, Is.EqualTo(message));\n    }\n\n    [Test]\n    public static void Encode_KeyIsTooShort_KeyIsAppended()\n    {\n        // Arrange\n        var encoder = new VigenereEncoder();\n        var message = new string('a', 2);\n        var key = new string('a', 1);\n\n        // Act\n        var encoded = encoder.Encode(message, key);\n        var decoded = encoder.Decode(encoded, key);\n\n        // Assert\n        Assert.That(decoded, Is.EqualTo(message));\n    }\n\n    [Test]\n    public static void EmptyKeyThrowsException()\n    {\n        var random = new Randomizer();\n        var encoder = new VigenereEncoder();\n        var message = random.GetString();\n        var key = string.Empty;\n\n        _ = Assert.Throws<ArgumentOutOfRangeException>(() => encoder.Encode(message, key));\n        _ = Assert.Throws<ArgumentOutOfRangeException>(() => encoder.Decode(message, key));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Financial/PresentValueTests.cs",
    "content": "using Algorithms.Financial;\n\nnamespace Algorithms.Tests.Financial;\n\npublic static class PresentValueTests\n{\n    [TestCase(0.13, new[] { 10.0, 20.70, -293.0, 297.0 }, 4.69)]\n    [TestCase(0.07, new[] { -109129.39, 30923.23, 15098.93, 29734.0, 39.0 }, -42739.63)]\n    [TestCase(0.07, new[] { 109129.39, 30923.23, 15098.93, 29734.0, 39.0 }, 175519.15)]\n    [TestCase(0.0, new[] { 109129.39, 30923.23, 15098.93, 29734.0, 39.0 }, 184924.55)]\n\n    public static void Present_Value_General_Tests(double discountRate, double[] cashFlow, double expected)\n    =>\n        PresentValue.Calculate(discountRate, cashFlow.ToList())\n           .Should()\n           .Be(expected);\n\n\n    [TestCase(-1.0, new[] { 10.0, 20.70, -293.0, 297.0 })]\n    [TestCase(1.0, new double[] { })]\n\n    public static void Present_Value_Exception_Tests(double discountRate, double[] cashFlow)\n    => Assert.Throws<ArgumentException>(() => PresentValue.Calculate(discountRate, cashFlow.ToList()));\n}\n"
  },
  {
    "path": "Algorithms.Tests/GlobalUsings.cs",
    "content": "// -----------------------------------------------------------------------------\n// Global using directives for the C-Sharp solution.\n// These namespaces are imported globally so they don’t need to be repeatedly declared\n// in individual files, improving readability and reducing boilerplate.\n//\n// Guidelines:\n// - Keep only the most commonly used namespaces here.\n// - Add project-specific namespaces (e.g., Utilities.Extensions) only if they are\n//   required across the majority of files in the project.\n// - Avoid placing rarely used namespaces here to maintain clarity.\n// -----------------------------------------------------------------------------\n\nglobal using System;                        // Core base classes and fundamental types\nglobal using System.Collections.Generic;    // Generic collection types (List, Dictionary, etc.)\nglobal using System.Linq;                   // LINQ query operators for collections\nglobal using System.Numerics;               // Numeric types such as BigInteger and Complex\nglobal using System.Text;                   // Text encoding, StringBuilder, etc.\nglobal using Utilities.Extensions;          // Common extension methods used across the solution\nglobal using NUnit.Framework;               // Testing framework providing attributes and assertions for test cases\nglobal using NUnit.Framework.Internal;      // Internal NUnit infrastructure (test context, utilities) — generally used for advanced or framework-level test control\nglobal using FluentAssertions;              // Assertion library for more readable and expressive unit tests\n"
  },
  {
    "path": "Algorithms.Tests/Graph/ArticulationPointsTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Algorithms.Graph;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace Algorithms.Tests.Graph;\n\npublic class ArticulationPointsTests\n{\n    [Test]\n    public void Find_SimpleChain_ReturnsMiddleVertex()\n    {\n        // Arrange: A - B - C (B is articulation point)\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = ArticulationPoints.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().ContainSingle();\n        result.Should().Contain(\"B\");\n    }\n\n    [Test]\n    public void Find_Triangle_ReturnsEmpty()\n    {\n        // Arrange: A - B - C - A (no articulation points)\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"C\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"A\", \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = ArticulationPoints.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeEmpty();\n    }\n\n    [Test]\n    public void Find_StarGraph_ReturnsCenterVertex()\n    {\n        // Arrange: Star with center A\n        var vertices = new[] { \"A\", \"B\", \"C\", \"D\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"C\", \"D\" },\n            \"B\" => new[] { \"A\" },\n            \"C\" => new[] { \"A\" },\n            \"D\" => new[] { \"A\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = ArticulationPoints.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().ContainSingle();\n        result.Should().Contain(\"A\");\n    }\n\n    [Test]\n    public void Find_BridgeGraph_ReturnsMultiplePoints()\n    {\n        // Arrange: (A-B-C) - D - (E-F-G)\n        var vertices = new[] { \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\", \"C\", \"D\" },\n            \"C\" => new[] { \"B\" },\n            \"D\" => new[] { \"B\", \"E\" },\n            \"E\" => new[] { \"D\", \"F\" },\n            \"F\" => new[] { \"E\", \"G\" },\n            \"G\" => new[] { \"F\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = ArticulationPoints.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().HaveCount(4);\n        result.Should().Contain(new[] { \"B\", \"D\", \"E\", \"F\" });\n    }\n\n    [Test]\n    public void Find_DisconnectedGraph_FindsPointsInEachComponent()\n    {\n        // Arrange: (A-B-C) and (D-E-F)\n        var vertices = new[] { \"A\", \"B\", \"C\", \"D\", \"E\", \"F\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\" },\n            \"D\" => new[] { \"E\" },\n            \"E\" => new[] { \"D\", \"F\" },\n            \"F\" => new[] { \"E\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = ArticulationPoints.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().HaveCount(2);\n        result.Should().Contain(new[] { \"B\", \"E\" });\n    }\n\n    [Test]\n    public void Find_SingleVertex_ReturnsEmpty()\n    {\n        // Arrange\n        var vertices = new[] { \"A\" };\n        IEnumerable<string> GetNeighbors(string v) => Array.Empty<string>();\n\n        // Act\n        var result = ArticulationPoints.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeEmpty();\n    }\n\n    [Test]\n    public void Find_TwoVertices_ReturnsEmpty()\n    {\n        // Arrange: A - B\n        var vertices = new[] { \"A\", \"B\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = ArticulationPoints.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeEmpty();\n    }\n\n    [Test]\n    public void Find_ComplexGraph_ReturnsCorrectPoints()\n    {\n        // Arrange: Complex graph with multiple articulation points\n        var vertices = new[] { 1, 2, 3, 4, 5, 6, 7 };\n        IEnumerable<int> GetNeighbors(int v) => v switch\n        {\n            1 => new[] { 2, 3 },\n            2 => new[] { 1, 3 },\n            3 => new[] { 1, 2, 4 },\n            4 => new[] { 3, 5, 6 },\n            5 => new[] { 4, 6 },\n            6 => new[] { 4, 5, 7 },\n            7 => new[] { 6 },\n            _ => Array.Empty<int>(),\n        };\n\n        // Act\n        var result = ArticulationPoints.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().Contain(new[] { 3, 4, 6 });\n    }\n\n    [Test]\n    public void Find_EmptyGraph_ReturnsEmpty()\n    {\n        // Arrange\n        var vertices = Array.Empty<string>();\n        IEnumerable<string> GetNeighbors(string v) => Array.Empty<string>();\n\n        // Act\n        var result = ArticulationPoints.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeEmpty();\n    }\n\n    [Test]\n    public void Find_NullVertices_ThrowsArgumentNullException()\n    {\n        // Act\n        Action act = () => ArticulationPoints.Find<string>(null!, v => Array.Empty<string>());\n\n        // Assert\n        act.Should().Throw<ArgumentNullException>().WithParameterName(\"vertices\");\n    }\n\n    [Test]\n    public void Find_NullGetNeighbors_ThrowsArgumentNullException()\n    {\n        // Arrange\n        var vertices = new[] { \"A\" };\n\n        // Act\n        Action act = () => ArticulationPoints.Find(vertices, null!);\n\n        // Assert\n        act.Should().Throw<ArgumentNullException>().WithParameterName(\"getNeighbors\");\n    }\n\n    [Test]\n    public void IsArticulationPoint_ValidPoint_ReturnsTrue()\n    {\n        // Arrange: A - B - C\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = ArticulationPoints.IsArticulationPoint(\"B\", vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void IsArticulationPoint_NotArticulationPoint_ReturnsFalse()\n    {\n        // Arrange: A - B - C\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = ArticulationPoints.IsArticulationPoint(\"A\", vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeFalse();\n    }\n\n    [Test]\n    public void Count_SimpleChain_ReturnsOne()\n    {\n        // Arrange: A - B - C\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = ArticulationPoints.Count(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().Be(1);\n    }\n\n    [Test]\n    public void Count_Triangle_ReturnsZero()\n    {\n        // Arrange: A - B - C - A\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"C\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"A\", \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = ArticulationPoints.Count(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().Be(0);\n    }\n\n    [Test]\n    public void Find_LargeGraph_FindsAllPoints()\n    {\n        // Arrange: Large chain\n        var vertices = Enumerable.Range(1, 10).ToArray();\n        IEnumerable<int> GetNeighbors(int v)\n        {\n            var neighbors = new List<int>();\n            if (v > 1)\n            {\n                neighbors.Add(v - 1);\n            }\n\n            if (v < 10)\n            {\n                neighbors.Add(v + 1);\n            }\n\n            return neighbors;\n        }\n\n        // Act\n        var result = ArticulationPoints.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().HaveCount(8); // All except endpoints\n        result.Should().NotContain(new[] { 1, 10 });\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Graph/BellmanFordTests.cs",
    "content": "using Algorithms.Graph;\nusing DataStructures.Graph;\n\nnamespace Algorithms.Tests.Graph;\n\npublic class BellmanFordTests\n{\n    [Test]\n    public void CorrectDistancesTest()\n    {\n        var graph = new DirectedWeightedGraph<int>(10);\n\n        var vertex1 = graph.AddVertex(1);\n        var vertex2 = graph.AddVertex(2);\n        var vertex3 = graph.AddVertex(3);\n        var vertex4 = graph.AddVertex(4);\n        var vertex5 = graph.AddVertex(5);\n\n        graph.AddEdge(vertex1, vertex2, 3);\n        graph.AddEdge(vertex1, vertex5, -4);\n        graph.AddEdge(vertex1, vertex3, 8);\n        graph.AddEdge(vertex2, vertex5, 7);\n        graph.AddEdge(vertex2, vertex4, 1);\n        graph.AddEdge(vertex3, vertex2, 4);\n        graph.AddEdge(vertex4, vertex3, -5);\n        graph.AddEdge(vertex4, vertex1, 2);\n        graph.AddEdge(vertex5, vertex4, 6);\n\n        var expectedDistances = new Dictionary<Vertex<int>, double>\n        {\n            { vertex1, 0 },\n            { vertex2, 1 },\n            { vertex3, -3 },\n            { vertex4, 2 },\n            { vertex5, -4 }\n        };\n\n        var bellmanFord = new BellmanFord<int>(graph, [], []);\n\n        var calculatedDistances = bellmanFord.Run(vertex1);\n\n        foreach (var vertex in graph.Vertices)\n        {\n            if (vertex != null)\n            {\n                calculatedDistances[vertex].Should().BeApproximately(expectedDistances[vertex], 0.001);\n            }\n        }\n    }\n\n    [Test]\n    public void NegativeWeightCycleTest()\n    {\n        var graph = new DirectedWeightedGraph<int>(3);\n\n        var vertex1 = graph.AddVertex(1);\n        var vertex2 = graph.AddVertex(2);\n        var vertex3 = graph.AddVertex(3);\n\n        graph.AddEdge(vertex1, vertex2, -1);\n        graph.AddEdge(vertex2, vertex3, -2);\n        graph.AddEdge(vertex3, vertex1, -3);\n\n        var bellmanFord = new BellmanFord<int>(graph, [], []);\n\n        Action action = () => bellmanFord.Run(vertex1);\n\n        action.Should().Throw<InvalidOperationException>().WithMessage(\"Graph contains a negative weight cycle.\");\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Graph/BipartiteGraphTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Algorithms.Graph;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace Algorithms.Tests.Graph;\n\npublic class BipartiteGraphTests\n{\n    [Test]\n    public void IsBipartite_EmptyGraph_ReturnsTrue()\n    {\n        // Arrange\n        var vertices = Array.Empty<string>();\n        IEnumerable<string> GetNeighbors(string v) => Array.Empty<string>();\n\n        // Act\n        var result = BipartiteGraph.IsBipartite(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void IsBipartite_SingleVertex_ReturnsTrue()\n    {\n        // Arrange\n        var vertices = new[] { \"A\" };\n        IEnumerable<string> GetNeighbors(string v) => Array.Empty<string>();\n\n        // Act\n        var result = BipartiteGraph.IsBipartite(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void IsBipartite_TwoVerticesConnected_ReturnsTrue()\n    {\n        // Arrange: A - B\n        var vertices = new[] { \"A\", \"B\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.IsBipartite(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void IsBipartite_Triangle_ReturnsFalse()\n    {\n        // Arrange: A - B - C - A (odd cycle)\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"C\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"A\", \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.IsBipartite(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeFalse();\n    }\n\n    [Test]\n    public void IsBipartite_Square_ReturnsTrue()\n    {\n        // Arrange: A - B - C - D - A (even cycle)\n        var vertices = new[] { \"A\", \"B\", \"C\", \"D\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"D\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\", \"D\" },\n            \"D\" => new[] { \"A\", \"C\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.IsBipartite(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void IsBipartite_CompleteBipartiteK23_ReturnsTrue()\n    {\n        // Arrange: Complete bipartite K(2,3)\n        var vertices = new[] { \"A\", \"B\", \"X\", \"Y\", \"Z\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"X\", \"Y\", \"Z\" },\n            \"B\" => new[] { \"X\", \"Y\", \"Z\" },\n            \"X\" => new[] { \"A\", \"B\" },\n            \"Y\" => new[] { \"A\", \"B\" },\n            \"Z\" => new[] { \"A\", \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.IsBipartite(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void IsBipartite_DisconnectedBipartiteComponents_ReturnsTrue()\n    {\n        // Arrange: (A-B) and (C-D)\n        var vertices = new[] { \"A\", \"B\", \"C\", \"D\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\" },\n            \"C\" => new[] { \"D\" },\n            \"D\" => new[] { \"C\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.IsBipartite(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void IsBipartite_DisconnectedWithOddCycle_ReturnsFalse()\n    {\n        // Arrange: (A-B) and (C-D-E-C triangle)\n        var vertices = new[] { \"A\", \"B\", \"C\", \"D\", \"E\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\" },\n            \"C\" => new[] { \"D\", \"E\" },\n            \"D\" => new[] { \"C\", \"E\" },\n            \"E\" => new[] { \"C\", \"D\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.IsBipartite(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeFalse();\n    }\n\n    [Test]\n    public void IsBipartite_StarGraph_ReturnsTrue()\n    {\n        // Arrange: Star with center A\n        var vertices = new[] { \"A\", \"B\", \"C\", \"D\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"C\", \"D\" },\n            \"B\" => new[] { \"A\" },\n            \"C\" => new[] { \"A\" },\n            \"D\" => new[] { \"A\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.IsBipartite(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void IsBipartite_Pentagon_ReturnsFalse()\n    {\n        // Arrange: Pentagon (5-cycle)\n        var vertices = new[] { 1, 2, 3, 4, 5 };\n        IEnumerable<int> GetNeighbors(int v) => v switch\n        {\n            1 => new[] { 2, 5 },\n            2 => new[] { 1, 3 },\n            3 => new[] { 2, 4 },\n            4 => new[] { 3, 5 },\n            5 => new[] { 1, 4 },\n            _ => Array.Empty<int>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.IsBipartite(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeFalse();\n    }\n\n    [Test]\n    public void IsBipartite_NullVertices_ThrowsArgumentNullException()\n    {\n        // Act\n        Action act = () => BipartiteGraph.IsBipartite<string>(null!, v => Array.Empty<string>());\n\n        // Assert\n        act.Should().Throw<ArgumentNullException>().WithParameterName(\"vertices\");\n    }\n\n    [Test]\n    public void IsBipartite_NullGetNeighbors_ThrowsArgumentNullException()\n    {\n        // Arrange\n        var vertices = new[] { \"A\" };\n\n        // Act\n        Action act = () => BipartiteGraph.IsBipartite(vertices, null!);\n\n        // Assert\n        act.Should().Throw<ArgumentNullException>().WithParameterName(\"getNeighbors\");\n    }\n\n    [Test]\n    public void GetPartitions_BipartiteGraph_ReturnsCorrectSets()\n    {\n        // Arrange: A - B - C - D (chain)\n        var vertices = new[] { \"A\", \"B\", \"C\", \"D\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\", \"D\" },\n            \"D\" => new[] { \"C\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.GetPartitions(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().NotBeNull();\n        result!.Value.SetA.Should().Contain(new[] { \"A\", \"C\" });\n        result.Value.SetB.Should().Contain(new[] { \"B\", \"D\" });\n    }\n\n    [Test]\n    public void GetPartitions_NonBipartiteGraph_ReturnsNull()\n    {\n        // Arrange: Triangle\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"C\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"A\", \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.GetPartitions(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeNull();\n    }\n\n    [Test]\n    public void GetPartitions_EmptyGraph_ReturnsEmptySets()\n    {\n        // Arrange\n        var vertices = Array.Empty<string>();\n        IEnumerable<string> GetNeighbors(string v) => Array.Empty<string>();\n\n        // Act\n        var result = BipartiteGraph.GetPartitions(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().NotBeNull();\n        result!.Value.SetA.Should().BeEmpty();\n        result.Value.SetB.Should().BeEmpty();\n    }\n\n    [Test]\n    public void GetPartitions_NullVertices_ThrowsArgumentNullException()\n    {\n        // Act\n        Action act = () => BipartiteGraph.GetPartitions<string>(null!, v => Array.Empty<string>());\n\n        // Assert\n        act.Should().Throw<ArgumentNullException>().WithParameterName(\"vertices\");\n    }\n\n    [Test]\n    public void GetPartitions_NullGetNeighbors_ThrowsArgumentNullException()\n    {\n        // Arrange\n        var vertices = new[] { \"A\" };\n\n        // Act\n        Action act = () => BipartiteGraph.GetPartitions(vertices, null!);\n\n        // Assert\n        act.Should().Throw<ArgumentNullException>().WithParameterName(\"getNeighbors\");\n    }\n\n    [Test]\n    public void IsBipartiteDfs_BipartiteGraph_ReturnsTrue()\n    {\n        // Arrange: Square\n        var vertices = new[] { \"A\", \"B\", \"C\", \"D\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"D\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\", \"D\" },\n            \"D\" => new[] { \"A\", \"C\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.IsBipartiteDfs(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void IsBipartiteDfs_NonBipartiteGraph_ReturnsFalse()\n    {\n        // Arrange: Triangle\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"C\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"A\", \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.IsBipartiteDfs(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeFalse();\n    }\n\n    [Test]\n    public void IsBipartiteDfs_NullVertices_ThrowsArgumentNullException()\n    {\n        // Act\n        Action act = () => BipartiteGraph.IsBipartiteDfs<string>(null!, v => Array.Empty<string>());\n\n        // Assert\n        act.Should().Throw<ArgumentNullException>().WithParameterName(\"vertices\");\n    }\n\n    [Test]\n    public void IsBipartiteDfs_NullGetNeighbors_ThrowsArgumentNullException()\n    {\n        // Arrange\n        var vertices = new[] { \"A\" };\n\n        // Act\n        Action act = () => BipartiteGraph.IsBipartiteDfs(vertices, null!);\n\n        // Assert\n        act.Should().Throw<ArgumentNullException>().WithParameterName(\"getNeighbors\");\n    }\n\n    [Test]\n    public void IsBipartite_LargeEvenCycle_ReturnsTrue()\n    {\n        // Arrange: Large even cycle (100 vertices)\n        var vertices = Enumerable.Range(0, 100).ToArray();\n        IEnumerable<int> GetNeighbors(int v)\n        {\n            var neighbors = new List<int>\n            {\n                v > 0 ? v - 1 : 99, // Previous or close cycle\n                v < 99 ? v + 1 : 0, // Next or close cycle\n            };\n\n            return neighbors;\n        }\n\n        // Act\n        var result = BipartiteGraph.IsBipartite(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void IsBipartite_LargeOddCycle_ReturnsFalse()\n    {\n        // Arrange: Large odd cycle (101 vertices)\n        var vertices = Enumerable.Range(0, 101).ToArray();\n        IEnumerable<int> GetNeighbors(int v)\n        {\n            var neighbors = new List<int>\n            {\n                v > 0 ? v - 1 : 100, // Previous or close cycle\n                v < 100 ? v + 1 : 0, // Next or close cycle\n            };\n\n            return neighbors;\n        }\n\n        // Act\n        var result = BipartiteGraph.IsBipartite(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeFalse();\n    }\n\n    [Test]\n    public void GetPartitions_CompleteBipartite_ReturnsCorrectSets()\n    {\n        // Arrange: K(2,2)\n        var vertices = new[] { \"A\", \"B\", \"X\", \"Y\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"X\", \"Y\" },\n            \"B\" => new[] { \"X\", \"Y\" },\n            \"X\" => new[] { \"A\", \"B\" },\n            \"Y\" => new[] { \"A\", \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = BipartiteGraph.GetPartitions(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().NotBeNull();\n        result!.Value.SetA.Should().HaveCount(2);\n        result.Value.SetB.Should().HaveCount(2);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Graph/BreadthFirstSearchTests.cs",
    "content": "using Algorithms.Graph;\nusing DataStructures.Graph;\n\nnamespace Algorithms.Tests.Graph;\n\npublic class BreadthFirstSearchTests\n{\n    [Test]\n    public void VisitAll_ShouldCountNumberOfVisitedVertix_ResultShouldBeTheSameAsNumberOfVerticesInGraph()\n    {\n        //Arrange\n        var graph = new DirectedWeightedGraph<int>(10);\n\n        var vertex1 = graph.AddVertex(1);\n\n        var vertex2 = graph.AddVertex(20);\n\n        var vertex3 = graph.AddVertex(40);\n\n        var vertex4 = graph.AddVertex(40);\n\n        graph.AddEdge(vertex1, vertex2, 1);\n\n        graph.AddEdge(vertex2, vertex3, 1);\n\n        graph.AddEdge(vertex2, vertex4, 1);\n\n        graph.AddEdge(vertex4, vertex1, 1);\n\n        var dfsSearcher = new BreadthFirstSearch<int>();\n\n        long countOfVisitedVertices = 0;\n\n        //Act\n        dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVertices++);\n\n        //Assert\n        Assert.That(graph.Count, Is.EqualTo(countOfVisitedVertices));\n    }\n\n    [Test]\n    public void VisitAll_ShouldCountNumberOfVisitedVerices_TwoSeparatedGraphInOne()\n    {\n        //Arrange\n        var graph = new DirectedWeightedGraph<int>(10);\n\n        var vertex1 = graph.AddVertex(1);\n\n        var vertex2 = graph.AddVertex(20);\n\n        var vertex3 = graph.AddVertex(40);\n\n        var vertex4 = graph.AddVertex(40);\n\n        var vertex5 = graph.AddVertex(40);\n\n        var vertex6 = graph.AddVertex(40);\n\n        graph.AddEdge(vertex1, vertex2, 1);\n\n        graph.AddEdge(vertex2, vertex3, 1);\n\n        graph.AddEdge(vertex4, vertex5, 1);\n\n        graph.AddEdge(vertex5, vertex6, 1);\n\n        var dfsSearcher = new BreadthFirstSearch<int>();\n\n        long countOfVisitedVerticesPerFirstGraph = 0;\n\n        long countOfVisitedVerticesPerSecondGraph = 0;\n\n        //Act\n        dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVerticesPerFirstGraph++);\n\n        dfsSearcher.VisitAll(graph, vertex4, _ => countOfVisitedVerticesPerSecondGraph++);\n\n        //Assert\n        Assert.That(countOfVisitedVerticesPerFirstGraph, Is.EqualTo(3));\n\n        Assert.That(countOfVisitedVerticesPerSecondGraph, Is.EqualTo(3));\n    }\n\n    [Test]\n    public void VisitAll_ReturnTheSuqenceOfVertices_ShouldBeTheSameAsExpected()\n    {\n        //Arrange\n        var graph = new DirectedWeightedGraph<int>(10);\n\n        var vertex1 = graph.AddVertex(1);\n\n        var vertex2 = graph.AddVertex(20);\n\n        var vertex3 = graph.AddVertex(40);\n\n        var vertex4 = graph.AddVertex(40);\n\n        var vertex5 = graph.AddVertex(40);\n\n        graph.AddEdge(vertex1, vertex2, 1);\n\n        graph.AddEdge(vertex1, vertex5, 1);\n\n        graph.AddEdge(vertex2, vertex3, 1);\n\n        graph.AddEdge(vertex2, vertex5, 1);\n\n        graph.AddEdge(vertex2, vertex4, 1);\n\n        var dfsSearcher = new BreadthFirstSearch<int>();\n\n        var expectedSequenceOfVisitedVertices = new List<Vertex<int>>\n        {\n            vertex1,\n            vertex2,\n            vertex5,\n            vertex3,\n            vertex4,\n        };\n\n        var sequenceOfVisitedVertices = new List<Vertex<int>>();\n\n        //Act\n        dfsSearcher.VisitAll(graph, vertex1, vertex => sequenceOfVisitedVertices.Add(vertex));\n\n        //Assert\n        Assert.That(sequenceOfVisitedVertices, Is.EqualTo(expectedSequenceOfVisitedVertices));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Graph/BreadthFirstTreeTraversalTests.cs",
    "content": "using Algorithms.Graph;\nusing DataStructures.BinarySearchTree;\n\nnamespace Algorithms.Tests.Graph;\n\npublic static class BreadthFirstTreeTraversalTests\n{\n    [Test]\n    public static void CorrectLevelOrderTraversal()\n    {\n        // Arrange\n        int[] correctPath = [7, 4, 13, 2, 5, 11, 15, 14, 16];\n        int[] insertionOrder = [7, 13, 11, 15, 14, 4, 5, 16, 2];\n        BinarySearchTree<int> testTree = new BinarySearchTree<int>();\n        foreach (int data in insertionOrder)\n        {\n            testTree.Add(data);\n        }\n\n        // Act\n        int[] levelOrder = BreadthFirstTreeTraversal<int>.LevelOrderTraversal(testTree);\n\n        // Assert\n        Assert.That(correctPath, Is.EqualTo(levelOrder));\n    }\n\n    [Test]\n    public static void EmptyArrayForNullRoot()\n    {\n        // Arrange\n        BinarySearchTree<int> testTree = new BinarySearchTree<int>();\n\n        // Act\n        int[] levelOrder = BreadthFirstTreeTraversal<int>.LevelOrderTraversal(testTree);\n\n        // Assert\n        Assert.That(levelOrder, Is.Empty);\n    }\n\n    [TestCase(new[] { 7, 9, 5 })]\n    [TestCase(new[] { 7, 13, 11, 15, 14, 4, 5, 16, 2 })]\n    public static void IncorrectLevelOrderTraversal(int[] insertion)\n    {\n        // Arrange\n        BinarySearchTree<int> testTree = new BinarySearchTree<int>();\n        foreach (int data in insertion)\n        {\n            testTree.Add(data);\n        }\n\n        // Act\n        int[] levelOrder = BreadthFirstTreeTraversal<int>.LevelOrderTraversal(testTree);\n\n        // Assert\n        Assert.That(insertion, Is.Not.EqualTo(levelOrder));\n    }\n\n    [Test]\n    public static void DeepestNodeInTree()\n    {\n        // Arrange\n        BinarySearchTree<int> testTree = new BinarySearchTree<int>();\n        int[] insertion = [7, 13, 11, 15, 4, 5, 12, 2, 9];\n        foreach (int data in insertion)\n        {\n            testTree.Add(data);\n        }\n\n        // Act\n        int deepest = BreadthFirstTreeTraversal<int>.DeepestNode(testTree);\n\n        // Assert\n        Assert.That(deepest, Is.EqualTo(12));\n    }\n\n    [Test]\n    public static void DeepestNodeOfEmptyTree()\n    {\n        // Arrange\n        BinarySearchTree<int?> testTree = new BinarySearchTree<int?>();\n\n        // Act\n        int? deepest = BreadthFirstTreeTraversal<int?>.DeepestNode(testTree);\n\n        // Assert\n        Assert.That(deepest, Is.Null);\n    }\n}\n\n"
  },
  {
    "path": "Algorithms.Tests/Graph/BridgesTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Algorithms.Graph;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace Algorithms.Tests.Graph;\n\npublic class BridgesTests\n{\n    [Test]\n    public void Find_SimpleChain_ReturnsAllEdges()\n    {\n        // Arrange: A - B - C (both edges are bridges)\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = Bridges.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().HaveCount(2);\n        result.Should().Contain(new[] { (\"A\", \"B\"), (\"B\", \"C\") });\n    }\n\n    [Test]\n    public void Find_Triangle_ReturnsEmpty()\n    {\n        // Arrange: A - B - C - A (no bridges in cycle)\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"C\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"A\", \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = Bridges.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeEmpty();\n    }\n\n    [Test]\n    public void Find_TwoComponentsConnectedByBridge_ReturnsBridge()\n    {\n        // Arrange: (A-B-C) - D - (E-F-G)\n        var vertices = new[] { \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"C\" },\n            \"B\" => new[] { \"A\", \"C\", \"D\" },\n            \"C\" => new[] { \"A\", \"B\" },\n            \"D\" => new[] { \"B\", \"E\" },\n            \"E\" => new[] { \"D\", \"F\", \"G\" },\n            \"F\" => new[] { \"E\", \"G\" },\n            \"G\" => new[] { \"E\", \"F\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = Bridges.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().HaveCount(2);\n        result.Should().Contain(new[] { (\"B\", \"D\"), (\"D\", \"E\") });\n    }\n\n    [Test]\n    public void Find_StarGraph_ReturnsAllEdges()\n    {\n        // Arrange: Star with center A\n        var vertices = new[] { \"A\", \"B\", \"C\", \"D\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"C\", \"D\" },\n            \"B\" => new[] { \"A\" },\n            \"C\" => new[] { \"A\" },\n            \"D\" => new[] { \"A\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = Bridges.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().HaveCount(3);\n        result.Should().Contain(new[] { (\"A\", \"B\"), (\"A\", \"C\"), (\"A\", \"D\") });\n    }\n\n    [Test]\n    public void Find_DisconnectedGraph_FindsBridgesInEachComponent()\n    {\n        // Arrange: (A-B-C) and (D-E-F)\n        var vertices = new[] { \"A\", \"B\", \"C\", \"D\", \"E\", \"F\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\" },\n            \"D\" => new[] { \"E\" },\n            \"E\" => new[] { \"D\", \"F\" },\n            \"F\" => new[] { \"E\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = Bridges.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().HaveCount(4);\n        result.Should().Contain(new[] { (\"A\", \"B\"), (\"B\", \"C\"), (\"D\", \"E\"), (\"E\", \"F\") });\n    }\n\n    [Test]\n    public void Find_SingleVertex_ReturnsEmpty()\n    {\n        // Arrange\n        var vertices = new[] { \"A\" };\n        IEnumerable<string> GetNeighbors(string v) => Array.Empty<string>();\n\n        // Act\n        var result = Bridges.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeEmpty();\n    }\n\n    [Test]\n    public void Find_TwoVertices_ReturnsBridge()\n    {\n        // Arrange: A - B\n        var vertices = new[] { \"A\", \"B\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = Bridges.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().ContainSingle();\n        result.Should().Contain((\"A\", \"B\"));\n    }\n\n    [Test]\n    public void Find_ComplexGraph_ReturnsCorrectBridges()\n    {\n        // Arrange: Complex graph with cycles and bridges\n        var vertices = new[] { 1, 2, 3, 4, 5, 6, 7 };\n        IEnumerable<int> GetNeighbors(int v) => v switch\n        {\n            1 => new[] { 2, 3 },\n            2 => new[] { 1, 3 },\n            3 => new[] { 1, 2, 4 },\n            4 => new[] { 3, 5, 6 },\n            5 => new[] { 4, 6 },\n            6 => new[] { 4, 5, 7 },\n            7 => new[] { 6 },\n            _ => Array.Empty<int>(),\n        };\n\n        // Act\n        var result = Bridges.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().Contain(new[] { (3, 4), (6, 7) });\n    }\n\n    [Test]\n    public void Find_EmptyGraph_ReturnsEmpty()\n    {\n        // Arrange\n        var vertices = Array.Empty<string>();\n        IEnumerable<string> GetNeighbors(string v) => Array.Empty<string>();\n\n        // Act\n        var result = Bridges.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeEmpty();\n    }\n\n    [Test]\n    public void Find_NullVertices_ThrowsArgumentNullException()\n    {\n        // Act\n        Action act = () => Bridges.Find<string>(null!, v => Array.Empty<string>());\n\n        // Assert\n        act.Should().Throw<ArgumentNullException>().WithParameterName(\"vertices\");\n    }\n\n    [Test]\n    public void Find_NullGetNeighbors_ThrowsArgumentNullException()\n    {\n        // Arrange\n        var vertices = new[] { \"A\" };\n\n        // Act\n        Action act = () => Bridges.Find(vertices, null!);\n\n        // Assert\n        act.Should().Throw<ArgumentNullException>().WithParameterName(\"getNeighbors\");\n    }\n\n    [Test]\n    public void IsBridge_ValidBridge_ReturnsTrue()\n    {\n        // Arrange: A - B - C\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = Bridges.IsBridge(\"A\", \"B\", vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void IsBridge_ReverseEdge_ReturnsTrue()\n    {\n        // Arrange: A - B - C\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = Bridges.IsBridge(\"B\", \"A\", vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void IsBridge_NotBridge_ReturnsFalse()\n    {\n        // Arrange: A - B - C - A (triangle)\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"C\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"A\", \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = Bridges.IsBridge(\"A\", \"B\", vertices, GetNeighbors);\n\n        // Assert\n        result.Should().BeFalse();\n    }\n\n    [Test]\n    public void Count_SimpleChain_ReturnsTwo()\n    {\n        // Arrange: A - B - C\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = Bridges.Count(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().Be(2);\n    }\n\n    [Test]\n    public void Count_Triangle_ReturnsZero()\n    {\n        // Arrange: A - B - C - A\n        var vertices = new[] { \"A\", \"B\", \"C\" };\n        IEnumerable<string> GetNeighbors(string v) => v switch\n        {\n            \"A\" => new[] { \"B\", \"C\" },\n            \"B\" => new[] { \"A\", \"C\" },\n            \"C\" => new[] { \"A\", \"B\" },\n            _ => Array.Empty<string>(),\n        };\n\n        // Act\n        var result = Bridges.Count(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().Be(0);\n    }\n\n    [Test]\n    public void Find_LargeChain_FindsAllBridges()\n    {\n        // Arrange: Large chain\n        var vertices = Enumerable.Range(1, 10).ToArray();\n        IEnumerable<int> GetNeighbors(int v)\n        {\n            var neighbors = new List<int>();\n            if (v > 1)\n            {\n                neighbors.Add(v - 1);\n            }\n\n            if (v < 10)\n            {\n                neighbors.Add(v + 1);\n            }\n\n            return neighbors;\n        }\n\n        // Act\n        var result = Bridges.Find(vertices, GetNeighbors);\n\n        // Assert\n        result.Should().HaveCount(9); // All edges in chain are bridges\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Graph/DepthFirstSearchTests.cs",
    "content": "using Algorithms.Graph;\nusing DataStructures.Graph;\n\nnamespace Algorithms.Tests.Graph;\n\npublic class DepthFirstSearchTests\n{\n    [Test]\n    public void VisitAll_ShouldCountNumberOfVisitedVertix_ResultShouldBeTheSameAsNumberOfVerticesInGraph()\n    {\n        //Arrange\n        var graph = new DirectedWeightedGraph<int>(10);\n\n        var vertex1 = graph.AddVertex(1);\n\n        var vertex2 = graph.AddVertex(20);\n\n        var vertex3 = graph.AddVertex(40);\n\n        var vertex4 = graph.AddVertex(40);\n\n        graph.AddEdge(vertex1, vertex2, 1);\n\n        graph.AddEdge(vertex2, vertex3, 1);\n\n        graph.AddEdge(vertex2, vertex4, 1);\n\n        graph.AddEdge(vertex4, vertex1, 1);\n\n        var dfsSearcher = new DepthFirstSearch<int>();\n\n        long countOfVisitedVertices = 0;\n\n        //Act\n        dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVertices++);\n\n        //Assert\n        Assert.That(graph.Count, Is.EqualTo(countOfVisitedVertices));\n    }\n\n    [Test]\n    public void VisitAll_ShouldCountNumberOfVisitedVertices_TwoSeparatedGraphInOne()\n    {\n        //Arrange\n        var graph = new DirectedWeightedGraph<int>(10);\n\n        var vertex1 = graph.AddVertex(1);\n\n        var vertex2 = graph.AddVertex(20);\n\n        var vertex3 = graph.AddVertex(40);\n\n        var vertex4 = graph.AddVertex(40);\n\n        var vertex5 = graph.AddVertex(40);\n\n        var vertex6 = graph.AddVertex(40);\n\n        graph.AddEdge(vertex1, vertex2, 1);\n\n        graph.AddEdge(vertex2, vertex3, 1);\n\n        graph.AddEdge(vertex4, vertex5, 1);\n\n        graph.AddEdge(vertex5, vertex6, 1);\n\n        var dfsSearcher = new DepthFirstSearch<int>();\n\n        long countOfVisitedVerticesPerFirstGraph = 0;\n\n        long countOfVisitedVerticesPerSecondGraph = 0;\n\n        //Act\n        dfsSearcher.VisitAll(graph, vertex1, _ => countOfVisitedVerticesPerFirstGraph++);\n\n        dfsSearcher.VisitAll(graph, vertex4, _ => countOfVisitedVerticesPerSecondGraph++);\n\n        //Assert\n        Assert.That(3, Is.EqualTo(countOfVisitedVerticesPerFirstGraph));\n\n        Assert.That(3, Is.EqualTo(countOfVisitedVerticesPerSecondGraph));\n    }\n\n    [Test]\n    public void VisitAll_ReturnTheSuqenceOfVertices_ShouldBeTheSameAsExpected()\n    {\n        //Arrange\n        var graph = new DirectedWeightedGraph<int>(10);\n\n        var vertex1 = graph.AddVertex(1);\n\n        var vertex2 = graph.AddVertex(20);\n\n        var vertex3 = graph.AddVertex(40);\n\n        var vertex4 = graph.AddVertex(40);\n\n        var vertex5 = graph.AddVertex(40);\n\n        graph.AddEdge(vertex1, vertex2, 1);\n\n        graph.AddEdge(vertex2, vertex3, 1);\n\n        graph.AddEdge(vertex2, vertex4, 1);\n\n        graph.AddEdge(vertex3, vertex5, 1);\n\n        var dfsSearcher = new DepthFirstSearch<int>();\n\n        var expectedSequenceOfVisitedVertices = new List<Vertex<int>>\n        {\n            vertex1,\n            vertex2,\n            vertex3,\n            vertex5,\n            vertex4,\n        };\n\n        var sequenceOfVisitedVertices = new List<Vertex<int>>();\n\n        //Act\n        dfsSearcher.VisitAll(graph, vertex1, vertex => sequenceOfVisitedVertices.Add(vertex));\n\n        //Assert\n        Assert.That(sequenceOfVisitedVertices, Is.EqualTo(expectedSequenceOfVisitedVertices));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Graph/Dijkstra/DijkstraTests.cs",
    "content": "using Algorithms.Graph.Dijkstra;\nusing DataStructures.Graph;\n\nnamespace Algorithms.Tests.Graph.Dijkstra;\n\n[TestFixture]\npublic class DijkstraTests\n{\n    [Test]\n    public void DijkstraTest1_Success()\n    {\n        // here test case is from https://www.youtube.com/watch?v=pVfj6mxhdMw\n\n        var graph = new DirectedWeightedGraph<char>(5);\n        var a = graph.AddVertex('A');\n        var b = graph.AddVertex('B');\n        var c = graph.AddVertex('C');\n        var d = graph.AddVertex('D');\n        var e = graph.AddVertex('E');\n\n        graph.AddEdge(a, b, 6);\n        graph.AddEdge(b, a, 6);\n\n        graph.AddEdge(a, d, 1);\n        graph.AddEdge(d, a, 1);\n\n        graph.AddEdge(d, e, 1);\n        graph.AddEdge(e, d, 1);\n\n        graph.AddEdge(d, b, 2);\n        graph.AddEdge(b, d, 2);\n\n        graph.AddEdge(e, b, 2);\n        graph.AddEdge(b, e, 2);\n\n        graph.AddEdge(e, c, 5);\n        graph.AddEdge(c, e, 5);\n\n        graph.AddEdge(c, b, 5);\n        graph.AddEdge(b, c, 5);\n\n        var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a);\n        shortestPathList.Length.Should().Be(5);\n\n        shortestPathList[0].Vertex.Should().Be(a);\n        shortestPathList[0].Distance.Should().Be(0);\n        shortestPathList[0].PreviousVertex.Should().Be(a);\n        shortestPathList[0].ToString().Should()\n            .Be($\"Vertex: {a} - Distance: {0} - Previous: {a}\");\n\n        shortestPathList[1].Vertex.Should().Be(b);\n        shortestPathList[1].Distance.Should().Be(3);\n        shortestPathList[1].PreviousVertex.Should().Be(d);\n        shortestPathList[1].ToString().Should()\n            .Be($\"Vertex: {b} - Distance: {3} - Previous: {d}\");\n\n        shortestPathList[2].Vertex.Should().Be(c);\n        shortestPathList[2].Distance.Should().Be(7);\n        shortestPathList[2].PreviousVertex.Should().Be(e);\n        shortestPathList[2].ToString().Should()\n            .Be($\"Vertex: {c} - Distance: {7} - Previous: {e}\");\n\n        shortestPathList[3].Vertex.Should().Be(d);\n        shortestPathList[3].Distance.Should().Be(1);\n        shortestPathList[3].PreviousVertex.Should().Be(a);\n        shortestPathList[3].ToString().Should()\n            .Be($\"Vertex: {d} - Distance: {1} - Previous: {a}\");\n\n        shortestPathList[4].Vertex.Should().Be(e);\n        shortestPathList[4].Distance.Should().Be(2);\n        shortestPathList[4].PreviousVertex.Should().Be(d);\n        shortestPathList[4].ToString().Should()\n            .Be($\"Vertex: {e} - Distance: {2} - Previous: {d}\");\n    }\n\n    [Test]\n    public void DijkstraTest2_Success()\n    {\n        var graph = new DirectedWeightedGraph<char>(5);\n        var a = graph.AddVertex('A');\n        var b = graph.AddVertex('B');\n        var c = graph.AddVertex('C');\n\n        graph.AddEdge(a, b, 1);\n        graph.AddEdge(b, a, 1);\n\n        graph.AddEdge(b, c, 1);\n        graph.AddEdge(c, b, 1);\n\n        graph.AddEdge(a, c, 3);\n        graph.AddEdge(c, a, 3);\n\n        var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a);\n\n        shortestPathList.Length.Should().Be(3);\n        shortestPathList[0].Vertex.Should().Be(a);\n        shortestPathList[0].Distance.Should().Be(0);\n        shortestPathList[0].PreviousVertex.Should().Be(a);\n        shortestPathList[0].ToString().Should()\n            .Be($\"Vertex: {a} - Distance: {0} - Previous: {a}\");\n\n        shortestPathList[1].Vertex.Should().Be(b);\n        shortestPathList[1].Distance.Should().Be(1);\n        shortestPathList[1].PreviousVertex.Should().Be(a);\n        shortestPathList[1].ToString().Should()\n            .Be($\"Vertex: {b} - Distance: {1} - Previous: {a}\");\n\n        shortestPathList[2].Vertex.Should().Be(c);\n        shortestPathList[2].Distance.Should().Be(2);\n        shortestPathList[2].PreviousVertex.Should().Be(b);\n        shortestPathList[2].ToString().Should()\n            .Be($\"Vertex: {c} - Distance: {2} - Previous: {b}\");\n    }\n\n    [Test]\n    public void DijkstraTest3_Success()\n    {\n        var graph = new DirectedWeightedGraph<char>(5);\n        var a = graph.AddVertex('A');\n        var b = graph.AddVertex('B');\n        var c = graph.AddVertex('C');\n\n        graph.AddEdge(a, b, 1);\n        graph.AddEdge(b, a, 1);\n\n        graph.AddEdge(a, c, 3);\n        graph.AddEdge(c, a, 3);\n\n        var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a);\n\n        shortestPathList.Length.Should().Be(3);\n        shortestPathList[0].Vertex.Should().Be(a);\n        shortestPathList[0].Distance.Should().Be(0);\n        shortestPathList[0].PreviousVertex.Should().Be(a);\n        shortestPathList[0].ToString().Should()\n            .Be($\"Vertex: {a} - Distance: {0} - Previous: {a}\");\n\n        shortestPathList[1].Vertex.Should().Be(b);\n        shortestPathList[1].Distance.Should().Be(1);\n        shortestPathList[1].PreviousVertex.Should().Be(a);\n        shortestPathList[1].ToString().Should()\n            .Be($\"Vertex: {b} - Distance: {1} - Previous: {a}\");\n\n        shortestPathList[2].Vertex.Should().Be(c);\n        shortestPathList[2].Distance.Should().Be(3);\n        shortestPathList[2].PreviousVertex.Should().Be(a);\n        shortestPathList[2].ToString().Should()\n            .Be($\"Vertex: {c} - Distance: {3} - Previous: {a}\");\n    }\n\n    [Test]\n    public void DijkstraTest4_Success()\n    {\n        var graph = new DirectedWeightedGraph<char>(5);\n        var a = graph.AddVertex('A');\n        var b = graph.AddVertex('B');\n        var c = graph.AddVertex('C');\n        var d = graph.AddVertex('D');\n\n        graph.AddEdge(a, b, 1);\n        graph.AddEdge(b, a, 1);\n\n        graph.AddEdge(a, c, 3);\n        graph.AddEdge(c, a, 3);\n\n        graph.AddEdge(c, d, 5);\n        graph.AddEdge(d, c, 5);\n\n        var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a);\n\n        shortestPathList.Length.Should().Be(4);\n        shortestPathList[0].Vertex.Should().Be(a);\n        shortestPathList[0].Distance.Should().Be(0);\n        shortestPathList[0].PreviousVertex.Should().Be(a);\n        shortestPathList[0].ToString().Should()\n            .Be($\"Vertex: {a} - Distance: {0} - Previous: {a}\");\n\n        shortestPathList[1].Vertex.Should().Be(b);\n        shortestPathList[1].Distance.Should().Be(1);\n        shortestPathList[1].PreviousVertex.Should().Be(a);\n        shortestPathList[1].ToString().Should()\n            .Be($\"Vertex: {b} - Distance: {1} - Previous: {a}\");\n\n        shortestPathList[2].Vertex.Should().Be(c);\n        shortestPathList[2].Distance.Should().Be(3);\n        shortestPathList[2].PreviousVertex.Should().Be(a);\n        shortestPathList[2].ToString().Should()\n            .Be($\"Vertex: {c} - Distance: {3} - Previous: {a}\");\n\n        shortestPathList[3].Vertex.Should().Be(d);\n        shortestPathList[3].Distance.Should().Be(8);\n        shortestPathList[3].PreviousVertex.Should().Be(c);\n        shortestPathList[3].ToString().Should()\n            .Be($\"Vertex: {d} - Distance: {8} - Previous: {c}\");\n    }\n\n    [Test]\n    public void DijkstraTest5_Success()\n    {\n        // here test case is from https://www.youtube.com/watch?v=pVfj6mxhdMw\n\n        var graph = new DirectedWeightedGraph<char>(7);\n        var a = graph.AddVertex('A');\n        var b = graph.AddVertex('B');\n        var c = graph.AddVertex('C');\n        var d = graph.AddVertex('D');\n        var e = graph.AddVertex('E');\n        var w = graph.AddVertex('W');\n        var z = graph.AddVertex('Z');\n\n        graph.AddEdge(a, b, 6);\n        graph.AddEdge(b, a, 6);\n\n        graph.AddEdge(a, d, 1);\n        graph.AddEdge(d, a, 1);\n\n        graph.AddEdge(d, e, 1);\n        graph.AddEdge(e, d, 1);\n\n        graph.AddEdge(d, b, 2);\n        graph.AddEdge(b, d, 2);\n\n        graph.AddEdge(e, b, 2);\n        graph.AddEdge(b, e, 2);\n\n        graph.AddEdge(e, c, 5);\n        graph.AddEdge(c, e, 5);\n\n        graph.AddEdge(c, b, 5);\n        graph.AddEdge(b, c, 5);\n\n        graph.AddEdge(a, w, 50);\n        graph.AddEdge(w, a, 50);\n\n        graph.AddEdge(w, z, 1);\n        graph.AddEdge(z, w, 1);\n\n        var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a);\n        shortestPathList.Length.Should().Be(7);\n\n        shortestPathList[0].Vertex.Should().Be(a);\n        shortestPathList[0].Distance.Should().Be(0);\n        shortestPathList[0].PreviousVertex.Should().Be(a);\n        shortestPathList[0].ToString().Should()\n            .Be($\"Vertex: {a} - Distance: {0} - Previous: {a}\");\n\n        shortestPathList[1].Vertex.Should().Be(b);\n        shortestPathList[1].Distance.Should().Be(3);\n        shortestPathList[1].PreviousVertex.Should().Be(d);\n        shortestPathList[1].ToString().Should()\n            .Be($\"Vertex: {b} - Distance: {3} - Previous: {d}\");\n\n        shortestPathList[2].Vertex.Should().Be(c);\n        shortestPathList[2].Distance.Should().Be(7);\n        shortestPathList[2].PreviousVertex.Should().Be(e);\n        shortestPathList[2].ToString().Should()\n            .Be($\"Vertex: {c} - Distance: {7} - Previous: {e}\");\n\n        shortestPathList[3].Vertex.Should().Be(d);\n        shortestPathList[3].Distance.Should().Be(1);\n        shortestPathList[3].PreviousVertex.Should().Be(a);\n        shortestPathList[3].ToString().Should()\n            .Be($\"Vertex: {d} - Distance: {1} - Previous: {a}\");\n\n        shortestPathList[4].Vertex.Should().Be(e);\n        shortestPathList[4].Distance.Should().Be(2);\n        shortestPathList[4].PreviousVertex.Should().Be(d);\n        shortestPathList[4].ToString().Should()\n            .Be($\"Vertex: {e} - Distance: {2} - Previous: {d}\");\n\n        shortestPathList[5].Vertex.Should().Be(w);\n        shortestPathList[5].Distance.Should().Be(50);\n        shortestPathList[5].PreviousVertex.Should().Be(a);\n        shortestPathList[5].ToString().Should()\n            .Be($\"Vertex: {w} - Distance: {50} - Previous: {a}\");\n\n        shortestPathList[6].Vertex.Should().Be(z);\n        shortestPathList[6].Distance.Should().Be(51);\n        shortestPathList[6].PreviousVertex.Should().Be(w);\n        shortestPathList[6].ToString().Should()\n            .Be($\"Vertex: {z} - Distance: {51} - Previous: {w}\");\n    }\n\n    [Test]\n    public void DijkstraTest6_Success()\n    {\n        var graph = new DirectedWeightedGraph<char>(5);\n        var a = graph.AddVertex('A');\n        var b = graph.AddVertex('B');\n        var c = graph.AddVertex('C');\n        var d = graph.AddVertex('D');\n\n        graph.AddEdge(a, b, 1);\n        graph.AddEdge(b, a, 1);\n\n        graph.AddEdge(c, d, 5);\n        graph.AddEdge(d, c, 5);\n\n        var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a);\n\n        shortestPathList.Length.Should().Be(4);\n        shortestPathList[0].Vertex.Should().Be(a);\n        shortestPathList[0].Distance.Should().Be(0);\n        shortestPathList[0].PreviousVertex.Should().Be(a);\n        shortestPathList[0].ToString().Should()\n            .Be($\"Vertex: {a} - Distance: {0} - Previous: {a}\");\n\n        shortestPathList[1].Vertex.Should().Be(b);\n        shortestPathList[1].Distance.Should().Be(1);\n        shortestPathList[1].PreviousVertex.Should().Be(a);\n        shortestPathList[1].ToString().Should()\n            .Be($\"Vertex: {b} - Distance: {1} - Previous: {a}\");\n\n        shortestPathList[2].Vertex.Should().Be(c);\n        shortestPathList[2].Distance.Should().Be(double.MaxValue);\n        shortestPathList[2].PreviousVertex.Should().BeNull();\n        shortestPathList[2].ToString().Should()\n            .Be($\"Vertex: {c} - Distance: {double.MaxValue} - Previous: {null}\");\n\n        shortestPathList[3].Vertex.Should().Be(d);\n        shortestPathList[3].Distance.Should().Be(double.MaxValue);\n        shortestPathList[3].PreviousVertex.Should().BeNull();\n        shortestPathList[3].ToString().Should()\n            .Be($\"Vertex: {d} - Distance: {double.MaxValue} - Previous: {null}\");\n    }\n\n    [Test]\n    public void DijkstraMethodTest_ShouldThrow_GraphIsNull()\n    {\n        var graph = new DirectedWeightedGraph<char>(5);\n        var a = graph.AddVertex('A');\n\n        Func<DistanceModel<char>[]> action = () => DijkstraAlgorithm.GenerateShortestPath(null!, a);\n\n        action.Should().Throw<ArgumentNullException>()\n            .WithMessage($\"Value cannot be null. (Parameter '{nameof(graph)}')\");\n    }\n\n    [Test]\n    public void DijkstraMethodTest_ShouldThrow_VertexDoesntBelongToGraph()\n    {\n        var graph = new DirectedWeightedGraph<char>(5);\n        var startVertex = graph.AddVertex('A');\n\n        Func<DistanceModel<char>[]> action = () => DijkstraAlgorithm.GenerateShortestPath(\n            new DirectedWeightedGraph<char>(5), startVertex);\n\n        action.Should().Throw<ArgumentNullException>()\n            .WithMessage($\"Value cannot be null. (Parameter '{nameof(graph)}')\");\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Graph/FloydWarshallTests.cs",
    "content": "using Algorithms.Graph;\nusing DataStructures.Graph;\n\nnamespace Algorithms.Tests.Graph;\n\npublic class FloydWarshallTests\n{\n    [Test]\n    public void CorrectMatrixTest()\n    {\n        var graph = new DirectedWeightedGraph<int>(10);\n\n        var vertex1 = graph.AddVertex(1);\n\n        var vertex2 = graph.AddVertex(2);\n\n        var vertex3 = graph.AddVertex(3);\n\n        var vertex4 = graph.AddVertex(4);\n\n        var vertex5 = graph.AddVertex(5);\n\n        graph.AddEdge(vertex1, vertex2, 3);\n\n        graph.AddEdge(vertex1, vertex5, -4);\n\n        graph.AddEdge(vertex1, vertex3, 8);\n\n        graph.AddEdge(vertex2, vertex5, 7);\n\n        graph.AddEdge(vertex2, vertex4, 1);\n\n        graph.AddEdge(vertex3, vertex2, 4);\n\n        graph.AddEdge(vertex4, vertex3, -5);\n\n        graph.AddEdge(vertex4, vertex1, 2);\n\n        graph.AddEdge(vertex5, vertex4, 6);\n\n        var actualDistances = new double[,]\n        {\n            { 0, 1, -3, 2, -4 },\n            { 3, 0, -4, 1, -1 },\n            { 7, 4, 0, 5, 3 },\n            { 2, -1, -5, 0, -2 },\n            { 8, 5, 1, 6, 0 },\n        };\n\n        var floydWarshaller = new FloydWarshall<int>();\n        floydWarshaller.Run(graph).Should().BeEquivalentTo(actualDistances);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Graph/KosarajuTests.cs",
    "content": "using Algorithms.Graph;\nusing DataStructures.Graph;\n\nnamespace Algorithms.Tests.Graph;\n\npublic class KosarajuTests\n{\n\n    [Test]\n    public void GetRepresentativesTest()\n    {\n        // Create a graph with some SCC. \n        var graph = new DirectedWeightedGraph<int>(10);\n\n        var vertex1 = graph.AddVertex(1);\n        var vertex2 = graph.AddVertex(2);\n        var vertex3 = graph.AddVertex(3);\n        var vertex4 = graph.AddVertex(4);\n        var vertex5 = graph.AddVertex(5);\n        var vertex6 = graph.AddVertex(6);\n        var vertex7 = graph.AddVertex(7);\n\n        graph.AddEdge(vertex1, vertex2, 1);\n        graph.AddEdge(vertex2, vertex3, 1);\n        graph.AddEdge(vertex3, vertex1, 1);\n        graph.AddEdge(vertex3, vertex2, 1);\n        graph.AddEdge(vertex2, vertex4, 1);\n        graph.AddEdge(vertex4, vertex5, 1);\n        graph.AddEdge(vertex5, vertex4, 1);\n        graph.AddEdge(vertex5, vertex6, 1);\n\n        // Run the algorithm and obtain the representative vertex of the SCC to which each vertex belongs.\n        Dictionary<Vertex<int>, Vertex<int>> result = Kosaraju<int>.GetRepresentatives(graph);\n\n        // Check every Vertex belongs to a SCC\n        result.Should().ContainKey(vertex1);\n        result.Should().ContainKey(vertex2);\n        result.Should().ContainKey(vertex3);\n        result.Should().ContainKey(vertex4);\n        result.Should().ContainKey(vertex5);\n        result.Should().ContainKey(vertex6);\n        result.Should().ContainKey(vertex7);\n\n        // There should be 4 SCC: {1,2,3}, {4,5}, {6} and {7}\n        // Vertices 1, 2 and 3 are a SCC\n        result[vertex1].Should().Be(result[vertex2]).And.Be(result[vertex3]);\n\n        // Vertices 4 and 5 are another SCC\n        result[vertex4].Should().Be(result[vertex5]);\n\n        // And the should have a different representative vertex\n        result[vertex1].Should().NotBe(result[vertex4]);\n\n        // Vertices 6 and 7 are their own SCC\n        result[vertex6].Should().Be(vertex6);\n        result[vertex7].Should().Be(vertex7);\n    }\n\n    [Test]\n    public void GetSccTest()\n    {\n        // Create a graph with some SCC. \n        var graph = new DirectedWeightedGraph<int>(10);\n\n        var vertex1 = graph.AddVertex(1);\n        var vertex2 = graph.AddVertex(2);\n        var vertex3 = graph.AddVertex(3);\n        var vertex4 = graph.AddVertex(4);\n        var vertex5 = graph.AddVertex(5);\n        var vertex6 = graph.AddVertex(6);\n        var vertex7 = graph.AddVertex(7);\n\n        graph.AddEdge(vertex1, vertex2, 1);\n        graph.AddEdge(vertex2, vertex3, 1);\n        graph.AddEdge(vertex3, vertex1, 1);\n        graph.AddEdge(vertex3, vertex2, 1);\n        graph.AddEdge(vertex2, vertex4, 1);\n        graph.AddEdge(vertex4, vertex5, 1);\n        graph.AddEdge(vertex5, vertex4, 1);\n        graph.AddEdge(vertex5, vertex6, 1);\n\n        // Run the algorithm and get SCC as lists of vertices. \n        var scc = Kosaraju<int>.GetScc(graph);\n\n        // There should be 4 SCC: {1,2,3}, {4,5}, {6} and {7}\n        scc.Should().HaveCount(4);\n\n        // Vertices 1, 2 and 3 are a SCC\n        scc.First(c => c.Contains(vertex1)).Should().Contain(vertex2).And.Contain(vertex3);\n\n        // Vertices 4 and 5 are another SCC\n        scc.First(c => c.Contains(vertex4)).Should().Contain(vertex5);\n\n        // Vertices 6 and 7 are their own SCC\n        scc.First(c => c.Contains(vertex6)).Should().HaveCount(1);\n        scc.First(c => c.Contains(vertex7)).Should().HaveCount(1);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Graph/MinimumSpanningTree/KruskalTests.cs",
    "content": "using Algorithms.Graph.MinimumSpanningTree;\n\nnamespace Algorithms.Tests.Graph.MinimumSpanningTree;\n\ninternal class KruskalTests\n{\n    [Test]\n    public void ValidateGraph_adjWrongSize_ThrowsException()\n    {\n        // Wrong number of columns\n        var adj = new[,]\n        {\n            { 0, 3, 4, float.PositiveInfinity },\n            { 3, 0, 5, 6 },\n            { 4, 5, 0, float.PositiveInfinity },\n            { float.PositiveInfinity, 6, float.PositiveInfinity, 0 },\n            { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity },\n        };\n        Assert.Throws<ArgumentException>(() => Kruskal.Solve(adj), \"adj must be square!\");\n\n        // Wrong number of rows\n        adj = new[,]\n        {\n            { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, 0, 5, 6, 2 },\n            { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity },\n        };\n        Assert.Throws<ArgumentException>(() => Kruskal.Solve(adj), \"adj must be square!\");\n    }\n\n    [Test]\n    public void ValidateGraph_adjDirectedGraph_ThrowsException()\n    {\n        // Nodes 1 and 2 have a directed edge\n        var adj = new[,]\n        {\n            { 0, float.PositiveInfinity, 4, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, 0, 5, 6, 2 },\n            { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity },\n            { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 0 },\n        };\n        Assert.Throws<ArgumentException>(() => Kruskal.Solve(adj), \"adj must be symmetric!\");\n    }\n\n    [Test]\n    public void Solve_adjGraph1_CorrectAnswer()\n    {\n        /* Graph\n         *       (1)\n         *       / \\\n         *      3   2\n         *     /     \\\n         *   (0)--2--(2)\n         */\n        var adj = new float[,]\n        {\n            { 0, 3, 2 },\n            { 3, 0, 2 },\n            { 2, 2, 0 },\n        };\n\n        /* Expected MST\n         *      (1)\n         *        \\ \n         *         2\n         *          \\\n         *  (0)--2--(2)\n         */\n        var expected = new[,]\n        {\n            { float.PositiveInfinity, float.PositiveInfinity, 2 },\n            { float.PositiveInfinity, float.PositiveInfinity, 2 },\n            { 2, 2, float.PositiveInfinity },\n        };\n\n        Kruskal.Solve(adj).Cast<float>().SequenceEqual(expected.Cast<float>()).Should().BeTrue();\n    }\n\n    [Test]\n    public void Solve_adjGraph2_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)     (4)\n         *   |\\     /\n         *   | 3   2\n         *   |  \\ /\n         *   4  (1)\n         *   |  / \\\n         *   | 5   6\n         *   |/     \\\n         *  (2)     (3)\n         */\n        var adj = new[,]\n        {\n            { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, 0, 5, 6, 2 },\n            { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity },\n            { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 0 },\n        };\n\n        /* Expected MST\n         *  (0)     (4)\n         *   |\\     /\n         *   | 3   2\n         *   |  \\ /\n         *   4  (1)\n         *   |    \\\n         *   |     6\n         *   |      \\\n         *  (2)     (3)\n         */\n        var expected = new[,]\n        {\n            { float.PositiveInfinity, 3, 4, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, float.PositiveInfinity, float.PositiveInfinity, 6, 2 },\n            { 4, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 6, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n        };\n\n        Kruskal.Solve(adj).Cast<float>().SequenceEqual(expected.Cast<float>()).Should().BeTrue();\n    }\n\n    [Test]\n    public void Solve_adjGraph3_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)--3--(2)     (4)--2--(5)\n         *    \\     / \\     /\n         *     4   1   4   6\n         *      \\ /     \\ /\n         *      (1)--2--(3)\n         */\n        var adj = new[,]\n        {\n            { 0, 4, 3, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { 4, 0, 1, 2, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, 1, 0, 4, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 2, 4, 0, 6, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 0, 2 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 2, 0 },\n        };\n\n        /* Graph\n         *  (0)--3--(2)     (4)--2--(5)\n         *          /       /\n         *         1       6\n         *        /       /\n         *      (1)--2--(3)\n         */\n        var expected = new[,]\n        {\n            { float.PositiveInfinity, float.PositiveInfinity, 3, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, 1, 2, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, 1, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity, 2 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 2, float.PositiveInfinity },\n        };\n\n        Kruskal.Solve(adj).Cast<float>().SequenceEqual(expected.Cast<float>()).Should().BeTrue();\n    }\n\n    [Test]\n    public void Solve_adjGraph4_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)--7--(1)--8--(2)\n         *    \\     / \\     /\n         *     5   9   7   5\n         *      \\ /     \\ /\n         *      (3)--15-(4)\n         *        \\     / \\\n         *         6   8   9\n         *          \\ /     \\\n         *          (5)--11-(6)\n         */\n        var adj = new[,]\n        {\n            { 0, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { 7, 0, 8, 9, 7, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 8, 0, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity },\n            { 5, 9, float.PositiveInfinity, 0, 15, 6, float.PositiveInfinity },\n            { float.PositiveInfinity, 7, 5, 15, 0, 8, 9 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 8, 0, 11 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9, 11, 0 },\n        };\n\n        /* Expected MST\n         *  (0)--7--(1)     (2)\n         *    \\       \\     /\n         *     5       7   5\n         *      \\       \\ /\n         *      (3)     (4)\n         *        \\       \\\n         *         6       9\n         *          \\       \\\n         *          (5)     (6)\n         */\n        var expected = new[,]\n        {\n            { float.PositiveInfinity, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { 7, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 7, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity },\n            { 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity },\n            { float.PositiveInfinity, 7, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity },\n        };\n\n        Kruskal.Solve(adj).Cast<float>().SequenceEqual(expected.Cast<float>()).Should().BeTrue();\n    }\n\n    [Test]\n    public void Solve_adjGraph5_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)--8--(1)--15-(2)\n         *   |\\     /     __/|\\\n         *   | 4   5  __25  13 12 \n         *   |  \\ /__/       |   \\\n         *  10  (3)----14---(4)  (5)\n         *   |  / \\        _/|   /\n         *   | 9   6   __16  18 30\n         *   |/     \\ /      |/\n         *  (6)--18-(7)--20-(8)\n         */\n        var adj = new[,]\n        {\n            { 0, 8, float.PositiveInfinity, 4, float.PositiveInfinity, float.PositiveInfinity, 10, float.PositiveInfinity, float.PositiveInfinity },\n            { 8, 0, 15, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 15, 0, 25, 13, 12, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { 4, 5, 25, 0, 14, float.PositiveInfinity, 9, 6, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, 13, 14, 0, float.PositiveInfinity, float.PositiveInfinity, 16, 18 },\n            { float.PositiveInfinity, float.PositiveInfinity, 12, float.PositiveInfinity, float.PositiveInfinity, 0, float.PositiveInfinity, float.PositiveInfinity, 30 },\n            { 10, float.PositiveInfinity, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity, 0, 18, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 16, float.PositiveInfinity, 18, 0, 20 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 18, 30, float.PositiveInfinity, 20, 0 },\n        };\n\n        /* Expected MST\n         *  (0)     (1)     (2)\n         *    \\     /        |\\\n         *     4   5        13 12 \n         *      \\ /          |   \\\n         *      (3)----14---(4)  (5)\n         *      / \\          |\n         *     9   6         18\n         *    /     \\        |\n         *  (6)     (7)     (8)\n         */\n        var expected = new[,]\n        {\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                4,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                5,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                13,\n                12,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n            {\n                4,\n                5,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                14,\n                float.PositiveInfinity,\n                9,\n                6,\n                float.PositiveInfinity,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                13,\n                14,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                18,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                12,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                9,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                6,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                18,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n        };\n\n        Kruskal.Solve(adj).Cast<float>().SequenceEqual(expected.Cast<float>()).Should().BeTrue();\n    }\n\n    [Test]\n    public void Solve_adjGraph6_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)--7--(1)     (2)\n         *    \\     /       /|\n         *     5   9       5 |\n         *      \\ /       /  |\n         *      (3)     (4)  2\n         *              / \\  |\n         *             8   9 |\n         *            /     \\|\n         *          (5)--11-(6)\n         */\n        var adj = new[,]\n        {\n            { 0, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { 7, 0, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, 0, float.PositiveInfinity, 5, float.PositiveInfinity, 2 },\n            { 5, 9, float.PositiveInfinity, 0, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, 0, 8, 9 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 8, 0, 11 },\n            { float.PositiveInfinity, float.PositiveInfinity, 2, float.PositiveInfinity, 9, 11, 0 },\n        };\n\n        /* Expected MST\n         *  (0)--7--(1)     (2)\n         *    \\             /|\n         *     5           5 |\n         *      \\         /  |\n         *      (3)     (4)  2\n         *              /    |\n         *             8     |\n         *            /      |\n         *          (5)     (6)\n         */\n        var expected = new[,]\n        {\n            { float.PositiveInfinity, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { 7, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, 2 },\n            { 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, 8, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 8, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n        };\n\n        Kruskal.Solve(adj).Cast<float>().SequenceEqual(expected.Cast<float>()).Should().BeTrue();\n    }\n\n    [Test]\n    public void ValidateGraph_ListDirectedGraph_ThrowsException()\n    {\n        var adj = new[]\n        {\n            new Dictionary<int, float>{ { 2, 4 } },\n            new Dictionary<int, float>{ { 0, 3 }, { 2, 5 }, { 3, 6 }, { 4, 2 } },\n            new Dictionary<int, float>{ { 0, 4 }, { 1, 5 } },\n            new Dictionary<int, float>{ { 1, 6 } },\n            new Dictionary<int, float>{ { 1, 2 } },\n        };\n        Assert.Throws<ArgumentException>(() => Kruskal.Solve(adj), \"Graph must be undirected!\");\n    }\n\n    [Test]\n    public void Solve_ListGraph1_CorrectAnswer()\n    {\n        /* Graph\n         *       (1)\n         *       / \\\n         *      3   2\n         *     /     \\\n         *   (0)--2--(2)\n         */\n        var adj = new[]\n        {\n            new Dictionary<int, float>{ { 1, 3 }, { 2, 2 } },\n            new Dictionary<int, float>{ { 0, 3 }, { 2, 2 } },\n            new Dictionary<int, float>{ { 0, 2 }, { 1, 2 } },\n        };\n\n        /* Expected MST\n         *      (1)\n         *        \\ \n         *         2\n         *          \\\n         *  (0)--2--(2)\n         */\n        var expected = new[]\n        {\n            new Dictionary<int, float>{ { 2, 2 } },\n            new Dictionary<int, float>{ { 2, 2 } },\n            new Dictionary<int, float>{ { 0, 2 }, { 1, 2 } },\n        };\n\n        var res = Kruskal.Solve(adj);\n        for (var i = 0; i < adj.Length; i++)\n        {\n            res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue();\n        }\n    }\n\n    [Test]\n    public void Solve_ListGraph2_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)     (4)\n         *   |\\     /\n         *   | 3   2\n         *   |  \\ /\n         *   4  (1)\n         *   |  / \\\n         *   | 5   6\n         *   |/     \\\n         *  (2)     (3)\n         */\n        var adj = new[]\n        {\n            new Dictionary<int, float>{ { 1, 3 }, { 2, 4 } },\n            new Dictionary<int, float>{ { 0, 3 }, { 2, 5 }, { 3, 6 }, { 4, 2 } },\n            new Dictionary<int, float>{ { 0, 4 }, { 1, 5 } },\n            new Dictionary<int, float>{ { 1, 6 } },\n            new Dictionary<int, float>{ { 1, 2 } },\n        };\n\n        /* Expected MST\n         *  (0)     (4)\n         *   |\\     /\n         *   | 3   2\n         *   |  \\ /\n         *   4  (1)\n         *   |    \\\n         *   |     6\n         *   |      \\\n         *  (2)     (3)\n         */\n        var expected = new[]\n        {\n            new Dictionary<int, float>{ { 1, 3 }, { 2, 4 } },\n            new Dictionary<int, float>{ { 0, 3 }, { 3, 6 }, { 4, 2 } },\n            new Dictionary<int, float>{ { 0, 4 } },\n            new Dictionary<int, float>{ { 1, 6 } },\n            new Dictionary<int, float>{ { 1, 2 } },\n        };\n\n        var res = Kruskal.Solve(adj);\n        for (var i = 0; i < adj.Length; i++)\n        {\n            res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue();\n        }\n    }\n\n    [Test]\n    public void Solve_ListGraph3_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)--3--(2)     (4)--2--(5)\n         *    \\     / \\     /\n         *     4   1   4   6\n         *      \\ /     \\ /\n         *      (1)--2--(3)\n         */\n        var adj = new[]\n        {\n            new Dictionary<int, float>{ { 1, 4 }, { 2, 3 } },\n            new Dictionary<int, float>{ { 0, 4 }, { 2, 1 }, { 3, 2 } },\n            new Dictionary<int, float>{ { 0, 3 }, { 1, 1 }, { 3, 4 } },\n            new Dictionary<int, float>{ { 1, 2 }, { 2, 4 }, { 4, 6 } },\n            new Dictionary<int, float>{ { 3, 6 }, { 5, 2 } },\n            new Dictionary<int, float>{ { 4, 2 } },\n        };\n\n        /* Graph\n         *  (0)--3--(2)     (4)--2--(5)\n         *          /       /\n         *         1       6\n         *        /       /\n         *      (1)--2--(3)\n         */\n        var expected = new[]\n        {\n            new Dictionary<int, float>{ { 2, 3 } },\n            new Dictionary<int, float>{ { 2, 1 }, { 3, 2 } },\n            new Dictionary<int, float>{ { 0, 3 }, { 1, 1 } },\n            new Dictionary<int, float>{ { 1, 2 }, { 4, 6 } },\n            new Dictionary<int, float>{ { 3, 6 }, { 5, 2 } },\n            new Dictionary<int, float>{ { 4, 2 } },\n        };\n\n        var res = Kruskal.Solve(adj);\n        for (var i = 0; i < adj.Length; i++)\n        {\n            res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue();\n        }\n    }\n\n    [Test]\n    public void Solve_ListGraph4_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)--7--(1)--8--(2)\n         *    \\     / \\     /\n         *     5   9   7   5\n         *      \\ /     \\ /\n         *      (3)--15-(4)\n         *        \\     / \\\n         *         6   8   9\n         *          \\ /     \\\n         *          (5)--11-(6)\n         */\n        var adj = new[]\n        {\n            new Dictionary<int, float>{ { 1, 7 }, { 3, 5 } },\n            new Dictionary<int, float>{ { 0, 7 }, { 2, 8 }, { 3, 9 }, { 4, 7 } },\n            new Dictionary<int, float>{ { 1, 8 }, { 4, 5 } },\n            new Dictionary<int, float>{ { 0, 5 }, { 1, 9 }, { 4, 15 }, { 5, 6 } },\n            new Dictionary<int, float>{ { 1, 7 }, { 2, 5 }, { 3, 15 }, { 5, 8 }, { 6, 9 } },\n            new Dictionary<int, float>{ { 3, 6 }, { 4, 8 }, { 6, 11 } },\n            new Dictionary<int, float>{ { 4, 9 }, { 5, 11 } },\n        };\n\n        /* Expected MST\n         *  (0)--7--(1)     (2)\n         *    \\       \\     /\n         *     5       7   5\n         *      \\       \\ /\n         *      (3)     (4)\n         *        \\       \\\n         *         6       9\n         *          \\       \\\n         *          (5)     (6)\n         */\n        var expected = new[]\n        {\n            new Dictionary<int, float>{ { 1, 7 }, { 3, 5 } },\n            new Dictionary<int, float>{ { 0, 7 }, { 4, 7 } },\n            new Dictionary<int, float>{ { 4, 5 } },\n            new Dictionary<int, float>{ { 0, 5 }, { 5, 6 } },\n            new Dictionary<int, float>{ { 1, 7 }, { 2, 5 }, { 6, 9 } },\n            new Dictionary<int, float>{ { 3, 6 } },\n            new Dictionary<int, float>{ { 4, 9 } },\n        };\n\n        var res = Kruskal.Solve(adj);\n        for (var i = 0; i < adj.Length; i++)\n        {\n            res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue();\n        }\n    }\n\n    [Test]\n    public void Solve_ListGraph5_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)--8--(1)--15-(2)\n         *   |\\     /     __/|\\\n         *   | 4   5  __25  13 12 \n         *   |  \\ /__/       |   \\\n         *  10  (3)----14---(4)  (5)\n         *   |  / \\        _/|   /\n         *   | 9   6   __16  18 30\n         *   |/     \\ /      |/\n         *  (6)--18-(7)--20-(8)\n         */\n        var adj = new[]\n        {\n            new Dictionary<int, float>{ { 1, 8 }, { 3, 4 }, { 6, 10 } },\n            new Dictionary<int, float>{ { 0, 8 }, { 2, 15 }, { 3, 5 } },\n            new Dictionary<int, float>{ { 1, 15 }, { 3, 25 }, { 4, 13 }, { 5, 12 } },\n            new Dictionary<int, float>{ { 0, 4 }, { 1, 5 }, { 2, 25 }, { 4, 14 }, { 6, 9 }, { 7, 6 } },\n            new Dictionary<int, float>{ { 2, 13 }, { 3, 14 }, { 7, 16 }, { 8, 18 } },\n            new Dictionary<int, float>{ { 2, 12 }, { 8, 30 } },\n            new Dictionary<int, float>{ { 0, 10 }, { 3, 9 }, { 7, 18 } },\n            new Dictionary<int, float>{ { 3, 6 }, { 4, 16 }, { 6, 18 }, { 8, 20 } },\n            new Dictionary<int, float>{ { 4, 18 }, { 5, 30 }, { 7, 20 } },\n        };\n\n        /* Expected MST\n         *  (0)     (1)     (2)\n         *    \\     /        |\\\n         *     4   5        13 12 \n         *      \\ /          |   \\\n         *      (3)----14---(4)  (5)\n         *      / \\          |\n         *     9   6         18\n         *    /     \\        |\n         *  (6)     (7)     (8)\n         */\n        var expected = new[]\n        {\n            new Dictionary<int, float>{ { 3, 4 } },\n            new Dictionary<int, float>{ { 3, 5 } },\n            new Dictionary<int, float>{ { 4, 13 }, { 5, 12 } },\n            new Dictionary<int, float>{ { 0, 4 }, { 1, 5 }, { 4, 14 }, { 6, 9 }, { 7, 6 } },\n            new Dictionary<int, float>{ { 2, 13 }, { 3, 14 }, { 8, 18 } },\n            new Dictionary<int, float>{ { 2, 12 } },\n            new Dictionary<int, float>{ { 3, 9 } },\n            new Dictionary<int, float>{ { 3, 6 } },\n            new Dictionary<int, float>{ { 4, 18 } },\n        };\n\n        var res = Kruskal.Solve(adj);\n        for (var i = 0; i < adj.Length; i++)\n        {\n            res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue();\n        }\n    }\n\n    [Test]\n    public void Solve_ListGraph6_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)--7--(1)     (2)\n         *    \\     /       /|\n         *     5   9       5 |\n         *      \\ /       /  |\n         *      (3)     (4)  2\n         *              / \\  |\n         *             8   9 |\n         *            /     \\|\n         *          (5)--11-(6)\n         */\n        var adj = new[]\n        {\n            new Dictionary<int, float>{ { 1, 7 }, { 3, 5 } },\n            new Dictionary<int, float>{ { 0, 7 }, { 3, 9 } },\n            new Dictionary<int, float>{ { 4, 5 }, { 6, 2 } },\n            new Dictionary<int, float>{ { 0, 5 }, { 1, 9 } },\n            new Dictionary<int, float>{ { 2, 5 }, { 5, 8 }, { 6, 9 } },\n            new Dictionary<int, float>{ { 4, 8 }, { 6, 11 } },\n            new Dictionary<int, float>{ { 2, 2 }, { 4, 9 }, { 5, 11 } },\n        };\n\n        /* Expected MST\n         *  (0)--7--(1)     (2)\n         *    \\             /|\n         *     5           5 |\n         *      \\         /  |\n         *      (3)     (4)  2\n         *              /    |\n         *             8     |\n         *            /      |\n         *          (5)     (6)\n         */\n        var expected = new[]\n        {\n            new Dictionary<int, float>{ { 1, 7 }, { 3, 5 } },\n            new Dictionary<int, float>{ { 0, 7 } },\n            new Dictionary<int, float>{ { 4, 5 }, { 6, 2 } },\n            new Dictionary<int, float>{ { 0, 5 } },\n            new Dictionary<int, float>{ { 2, 5 }, { 5, 8 } },\n            new Dictionary<int, float>{ { 4, 8 } },\n            new Dictionary<int, float>{ { 2, 2 } },\n        };\n\n        var res = Kruskal.Solve(adj);\n        for (var i = 0; i < adj.Length; i++)\n        {\n            res[i].OrderBy(edge => edge.Key).SequenceEqual(expected[i]).Should().BeTrue();\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Graph/MinimumSpanningTree/PrimMatrixTests.cs",
    "content": "using Algorithms.Graph.MinimumSpanningTree;\n\nnamespace Algorithms.Tests.Graph.MinimumSpanningTree;\n\ninternal class PrimTests\n{\n    [Test]\n    public void ValidateMatrix_WrongSize_ThrowsException()\n    {\n        // Wrong number of columns\n        var matrix = new[,]\n        {\n            { 0, 3, 4, float.PositiveInfinity },\n            { 3, 0, 5, 6 },\n            { 4, 5, 0, float.PositiveInfinity },\n            { float.PositiveInfinity, 6, float.PositiveInfinity, 0 },\n            { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity },\n        };\n        Assert.Throws<ArgumentException>(() => PrimMatrix.Solve(matrix, 0));\n\n        // Wrong number of rows\n        matrix = new[,]\n        {\n            { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, 0, 5, 6, 2 },\n            { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity },\n        };\n        Assert.Throws<ArgumentException>(() => PrimMatrix.Solve(matrix, 0));\n    }\n\n    [Test]\n    public void ValidateMatrix_UnconnectedGraph_ThrowsException()\n    {\n        // Last node does not connect to any other nodes\n        var matrix = new[,]\n        {\n            { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, 0, 5, 6, 2 },\n            { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 0 },\n        };\n        Assert.Throws<ArgumentException>(() => PrimMatrix.Solve(matrix, 0));\n    }\n\n    [Test]\n    public void ValidateMatrix_DirectedGraph_ThrowsException()\n    {\n        // Nodes 1 and 2 have a directed edge\n        var matrix = new[,]\n        {\n            { 0, float.PositiveInfinity, 4, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, 0, 5, 6, 2 },\n            { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity },\n            { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 0 },\n        };\n        Assert.Throws<ArgumentException>(() => PrimMatrix.Solve(matrix, 0));\n    }\n\n    [Test]\n    public void SolveMatrix_Graph1_CorrectAnswer()\n    {\n        /* Graph\n         *       (1)\n         *       / \\\n         *      3   2\n         *     /     \\\n         *   (0)--2--(2)\n         */\n        var matrix = new float[,]\n        {\n            { 0, 3, 2 },\n            { 3, 0, 2 },\n            { 2, 2, 0 },\n        };\n\n        /* Expected MST\n         *      (1)\n         *        \\ \n         *         2\n         *          \\\n         *  (0)--2--(2)\n         */\n        var expected = new[,]\n        {\n            { float.PositiveInfinity, float.PositiveInfinity, 2 },\n            { float.PositiveInfinity, float.PositiveInfinity, 2 },\n            { 2, 2, float.PositiveInfinity },\n        };\n\n        for (var i = 0; i < matrix.GetLength(0); i++)\n        {\n            PrimMatrix.Solve(matrix, i).Cast<float>().SequenceEqual(expected.Cast<float>()).Should().BeTrue();\n        }\n    }\n\n    [Test]\n    public void SolveMatrix_Graph2_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)     (4)\n         *   |\\     /\n         *   | 3   2\n         *   |  \\ /\n         *   4  (1)\n         *   |  / \\\n         *   | 5   6\n         *   |/     \\\n         *  (2)     (3)\n         */\n        var matrix = new[,]\n        {\n            { 0, 3, 4, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, 0, 5, 6, 2 },\n            { 4, 5, 0, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 6, float.PositiveInfinity, 0, float.PositiveInfinity },\n            { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 0 },\n        };\n\n        /* Expected MST\n         *  (0)     (4)\n         *   |\\     /\n         *   | 3   2\n         *   |  \\ /\n         *   4  (1)\n         *   |    \\\n         *   |     6\n         *   |      \\\n         *  (2)     (3)\n         */\n        var expected = new[,]\n        {\n            { float.PositiveInfinity, 3, 4, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, float.PositiveInfinity, float.PositiveInfinity, 6, 2 },\n            { 4, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 6, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n        };\n\n        for (var i = 0; i < matrix.GetLength(0); i++)\n        {\n            PrimMatrix.Solve(matrix, i).Cast<float>().SequenceEqual(expected.Cast<float>()).Should().BeTrue();\n        }\n    }\n\n    [Test]\n    public void SolveMatrix_Graph3_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)--3--(2)     (4)--2--(5)\n         *    \\     / \\     /\n         *     4   1   4   6\n         *      \\ /     \\ /\n         *      (1)--2--(3)\n         */\n        var matrix = new[,]\n        {\n            { 0, 4, 3, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { 4, 0, 1, 2, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, 1, 0, 4, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 2, 4, 0, 6, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 0, 2 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 2, 0 },\n        };\n\n        /* Graph\n         *  (0)--3--(2)     (4)--2--(5)\n         *          /       /\n         *         1       6\n         *        /       /\n         *      (1)--2--(3)\n         */\n        var expected = new[,]\n        {\n            { float.PositiveInfinity, float.PositiveInfinity, 3, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, 1, 2, float.PositiveInfinity, float.PositiveInfinity },\n            { 3, 1, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 2, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity, 2 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 2, float.PositiveInfinity },\n        };\n\n        for (var i = 0; i < matrix.GetLength(0); i++)\n        {\n            PrimMatrix.Solve(matrix, i).Cast<float>().SequenceEqual(expected.Cast<float>()).Should().BeTrue();\n        }\n    }\n\n    [Test]\n    public void SolveMatrix_Graph4_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)--7--(1)--8--(2)\n         *    \\     / \\     /\n         *     5   9   7   5\n         *      \\ /     \\ /\n         *      (3)--15-(4)\n         *        \\     / \\\n         *         6   8   9\n         *          \\ /     \\\n         *          (5)--11-(6)\n         */\n        var matrix = new[,]\n        {\n            { 0, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { 7, 0, 8, 9, 7, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 8, 0, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity },\n            { 5, 9, float.PositiveInfinity, 0, 15, 6, float.PositiveInfinity },\n            { float.PositiveInfinity, 7, 5, 15, 0, 8, 9 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 8, 0, 11 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9, 11, 0 },\n        };\n\n        /* Expected MST\n         *  (0)--7--(1)     (2)\n         *    \\       \\     /\n         *     5       7   5\n         *      \\       \\ /\n         *      (3)     (4)\n         *        \\       \\\n         *         6       9\n         *          \\       \\\n         *          (5)     (6)\n         */\n        var expected = new[,]\n        {\n            { float.PositiveInfinity, 7, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { 7, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 7, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 5, float.PositiveInfinity, float.PositiveInfinity },\n            { 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity },\n            { float.PositiveInfinity, 7, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity },\n        };\n\n        for (var i = 0; i < matrix.GetLength(0); i++)\n        {\n            PrimMatrix.Solve(matrix, i).Cast<float>().SequenceEqual(expected.Cast<float>()).Should().BeTrue();\n        }\n    }\n\n    [Test]\n    public void SolveMatrix_Graph5_CorrectAnswer()\n    {\n        /* Graph\n         *  (0)--8--(1)--15-(2)\n         *   |\\     /     __/|\\\n         *   | 4   5  __25  13 12 \n         *   |  \\ /__/       |   \\\n         *  10  (3)----14---(4)  (5)\n         *   |  / \\        _/|   /\n         *   | 9   6   __16  18 30\n         *   |/     \\ /      |/\n         *  (6)--18-(7)--20-(8)\n         */\n        var matrix = new[,]\n        {\n            { 0, 8, float.PositiveInfinity, 4, float.PositiveInfinity, float.PositiveInfinity, 10, float.PositiveInfinity, float.PositiveInfinity },\n            { 8, 0, 15, 5, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { float.PositiveInfinity, 15, 0, 25, 13, 12, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity },\n            { 4, 5, 25, 0, 14, float.PositiveInfinity, 9, 6, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, 13, 14, 0, float.PositiveInfinity, float.PositiveInfinity, 16, 18 },\n            { float.PositiveInfinity, float.PositiveInfinity, 12, float.PositiveInfinity, float.PositiveInfinity, 0, float.PositiveInfinity, float.PositiveInfinity, 30 },\n            { 10, float.PositiveInfinity, float.PositiveInfinity, 9, float.PositiveInfinity, float.PositiveInfinity, 0, 18, float.PositiveInfinity },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 6, 16, float.PositiveInfinity, 18, 0, 20 },\n            { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 18, 30, float.PositiveInfinity, 20, 0 },\n        };\n\n        /* Expected MST\n         *  (0)     (1)     (2)\n         *    \\     /        |\\\n         *     4   5        13 12 \n         *      \\ /          |   \\\n         *      (3)----14---(4)  (5)\n         *      / \\          |\n         *     9   6         18\n         *    /     \\        |\n         *  (6)     (7)     (8)\n         */\n        var expected = new[,]\n        {\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                4,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                5,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                13,\n                12,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n            {\n                4,\n                5,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                14,\n                float.PositiveInfinity,\n                9,\n                6,\n                float.PositiveInfinity,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                13,\n                14,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                18,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                12,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                9,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                6,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n            {\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                18,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n                float.PositiveInfinity,\n            },\n        };\n\n        for (var i = 0; i < matrix.GetLength(0); i++)\n        {\n            PrimMatrix.Solve(matrix, i).Cast<float>().SequenceEqual(expected.Cast<float>()).Should().BeTrue();\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Graph/TarjanStronglyConnectedComponentsTests.cs",
    "content": "using Algorithms.Graph;\nusing NUnit.Framework;\nusing FluentAssertions;\nusing System.Linq;\n\nnamespace Algorithms.Tests.Graph;\n\npublic class TarjanStronglyConnectedComponentsTests\n{\n    [Test]\n    public void FindSCCs_SimpleGraph_ReturnsCorrectSCCs()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(3);\n        tarjan.AddEdge(0, 1);\n        tarjan.AddEdge(1, 2);\n        tarjan.AddEdge(2, 0);\n\n        var sccs = tarjan.FindSCCs();\n\n        sccs.Should().HaveCount(1);\n        sccs[0].Should().BeEquivalentTo(new[] { 0, 1, 2 });\n    }\n\n    [Test]\n    public void FindSCCs_TwoSeparateSCCs_ReturnsBothSCCs()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(4);\n        tarjan.AddEdge(0, 1);\n        tarjan.AddEdge(1, 0);\n        tarjan.AddEdge(2, 3);\n        tarjan.AddEdge(3, 2);\n\n        var sccs = tarjan.FindSCCs();\n\n        sccs.Should().HaveCount(2);\n    }\n\n    [Test]\n    public void FindSCCs_DisconnectedVertices_EachVertexIsSCC()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(3);\n\n        var sccs = tarjan.FindSCCs();\n\n        sccs.Should().HaveCount(3);\n        sccs.Should().OnlyContain(scc => scc.Count == 1);\n    }\n\n    [Test]\n    public void FindSCCs_ComplexGraph_ReturnsCorrectSCCs()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(8);\n        tarjan.AddEdge(0, 1);\n        tarjan.AddEdge(1, 2);\n        tarjan.AddEdge(2, 0);\n        tarjan.AddEdge(2, 3);\n        tarjan.AddEdge(3, 4);\n        tarjan.AddEdge(4, 5);\n        tarjan.AddEdge(5, 3);\n        tarjan.AddEdge(5, 6);\n        tarjan.AddEdge(6, 7);\n        tarjan.AddEdge(7, 6);\n\n        var sccs = tarjan.FindSCCs();\n\n        sccs.Should().HaveCount(3);\n    }\n\n    [Test]\n    public void GetSccCount_AfterFindingSCCs_ReturnsCorrectCount()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(5);\n        tarjan.AddEdge(0, 1);\n        tarjan.AddEdge(1, 0);\n        tarjan.AddEdge(2, 3);\n        tarjan.AddEdge(3, 4);\n        tarjan.AddEdge(4, 2);\n\n        tarjan.FindSCCs();\n        var count = tarjan.GetSccCount();\n\n        count.Should().Be(2);\n    }\n\n    [Test]\n    public void InSameScc_VerticesInSameScc_ReturnsTrue()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(3);\n        tarjan.AddEdge(0, 1);\n        tarjan.AddEdge(1, 2);\n        tarjan.AddEdge(2, 0);\n\n        var result = tarjan.InSameScc(0, 2);\n\n        result.Should().BeTrue();\n    }\n\n    [Test]\n    public void InSameScc_VerticesInDifferentSccs_ReturnsFalse()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(4);\n        tarjan.AddEdge(0, 1);\n        tarjan.AddEdge(1, 0);\n        tarjan.AddEdge(2, 3);\n\n        var result = tarjan.InSameScc(0, 2);\n\n        result.Should().BeFalse();\n    }\n\n    [Test]\n    public void GetScc_ValidVertex_ReturnsSccContainingVertex()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(3);\n        tarjan.AddEdge(0, 1);\n        tarjan.AddEdge(1, 2);\n        tarjan.AddEdge(2, 0);\n\n        var scc = tarjan.GetScc(1);\n\n        scc.Should().NotBeNull();\n        scc.Should().Contain(1);\n        scc.Should().HaveCount(3);\n    }\n\n    [Test]\n    public void BuildCondensationGraph_ComplexGraph_ReturnsDAG()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(6);\n        tarjan.AddEdge(0, 1);\n        tarjan.AddEdge(1, 0);\n        tarjan.AddEdge(1, 2);\n        tarjan.AddEdge(2, 3);\n        tarjan.AddEdge(3, 4);\n        tarjan.AddEdge(4, 5);\n        tarjan.AddEdge(5, 3);\n\n        var condensation = tarjan.BuildCondensationGraph();\n\n        condensation.Should().NotBeNull();\n        condensation.Length.Should().Be(3); // {0,1}, {2}, {3,4,5}\n    }\n\n    [Test]\n    public void AddEdge_InvalidVertex_ThrowsException()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(3);\n\n        var act = () => tarjan.AddEdge(0, 5);\n\n        act.Should().Throw<ArgumentOutOfRangeException>();\n    }\n\n    [Test]\n    public void FindSCCs_SingleVertex_ReturnsSingleSCC()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(1);\n\n        var sccs = tarjan.FindSCCs();\n\n        sccs.Should().HaveCount(1);\n        sccs[0].Should().BeEquivalentTo(new[] { 0 });\n    }\n\n    [Test]\n    public void FindSCCs_LinearChain_EachVertexIsSCC()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(4);\n        tarjan.AddEdge(0, 1);\n        tarjan.AddEdge(1, 2);\n        tarjan.AddEdge(2, 3);\n\n        var sccs = tarjan.FindSCCs();\n\n        sccs.Should().HaveCount(4);\n    }\n\n    [Test]\n    public void FindSCCs_SelfLoop_VertexIsSCC()\n    {\n        var tarjan = new TarjanStronglyConnectedComponents(2);\n        tarjan.AddEdge(0, 0);\n        tarjan.AddEdge(0, 1);\n\n        var sccs = tarjan.FindSCCs();\n\n        sccs.Should().Contain(scc => scc.Contains(0) && scc.Count == 1);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Graph/TopologicalSortTests.cs",
    "content": "using Algorithms.Graph;\nusing DataStructures.Graph;\n\nnamespace Algorithms.Tests.Graph;\n\npublic class TopologicalSortTests\n{\n    /// <summary>\n    ///     Test topological sort on a simple linear DAG: A → B → C.\n    ///     Expected order: [A, B, C].\n    /// </summary>\n    [Test]\n    public void Sort_SimpleLinearGraph_ReturnsCorrectOrder()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(3);\n        var vertexA = graph.AddVertex(\"A\");\n        var vertexB = graph.AddVertex(\"B\");\n        var vertexC = graph.AddVertex(\"C\");\n\n        graph.AddEdge(vertexA, vertexB, 1);\n        graph.AddEdge(vertexB, vertexC, 1);\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act\n        var result = topologicalSort.Sort(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(3));\n        Assert.That(result[0], Is.EqualTo(vertexA));\n        Assert.That(result[1], Is.EqualTo(vertexB));\n        Assert.That(result[2], Is.EqualTo(vertexC));\n    }\n\n    /// <summary>\n    ///     Test Kahn's algorithm on a simple linear DAG: A → B → C.\n    ///     Expected order: [A, B, C].\n    /// </summary>\n    [Test]\n    public void SortKahn_SimpleLinearGraph_ReturnsCorrectOrder()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(3);\n        var vertexA = graph.AddVertex(\"A\");\n        var vertexB = graph.AddVertex(\"B\");\n        var vertexC = graph.AddVertex(\"C\");\n\n        graph.AddEdge(vertexA, vertexB, 1);\n        graph.AddEdge(vertexB, vertexC, 1);\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act\n        var result = topologicalSort.SortKahn(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(3));\n        Assert.That(result[0], Is.EqualTo(vertexA));\n        Assert.That(result[1], Is.EqualTo(vertexB));\n        Assert.That(result[2], Is.EqualTo(vertexC));\n    }\n\n    /// <summary>\n    ///     Test topological sort on a DAG with multiple valid orderings.\n    ///     Graph: A → C\n    ///            B → C\n    ///     Valid orderings: [A, B, C] or [B, A, C].\n    ///     We verify that C comes after both A and B.\n    /// </summary>\n    [Test]\n    public void Sort_GraphWithMultipleValidOrderings_ReturnsValidOrder()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(3);\n        var vertexA = graph.AddVertex(\"A\");\n        var vertexB = graph.AddVertex(\"B\");\n        var vertexC = graph.AddVertex(\"C\");\n\n        graph.AddEdge(vertexA, vertexC, 1);\n        graph.AddEdge(vertexB, vertexC, 1);\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act\n        var result = topologicalSort.Sort(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(3));\n\n        // C should come after both A and B\n        var indexA = result.IndexOf(vertexA);\n        var indexB = result.IndexOf(vertexB);\n        var indexC = result.IndexOf(vertexC);\n\n        Assert.That(indexC, Is.GreaterThan(indexA));\n        Assert.That(indexC, Is.GreaterThan(indexB));\n    }\n\n    /// <summary>\n    ///     Test Kahn's algorithm on a DAG with multiple valid orderings.\n    ///     Graph: A → C\n    ///            B → C\n    ///     Valid orderings: [A, B, C] or [B, A, C].\n    ///     We verify that C comes after both A and B.\n    /// </summary>\n    [Test]\n    public void SortKahn_GraphWithMultipleValidOrderings_ReturnsValidOrder()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(3);\n        var vertexA = graph.AddVertex(\"A\");\n        var vertexB = graph.AddVertex(\"B\");\n        var vertexC = graph.AddVertex(\"C\");\n\n        graph.AddEdge(vertexA, vertexC, 1);\n        graph.AddEdge(vertexB, vertexC, 1);\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act\n        var result = topologicalSort.SortKahn(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(3));\n\n        // C should come after both A and B\n        var indexA = result.IndexOf(vertexA);\n        var indexB = result.IndexOf(vertexB);\n        var indexC = result.IndexOf(vertexC);\n\n        Assert.That(indexC, Is.GreaterThan(indexA));\n        Assert.That(indexC, Is.GreaterThan(indexB));\n    }\n\n    /// <summary>\n    ///     Test topological sort on a more complex DAG.\n    ///     Graph: A → B → D\n    ///            A → C → D\n    ///     Valid orderings include: [A, B, C, D], [A, C, B, D].\n    ///     We verify that A comes first and D comes last.\n    /// </summary>\n    [Test]\n    public void Sort_ComplexDAG_ReturnsValidOrder()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(4);\n        var vertexA = graph.AddVertex(\"A\");\n        var vertexB = graph.AddVertex(\"B\");\n        var vertexC = graph.AddVertex(\"C\");\n        var vertexD = graph.AddVertex(\"D\");\n\n        graph.AddEdge(vertexA, vertexB, 1);\n        graph.AddEdge(vertexA, vertexC, 1);\n        graph.AddEdge(vertexB, vertexD, 1);\n        graph.AddEdge(vertexC, vertexD, 1);\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act\n        var result = topologicalSort.Sort(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(4));\n        Assert.That(result[0], Is.EqualTo(vertexA)); // A must be first\n        Assert.That(result[3], Is.EqualTo(vertexD)); // D must be last\n\n        // B and C should come after A and before D\n        var indexB = result.IndexOf(vertexB);\n        var indexC = result.IndexOf(vertexC);\n\n        Assert.That(indexB, Is.GreaterThan(0));\n        Assert.That(indexB, Is.LessThan(3));\n        Assert.That(indexC, Is.GreaterThan(0));\n        Assert.That(indexC, Is.LessThan(3));\n    }\n\n    /// <summary>\n    ///     Test Kahn's algorithm on a more complex DAG.\n    ///     Graph: A → B → D\n    ///            A → C → D\n    ///     Valid orderings include: [A, B, C, D], [A, C, B, D].\n    ///     We verify that A comes first and D comes last.\n    /// </summary>\n    [Test]\n    public void SortKahn_ComplexDAG_ReturnsValidOrder()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(4);\n        var vertexA = graph.AddVertex(\"A\");\n        var vertexB = graph.AddVertex(\"B\");\n        var vertexC = graph.AddVertex(\"C\");\n        var vertexD = graph.AddVertex(\"D\");\n\n        graph.AddEdge(vertexA, vertexB, 1);\n        graph.AddEdge(vertexA, vertexC, 1);\n        graph.AddEdge(vertexB, vertexD, 1);\n        graph.AddEdge(vertexC, vertexD, 1);\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act\n        var result = topologicalSort.SortKahn(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(4));\n        Assert.That(result[0], Is.EqualTo(vertexA)); // A must be first\n        Assert.That(result[3], Is.EqualTo(vertexD)); // D must be last\n\n        // B and C should come after A and before D\n        var indexB = result.IndexOf(vertexB);\n        var indexC = result.IndexOf(vertexC);\n\n        Assert.That(indexB, Is.GreaterThan(0));\n        Assert.That(indexB, Is.LessThan(3));\n        Assert.That(indexC, Is.GreaterThan(0));\n        Assert.That(indexC, Is.LessThan(3));\n    }\n\n    /// <summary>\n    ///     Test topological sort on a graph with a cycle.\n    ///     Graph: A → B → C → A (cycle).\n    ///     Should throw InvalidOperationException.\n    /// </summary>\n    [Test]\n    public void Sort_GraphWithCycle_ThrowsInvalidOperationException()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(3);\n        var vertexA = graph.AddVertex(\"A\");\n        var vertexB = graph.AddVertex(\"B\");\n        var vertexC = graph.AddVertex(\"C\");\n\n        graph.AddEdge(vertexA, vertexB, 1);\n        graph.AddEdge(vertexB, vertexC, 1);\n        graph.AddEdge(vertexC, vertexA, 1); // Creates a cycle\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act & Assert\n        Assert.Throws<InvalidOperationException>(() => topologicalSort.Sort(graph));\n    }\n\n    /// <summary>\n    ///     Test Kahn's algorithm on a graph with a cycle.\n    ///     Graph: A → B → C → A (cycle).\n    ///     Should throw InvalidOperationException.\n    /// </summary>\n    [Test]\n    public void SortKahn_GraphWithCycle_ThrowsInvalidOperationException()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(3);\n        var vertexA = graph.AddVertex(\"A\");\n        var vertexB = graph.AddVertex(\"B\");\n        var vertexC = graph.AddVertex(\"C\");\n\n        graph.AddEdge(vertexA, vertexB, 1);\n        graph.AddEdge(vertexB, vertexC, 1);\n        graph.AddEdge(vertexC, vertexA, 1); // Creates a cycle\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act & Assert\n        Assert.Throws<InvalidOperationException>(() => topologicalSort.SortKahn(graph));\n    }\n\n    /// <summary>\n    ///     Test topological sort on a single vertex graph.\n    ///     Graph: A (no edges).\n    ///     Expected order: [A].\n    /// </summary>\n    [Test]\n    public void Sort_SingleVertexGraph_ReturnsSingleVertex()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(1);\n        var vertexA = graph.AddVertex(\"A\");\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act\n        var result = topologicalSort.Sort(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(1));\n        Assert.That(result[0], Is.EqualTo(vertexA));\n    }\n\n    /// <summary>\n    ///     Test Kahn's algorithm on a single vertex graph.\n    ///     Graph: A (no edges).\n    ///     Expected order: [A].\n    /// </summary>\n    [Test]\n    public void SortKahn_SingleVertexGraph_ReturnsSingleVertex()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(1);\n        var vertexA = graph.AddVertex(\"A\");\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act\n        var result = topologicalSort.SortKahn(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(1));\n        Assert.That(result[0], Is.EqualTo(vertexA));\n    }\n\n    /// <summary>\n    ///     Test topological sort on a disconnected DAG.\n    ///     Graph: A → B (component 1)\n    ///            C → D (component 2)\n    ///     Valid orderings: [A, B, C, D], [A, C, B, D], [C, A, B, D], [C, D, A, B], etc.\n    ///     We verify that A comes before B and C comes before D.\n    /// </summary>\n    [Test]\n    public void Sort_DisconnectedDAG_ReturnsValidOrder()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(4);\n        var vertexA = graph.AddVertex(\"A\");\n        var vertexB = graph.AddVertex(\"B\");\n        var vertexC = graph.AddVertex(\"C\");\n        var vertexD = graph.AddVertex(\"D\");\n\n        graph.AddEdge(vertexA, vertexB, 1);\n        graph.AddEdge(vertexC, vertexD, 1);\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act\n        var result = topologicalSort.Sort(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(4));\n\n        // A should come before B\n        var indexA = result.IndexOf(vertexA);\n        var indexB = result.IndexOf(vertexB);\n        Assert.That(indexB, Is.GreaterThan(indexA));\n\n        // C should come before D\n        var indexC = result.IndexOf(vertexC);\n        var indexD = result.IndexOf(vertexD);\n        Assert.That(indexD, Is.GreaterThan(indexC));\n    }\n\n    /// <summary>\n    ///     Test Kahn's algorithm on a disconnected DAG.\n    ///     Graph: A → B (component 1)\n    ///            C → D (component 2)\n    ///     Valid orderings: [A, B, C, D], [A, C, B, D], [C, A, B, D], [C, D, A, B], etc.\n    ///     We verify that A comes before B and C comes before D.\n    /// </summary>\n    [Test]\n    public void SortKahn_DisconnectedDAG_ReturnsValidOrder()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(4);\n        var vertexA = graph.AddVertex(\"A\");\n        var vertexB = graph.AddVertex(\"B\");\n        var vertexC = graph.AddVertex(\"C\");\n        var vertexD = graph.AddVertex(\"D\");\n\n        graph.AddEdge(vertexA, vertexB, 1);\n        graph.AddEdge(vertexC, vertexD, 1);\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act\n        var result = topologicalSort.SortKahn(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(4));\n\n        // A should come before B\n        var indexA = result.IndexOf(vertexA);\n        var indexB = result.IndexOf(vertexB);\n        Assert.That(indexB, Is.GreaterThan(indexA));\n\n        // C should come before D\n        var indexC = result.IndexOf(vertexC);\n        var indexD = result.IndexOf(vertexD);\n        Assert.That(indexD, Is.GreaterThan(indexC));\n    }\n\n    /// <summary>\n    ///     Test topological sort on a real-world scenario: course prerequisites.\n    ///     Graph represents course dependencies:\n    ///     - Intro to CS (A) is a prerequisite for Data Structures (B) and Algorithms (C).\n    ///     - Data Structures (B) is a prerequisite for Advanced Algorithms (D).\n    ///     - Algorithms (C) is a prerequisite for Advanced Algorithms (D).\n    ///     Expected: A must come first, D must come last.\n    /// </summary>\n    [Test]\n    public void Sort_CoursePrerequisitesScenario_ReturnsValidOrder()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(4);\n        var introCS = graph.AddVertex(\"Intro to CS\");\n        var dataStructures = graph.AddVertex(\"Data Structures\");\n        var algorithms = graph.AddVertex(\"Algorithms\");\n        var advancedAlgorithms = graph.AddVertex(\"Advanced Algorithms\");\n\n        graph.AddEdge(introCS, dataStructures, 1);\n        graph.AddEdge(introCS, algorithms, 1);\n        graph.AddEdge(dataStructures, advancedAlgorithms, 1);\n        graph.AddEdge(algorithms, advancedAlgorithms, 1);\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act\n        var result = topologicalSort.Sort(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(4));\n        Assert.That(result[0], Is.EqualTo(introCS)); // Must take Intro to CS first\n        Assert.That(result[3], Is.EqualTo(advancedAlgorithms)); // Advanced Algorithms must be last\n\n        // Data Structures and Algorithms should be in the middle\n        var indexDS = result.IndexOf(dataStructures);\n        var indexAlgo = result.IndexOf(algorithms);\n\n        Assert.That(indexDS, Is.GreaterThan(0));\n        Assert.That(indexDS, Is.LessThan(3));\n        Assert.That(indexAlgo, Is.GreaterThan(0));\n        Assert.That(indexAlgo, Is.LessThan(3));\n    }\n\n    /// <summary>\n    ///     Test Kahn's algorithm on a real-world scenario: course prerequisites.\n    ///     Graph represents course dependencies:\n    ///     - Intro to CS (A) is a prerequisite for Data Structures (B) and Algorithms (C).\n    ///     - Data Structures (B) is a prerequisite for Advanced Algorithms (D).\n    ///     - Algorithms (C) is a prerequisite for Advanced Algorithms (D).\n    ///     Expected: A must come first, D must come last.\n    /// </summary>\n    [Test]\n    public void SortKahn_CoursePrerequisitesScenario_ReturnsValidOrder()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(4);\n        var introCS = graph.AddVertex(\"Intro to CS\");\n        var dataStructures = graph.AddVertex(\"Data Structures\");\n        var algorithms = graph.AddVertex(\"Algorithms\");\n        var advancedAlgorithms = graph.AddVertex(\"Advanced Algorithms\");\n\n        graph.AddEdge(introCS, dataStructures, 1);\n        graph.AddEdge(introCS, algorithms, 1);\n        graph.AddEdge(dataStructures, advancedAlgorithms, 1);\n        graph.AddEdge(algorithms, advancedAlgorithms, 1);\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act\n        var result = topologicalSort.SortKahn(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(4));\n        Assert.That(result[0], Is.EqualTo(introCS)); // Must take Intro to CS first\n        Assert.That(result[3], Is.EqualTo(advancedAlgorithms)); // Advanced Algorithms must be last\n\n        // Data Structures and Algorithms should be in the middle\n        var indexDS = result.IndexOf(dataStructures);\n        var indexAlgo = result.IndexOf(algorithms);\n\n        Assert.That(indexDS, Is.GreaterThan(0));\n        Assert.That(indexDS, Is.LessThan(3));\n        Assert.That(indexAlgo, Is.GreaterThan(0));\n        Assert.That(indexAlgo, Is.LessThan(3));\n    }\n\n    /// <summary>\n    ///     Test topological sort with integer vertices.\n    ///     Graph: 1 → 2 → 3.\n    ///     Expected order: [1, 2, 3].\n    /// </summary>\n    [Test]\n    public void Sort_IntegerVertices_ReturnsCorrectOrder()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<int>(3);\n        var vertex1 = graph.AddVertex(1);\n        var vertex2 = graph.AddVertex(2);\n        var vertex3 = graph.AddVertex(3);\n\n        graph.AddEdge(vertex1, vertex2, 1);\n        graph.AddEdge(vertex2, vertex3, 1);\n\n        var topologicalSort = new TopologicalSort<int>();\n\n        // Act\n        var result = topologicalSort.Sort(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(3));\n        Assert.That(result[0], Is.EqualTo(vertex1));\n        Assert.That(result[1], Is.EqualTo(vertex2));\n        Assert.That(result[2], Is.EqualTo(vertex3));\n    }\n\n    /// <summary>\n    ///     Test Kahn's algorithm with integer vertices.\n    ///     Graph: 1 → 2 → 3.\n    ///     Expected order: [1, 2, 3].\n    /// </summary>\n    [Test]\n    public void SortKahn_IntegerVertices_ReturnsCorrectOrder()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<int>(3);\n        var vertex1 = graph.AddVertex(1);\n        var vertex2 = graph.AddVertex(2);\n        var vertex3 = graph.AddVertex(3);\n\n        graph.AddEdge(vertex1, vertex2, 1);\n        graph.AddEdge(vertex2, vertex3, 1);\n\n        var topologicalSort = new TopologicalSort<int>();\n\n        // Act\n        var result = topologicalSort.SortKahn(graph);\n\n        // Assert\n        Assert.That(result.Count, Is.EqualTo(3));\n        Assert.That(result[0], Is.EqualTo(vertex1));\n        Assert.That(result[1], Is.EqualTo(vertex2));\n        Assert.That(result[2], Is.EqualTo(vertex3));\n    }\n\n    /// <summary>\n    ///     Test topological sort on a graph with self-loop (cycle).\n    ///     Graph: A → A (self-loop).\n    ///     Should throw InvalidOperationException.\n    /// </summary>\n    [Test]\n    public void Sort_GraphWithSelfLoop_ThrowsInvalidOperationException()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(1);\n        var vertexA = graph.AddVertex(\"A\");\n\n        graph.AddEdge(vertexA, vertexA, 1); // Self-loop\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act & Assert\n        Assert.Throws<InvalidOperationException>(() => topologicalSort.Sort(graph));\n    }\n\n    /// <summary>\n    ///     Test Kahn's algorithm on a graph with self-loop (cycle).\n    ///     Graph: A → A (self-loop).\n    ///     Should throw InvalidOperationException.\n    /// </summary>\n    [Test]\n    public void SortKahn_GraphWithSelfLoop_ThrowsInvalidOperationException()\n    {\n        // Arrange\n        var graph = new DirectedWeightedGraph<string>(1);\n        var vertexA = graph.AddVertex(\"A\");\n\n        graph.AddEdge(vertexA, vertexA, 1); // Self-loop\n\n        var topologicalSort = new TopologicalSort<string>();\n\n        // Act & Assert\n        Assert.Throws<InvalidOperationException>(() => topologicalSort.SortKahn(graph));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Helpers/IntComparer.cs",
    "content": "namespace Algorithms.Tests.Helpers;\n\ninternal class IntComparer : IComparer<int>\n{\n    public int Compare(int x, int y) => x.CompareTo(y);\n}\n"
  },
  {
    "path": "Algorithms.Tests/Helpers/RandomHelper.cs",
    "content": "namespace Algorithms.Tests.Helpers;\n\ninternal static class RandomHelper\n{\n    public static (int[] correctArray, int[] testArray) GetArrays(int n)\n    {\n        var testArr = new int[n];\n        var correctArray = new int[n];\n\n        for (var i = 0; i < n; i++)\n        {\n            var t = TestContext.CurrentContext.Random.Next(1_000_000);\n            testArr[i] = t;\n            correctArray[i] = t;\n        }\n\n        return (correctArray, testArr);\n    }\n\n    public static (string[] correctArray, string[] testArray) GetStringArrays(\n        int n,\n        int maxLength,\n        bool equalLength)\n    {\n        var testArr = new string[n];\n        var correctArray = new string[n];\n        var length = TestContext.CurrentContext.Random.Next(2, maxLength);\n\n        for (var i = 0; i < n; i++)\n        {\n            if (!equalLength)\n            {\n                length = TestContext.CurrentContext.Random.Next(2, maxLength);\n            }\n\n            var chars = new char[length];\n            for (var j = 0; j < length; j++)\n            {\n                chars[j] = (char)TestContext.CurrentContext.Random.Next(97, 123);\n            }\n\n            var t = new string(chars);\n            testArr[i] = t;\n            correctArray[i] = t;\n        }\n\n        return (correctArray, testArr);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Knapsack/BranchAndBoundKnapsackSolverTests.cs",
    "content": "using Algorithms.Knapsack;\n\nnamespace Algorithms.Tests.Knapsack;\n\npublic static class BranchAndBoundKnapsackSolverTests\n{\n    [Test]\n    public static void BranchAndBoundTest_Example1_Success()\n    {\n        // Arrange\n        var items = new[] { 'A', 'B', 'C', 'D' };\n        var values = new[] { 18, 20, 14, 18 };\n        var weights = new[] { 2, 4, 6, 9 };\n\n        var capacity = 15;\n\n        Func<char, int> weightSelector = x => weights[Array.IndexOf(items, x)];\n        Func<char, double> valueSelector = x => values[Array.IndexOf(items, x)];\n\n        // Act\n        var solver = new BranchAndBoundKnapsackSolver<char>();\n        var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector);\n\n        // Assert\n        actualResult.Should().BeEquivalentTo(new[] { 'A', 'B', 'D' });\n    }\n\n    [Test]\n    public static void BranchAndBoundTest_Example2_Success()\n    {\n        // Arrange\n        var items = new[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' };\n        var values = new[] { 505, 352, 458, 220, 354, 414, 498, 545, 473, 543 };\n        var weights = new[] { 23, 26, 20, 18, 32, 27, 29, 26, 30, 27 };\n\n        var capacity = 67;\n\n        Func<char, int> weightSelector = x => weights[Array.IndexOf(items, x)];\n        Func<char, double> valueSelector = x => values[Array.IndexOf(items, x)];\n\n        // Act\n        var solver = new BranchAndBoundKnapsackSolver<char>();\n        var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector);\n\n        // Assert\n        actualResult.Should().BeEquivalentTo(new[] { 'H', 'D', 'A' });\n    }\n\n    [Test]\n    public static void BranchAndBoundTest_CapacityIsZero_NothingTaken()\n    {\n        // Arrange\n        var items = new[] { 'A', 'B', 'C', 'D' };\n        var values = new[] { 18, 20, 14, 18 };\n        var weights = new[] { 2, 4, 6, 9 };\n\n        var capacity = 0;\n\n        Func<char, int> weightSelector = x => weights[Array.IndexOf(items, x)];\n        Func<char, double> valueSelector = x => values[Array.IndexOf(items, x)];\n\n        // Act\n        var solver = new BranchAndBoundKnapsackSolver<char>();\n        var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector);\n\n        // Assert\n        actualResult.Should().BeEmpty();\n    }\n\n    [Test]\n    public static void BranchAndBoundTest_PlentyCapacity_EverythingIsTaken()\n    {\n        // Arrange\n        var items = new[] { 'A', 'B', 'C', 'D' };\n        var values = new[] { 18, 20, 14, 18 };\n        var weights = new[] { 2, 4, 6, 9 };\n\n        var capacity = 1000;\n\n        Func<char, int> weightSelector = x => weights[Array.IndexOf(items, x)];\n        Func<char, double> valueSelector = x => values[Array.IndexOf(items, x)];\n\n        // Act\n        var solver = new BranchAndBoundKnapsackSolver<char>();\n        var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector);\n\n        // Assert\n        actualResult.Should().BeEquivalentTo(items);\n    }\n\n    [Test]\n    public static void BranchAndBoundTest_NoItems_NothingTaken()\n    {\n        // Arrange\n        var items = Array.Empty<char>();\n        var values = Array.Empty<int>();\n        var weights = Array.Empty<int>();\n\n        var capacity = 15;\n\n        Func<char, int> weightSelector = x => weights[Array.IndexOf(items, x)];\n        Func<char, double> valueSelector = x => values[Array.IndexOf(items, x)];\n\n        // Act\n        var solver = new BranchAndBoundKnapsackSolver<char>();\n        var actualResult = solver.Solve(items, capacity, weightSelector, valueSelector);\n\n        // Assert\n        actualResult.Should().BeEmpty();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Knapsack/DynamicProgrammingKnapsackSolverTests.cs",
    "content": "using Algorithms.Knapsack;\n\nnamespace Algorithms.Tests.Knapsack;\n\npublic static class DynamicProgrammingKnapsackSolverTests\n{\n    [Test]\n    public static void SmallSampleOfChar()\n    {\n        //Arrange\n        var items = new[] { 'A', 'B', 'C' };\n        var val = new[] { 50, 100, 130 };\n        var wt = new[] { 10, 20, 40 };\n\n        var capacity = 50;\n\n        Func<char, int> weightSelector = x => wt[Array.IndexOf(items, x)];\n        Func<char, double> valueSelector = x => val[Array.IndexOf(items, x)];\n\n        var expected = new[] { 'A', 'C' };\n\n\n        //Act\n        var solver = new DynamicProgrammingKnapsackSolver<char>();\n        var actual = solver.Solve(items, capacity, weightSelector, valueSelector);\n\n        //Assert\n        Assert.That(actual.OrderBy(x => x), Is.EqualTo(expected.OrderBy(x => x)));\n    }\n\n    [Test]\n    public static void FSU_P01()\n    {\n        // Data from https://people.sc.fsu.edu/~jburkardt/datasets/knapsack_01/knapsack_01.html\n\n        //Arrange\n        var items = new[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' };\n        var val = new[] { 92, 57, 49, 68, 60, 43, 67, 84, 87, 72 };\n        var wt = new[] { 23, 31, 29, 44, 53, 38, 63, 85, 89, 82 };\n\n        var capacity = 165;\n\n        Func<char, int> weightSelector = x => wt[Array.IndexOf(items, x)];\n        Func<char, double> valueSelector = x => val[Array.IndexOf(items, x)];\n\n        var expected = new[] { 'A', 'B', 'C', 'D', 'F' };\n\n        //Act\n        var solver = new DynamicProgrammingKnapsackSolver<char>();\n        var actual = solver.Solve(items, capacity, weightSelector, valueSelector);\n\n        //Assert\n        Assert.That(actual.OrderBy(x => x), Is.EqualTo(expected.OrderBy(x => x)));\n    }\n\n    [Test]\n    public static void FSU_P07_WithNonIntegralValues()\n    {\n        // Shows how to handle weights with 1 significant digit right of the decimal\n        // Data from https://people.sc.fsu.edu/~jburkardt/datasets/knapsack_01/knapsack_01.html\n\n        //Arrange\n        var val = new[] { 135, 139, 149, 150, 156, 163, 173, 184, 192, 201, 210, 214, 221, 229, 240 };\n        var wt = new[] { 7.0, 7.3, 7.7, 8.0, 8.2, 8.7, 9.0, 9.4, 9.8, 10.6, 11.0, 11.3, 11.5, 11.8, 12.0 };\n        var items = Enumerable.Range(1, val.Count()).ToArray();\n\n        var capacity = 75;\n\n        Func<int, int> weightSelector = x => (int)(wt[Array.IndexOf(items, x)] * 10);\n        Func<int, double> valueSelector = x => val[Array.IndexOf(items, x)];\n\n        var expected = new[] { 1, 3, 5, 7, 8, 9, 14, 15 };\n\n\n        //Act\n        var solver = new DynamicProgrammingKnapsackSolver<int>();\n        var actual = solver.Solve(items, capacity * 10, weightSelector, valueSelector);\n\n        //Assert\n        Assert.That(actual.OrderBy(x => x), Is.EqualTo(expected.OrderBy(x => x)));\n    }\n\n\n    [Test]\n    public static void TakesHalf(\n        [Random(0, 1000, 100, Distinct = true)]\n        int length)\n    {\n        //Arrange\n        var solver = new DynamicProgrammingKnapsackSolver<int>();\n        var items = Enumerable.Repeat(42, 2 * length).ToArray();\n        var expectedResult = Enumerable.Repeat(42, length);\n\n        //Act\n        var result = solver.Solve(items, length, _ => 1, _ => 1);\n\n        //Assert\n        Assert.That(result, Is.EqualTo(expectedResult));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Knapsack/NaiveKnapsackSolverTests.cs",
    "content": "using Algorithms.Knapsack;\n\nnamespace Algorithms.Tests.Knapsack;\n\npublic static class NaiveKnapsackSolverTests\n{\n    [Test]\n    public static void TakesHalf(\n        [Random(0, 1000, 100, Distinct = true)]\n        int length)\n    {\n        //Arrange\n        var solver = new NaiveKnapsackSolver<int>();\n        var items = Enumerable.Repeat(42, 2 * length).ToArray();\n        var expectedResult = Enumerable.Repeat(42, length);\n\n        //Act\n        var result = solver.Solve(items, length, _ => 1, _ => 1);\n\n        //Assert\n        Assert.That(result, Is.EqualTo(expectedResult));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/LinearAlgebra/Distances/ChebyshevTests.cs",
    "content": "using Algorithms.LinearAlgebra.Distances;\n\nnamespace Algorithms.Tests.LinearAlgebra.Distances;\n\npublic class ChebyshevTests\n{\n    [TestCase(new[] { 1.0, 1.0 }, new[] { 2.0, 2.0 }, 1.0)]\n    [TestCase(new[] { 1.0, 1.0, 9.0 }, new[] { 2.0, 2.0, -5.2 }, 14.2)]\n    [TestCase(new[] { 1.0, 2.0, 3.0 }, new[] { 1.0, 2.0, 3.0 }, 0.0)]\n    [TestCase(new[] { 1.0, 2.0, 3.0, 4.0 }, new[] { 1.75, 2.25, -3.0, 0.5 }, 6.0)]\n    public void DistanceTest(double[] point1, double[] point2, double expectedDistance)\n    {\n        Chebyshev.Distance(point1, point2).Should().BeApproximately(expectedDistance, 0.01);\n    }\n\n    [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0 })]\n    [TestCase(new[] { 1.0 }, new[] { 1.0, 2.0, 3.0 })]\n    public void DistanceThrowsArgumentExceptionOnDifferentPointDimensions(double[] point1, double[] point2)\n    {\n        Action action = () => Chebyshev.Distance(point1, point2);\n        action.Should().Throw<ArgumentException>();\n    }\n}"
  },
  {
    "path": "Algorithms.Tests/LinearAlgebra/Distances/EuclideanTests.cs",
    "content": "using Algorithms.LinearAlgebra.Distances;\n\nnamespace Algorithms.Tests.LinearAlgebra.Distances;\n\npublic static class EuclideanTests\n{\n    /// <summary>\n    /// Test the result given by Euclidean distance function.\n    /// </summary>\n    /// <param name=\"point1\">Origin point.</param>\n    /// <param name=\"point2\">Target point.</param>\n    /// <param name=\"expectedResult\">Expected result.</param>\n    [TestCase(new[] { 1.5 }, new[] { -1.0 }, 2.5)]\n    [TestCase(new[] { 7.0, 4.0, 3.0 }, new[] { 17.0, 6.0, 2.0 }, 10.247)]\n    public static void DistanceTest(double[] point1, double[] point2, double expectedResult)\n    {\n        Euclidean.Distance(point1, point2).Should().BeApproximately(expectedResult, 0.01);\n    }\n\n    /// <summary>\n    /// Throws ArgumentException if two different dimension arrays are given.\n    /// </summary>\n    /// <param name=\"point1\">First point of N dimensions.</param>\n    /// <param name=\"point2\">Second point of M dimensions, M != N.</param>\n    [TestCase(new[] { 7.0, 4.5 }, new[] { -3.0 })]\n    [TestCase(new[] { 12.0 }, new[] { 1.5, 7.0, 3.2 })]\n    public static void DistanceThrowsArgumentExceptionOnDifferentPointDimensions(double[] point1, double[] point2)\n    {\n        Action action = () => Euclidean.Distance(point1, point2);\n        action.Should().Throw<ArgumentException>();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/LinearAlgebra/Distances/ManhattanTests.cs",
    "content": "using Algorithms.LinearAlgebra.Distances;\n\nnamespace Algorithms.Tests.LinearAlgebra.Distances;\n\npublic class ManhattanTests\n{\n    /// <summary>\n    /// Test the result given by Manhattan distance function.\n    /// </summary>\n    /// <param name=\"point1\">Origin point.</param>\n    /// <param name=\"point2\">Target point.</param>\n    /// <param name=\"expectedDistance\">Expected result.</param>\n    [TestCase(new[] { 1.5 }, new[] { -1.0 }, 2.5)]\n    [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0, 5.0 }, 5)]\n    [TestCase(new[] { 1.0, 2.0, 3.0 }, new[] { 1.0, 2.0, 3.0 }, 0)]\n    [TestCase(new[] { 1.0, 2.0, 3.0, 4.0 }, new[] { 1.75, 2.25, -3.0, 0.5 }, 10.5)]\n    public void DistanceTest(double[] point1, double[] point2, double expectedDistance)\n    {\n        Manhattan.Distance(point1, point2).Should().BeApproximately(expectedDistance, 0.01);\n    }\n\n    /// <summary>\n    /// Test that it throws ArgumentException if two different dimension arrays are given.\n    /// </summary>\n    /// <param name=\"point1\">First point of N dimensions.</param>\n    /// <param name=\"point2\">Second point of M dimensions, M != N.</param>\n    [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0 })]\n    [TestCase(new[] { 1.0 }, new[] { 1.0, 2.0, 3.0 })]\n    public void DistanceThrowsArgumentExceptionOnDifferentPointDimensions(double[] point1, double[] point2)\n    {\n        Action action = () => Manhattan.Distance(point1, point2);\n        action.Should().Throw<ArgumentException>();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/LinearAlgebra/Distances/MinkowskiTests.cs",
    "content": "using Algorithms.LinearAlgebra.Distances;\n\nnamespace Algorithms.Tests.LinearAlgebra.Distances;\n\npublic class MinkowskiTests\n{\n    [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0, 5.0 }, 1, 5.0)] // Simulate Manhattan condition\n    [TestCase(new[] { 7.0, 4.0, 3.0 }, new[] { 17.0, 6.0, 2.0 }, 2, 10.247)] // Simulate Euclidean condition\n    [TestCase(new[] { 1.0, 2.0, 3.0, 4.0 }, new[] { 1.75, 2.25, -3.0, 0.5 }, 20, 6.0)] // Simulate Chebyshev condition\n    [TestCase(new[] { 1.0, 1.0, 9.0 }, new[] { 2.0, 2.0, -5.2 }, 3, 14.2)]\n    [TestCase(new[] { 1.0, 2.0, 3.0 }, new[] { 1.0, 2.0, 3.0 }, 5, 0.0)]\n    public void DistanceTest(double[] point1, double[] point2, int order, double expectedDistance)\n    {\n        Minkowski.Distance(point1, point2, order).Should().BeApproximately(expectedDistance, 0.01);\n    }\n\n    [TestCase(new[] { 2.0, 3.0 }, new[] { -1.0 }, 2)]\n    [TestCase(new[] { 1.0 }, new[] { 1.0, 2.0, 3.0 }, 1)]\n    [TestCase(new[] { 1.0, 1.0 }, new[] { 2.0, 2.0 }, 0)]\n    public void DistanceThrowsArgumentExceptionOnInvalidInput(double[] point1, double[] point2, int order)\n    {\n        Action action = () => Minkowski.Distance(point1, point2, order);\n        action.Should().Throw<ArgumentException>();\n    }\n}"
  },
  {
    "path": "Algorithms.Tests/LinearAlgebra/Eigenvalue/PowerIterationTests.cs",
    "content": "using Algorithms.LinearAlgebra.Eigenvalue;\n\nnamespace Algorithms.Tests.LinearAlgebra.Eigenvalue;\n\npublic class PowerIterationTests\n{\n    private static readonly object[] DominantVectorTestCases =\n    [\n        new object[]\n        {\n            3.0,\n            new[] { 0.7071039, 0.70710966 },\n            new[,] { { 2.0, 1.0 }, { 1.0, 2.0 } },\n        },\n        new object[]\n        {\n            4.235889,\n            new[] { 0.91287093, 0.40824829 },\n            new[,] { { 2.0, 5.0 }, { 1.0, 2.0 } },\n        },\n    ];\n\n    private readonly double epsilon = Math.Pow(10, -5);\n\n    [Test]\n    public void Dominant_ShouldThrowArgumentException_WhenSourceMatrixIsNotSquareShaped()\n    {\n        // Arrange\n        var source = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 0, 0, 0 } };\n\n        // Act\n        Action action = () => PowerIteration.Dominant(source, StartVector(source.GetLength(0)), epsilon);\n\n        // Assert\n        action.Should().Throw<ArgumentException>().WithMessage(\"The source matrix is not square-shaped.\");\n    }\n\n    [Test]\n    public void Dominant_ShouldThrowArgumentException_WhenStartVectorIsNotSameSizeAsMatrix()\n    {\n        // Arrange\n        var source = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };\n        var startVector = new double[] { 1, 0, 0, 0 };\n\n        // Act\n        Action action = () => PowerIteration.Dominant(source, startVector, epsilon);\n\n        // Assert\n        action.Should().Throw<ArgumentException>()\n            .WithMessage(\"The length of the start vector doesn't equal the size of the source matrix.\");\n    }\n\n    [TestCaseSource(nameof(DominantVectorTestCases))]\n    public void Dominant_ShouldCalculateDominantEigenvalueAndEigenvector(\n        double eigenvalue,\n        double[] eigenvector,\n        double[,] source)\n    {\n        // Act\n        var (actualEigVal, actualEigVec) =\n            PowerIteration.Dominant(source, StartVector(source.GetLength(0)), epsilon);\n\n        // Assert\n        actualEigVal.Should().BeApproximately(eigenvalue, epsilon);\n        actualEigVec.Magnitude().Should().BeApproximately(eigenvector.Magnitude(), epsilon);\n    }\n\n    private double[] StartVector(int length) => new Random(111111).NextVector(length);\n}\n"
  },
  {
    "path": "Algorithms.Tests/MachineLearning/KNearestNeighborsTests.cs",
    "content": "using NUnit.Framework;\nusing Algorithms.MachineLearning;\nusing System;\n\nnamespace Algorithms.Tests.MachineLearning;\n\n[TestFixture]\npublic class KNearestNeighborsTests\n{\n    [Test]\n    public void Constructor_InvalidK_ThrowsException()\n    {\n        Assert.Throws<ArgumentOutOfRangeException>(() => new KNearestNeighbors<string>(0));\n    }\n\n    [Test]\n    public void AddSample_NullFeatures_ThrowsException()\n    {\n        var knn = new KNearestNeighbors<string>(3);\n        double[]? features = null;\n        Assert.Throws<ArgumentNullException>(() => knn.AddSample(features!, \"A\"));\n    }\n\n    [Test]\n    public void Predict_NoTrainingData_ThrowsException()\n    {\n        var knn = new KNearestNeighbors<string>(1);\n        Assert.Throws<InvalidOperationException>(() => knn.Predict(new[] { 1.0 }));\n    }\n\n    [Test]\n    public void Predict_NullFeatures_ThrowsException()\n    {\n        var knn = new KNearestNeighbors<string>(1);\n        knn.AddSample(new[] { 1.0 }, \"A\");\n        double[]? features = null;\n        Assert.Throws<ArgumentNullException>(() => knn.Predict(features!));\n    }\n\n    [Test]\n    public void EuclideanDistance_DifferentLengths_ThrowsException()\n    {\n        Assert.Throws<ArgumentException>(() => KNearestNeighbors<string>.EuclideanDistance(new[] { 1.0 }, new[] { 1.0, 2.0 }));\n    }\n\n    [Test]\n    public void EuclideanDistance_CorrectResult()\n    {\n        double[] a = { 1.0, 2.0 };\n        double[] b = { 4.0, 6.0 };\n        double expected = 5.0;\n        double actual = KNearestNeighbors<string>.EuclideanDistance(a, b);\n        Assert.That(actual, Is.EqualTo(expected).Within(1e-9));\n    }\n\n    [Test]\n    public void Predict_SingleNeighbor_CorrectLabel()\n    {\n        var knn = new KNearestNeighbors<string>(1);\n        knn.AddSample(new[] { 1.0, 2.0 }, \"A\");\n        knn.AddSample(new[] { 3.0, 4.0 }, \"B\");\n        var label = knn.Predict(new[] { 1.1, 2.1 });\n        Assert.That(label, Is.EqualTo(\"A\"));\n    }\n\n    [Test]\n    public void Predict_MajorityVote_CorrectLabel()\n    {\n        var knn = new KNearestNeighbors<string>(3);\n        knn.AddSample(new[] { 0.0, 0.0 }, \"A\");\n        knn.AddSample(new[] { 0.1, 0.1 }, \"A\");\n        knn.AddSample(new[] { 1.0, 1.0 }, \"B\");\n        var label = knn.Predict(new[] { 0.05, 0.05 });\n        Assert.That(label, Is.EqualTo(\"A\"));\n    }\n\n    [Test]\n    public void Predict_TieBreaker_ReturnsConsistentLabel()\n    {\n        var knn = new KNearestNeighbors<string>(2);\n        knn.AddSample(new[] { 0.0, 0.0 }, \"A\");\n        knn.AddSample(new[] { 1.0, 1.0 }, \"B\");\n        var label = knn.Predict(new[] { 0.5, 0.5 });\n        Assert.That(label, Is.EqualTo(\"A\"));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/MachineLearning/LinearRegressionTests.cs",
    "content": "using Algorithms.MachineLearning;\n\nnamespace Algorithms.Tests.MachineLearning;\n\n/// <summary>\n/// Unit tests for the LinearRegression class.\n/// </summary>\npublic class LinearRegressionTests\n{\n    [Test]\n    public void Fit_ThrowsException_WhenInputIsNull()\n    {\n        var lr = new LinearRegression();\n        Assert.Throws<ArgumentException>(() => lr.Fit(null!, new List<double> { 1 }));\n        Assert.Throws<ArgumentException>(() => lr.Fit(new List<double> { 1 }, null!));\n    }\n\n    [Test]\n    public void Fit_ThrowsException_WhenInputIsEmpty()\n    {\n        var lr = new LinearRegression();\n        Assert.Throws<ArgumentException>(() => lr.Fit(new List<double>(), new List<double>()));\n    }\n\n    [Test]\n    public void Fit_ThrowsException_WhenInputLengthsDiffer()\n    {\n        var lr = new LinearRegression();\n        Assert.Throws<ArgumentException>(() => lr.Fit(new List<double> { 1 }, new List<double> { 2, 3 }));\n    }\n\n    [Test]\n    public void Fit_ThrowsException_WhenXVarianceIsZero()\n    {\n        var lr = new LinearRegression();\n        Assert.Throws<ArgumentException>(() => lr.Fit(new List<double> { 1, 1, 1 }, new List<double> { 2, 3, 4 }));\n    }\n\n    [Test]\n    public void Predict_ThrowsException_IfNotFitted()\n    {\n        var lr = new LinearRegression();\n        Assert.Throws<InvalidOperationException>(() => lr.Predict(1.0));\n        Assert.Throws<InvalidOperationException>(() => lr.Predict(new List<double> { 1.0 }));\n    }\n\n    [Test]\n    public void FitAndPredict_WorksForSimpleData()\n    {\n        // y = 2x + 1\n        var x = new List<double> { 1, 2, 3, 4 };\n        var y = new List<double> { 3, 5, 7, 9 };\n        var lr = new LinearRegression();\n        lr.Fit(x, y);\n        Assert.That(lr.IsFitted, Is.True);\n        Assert.That(lr.Intercept, Is.EqualTo(1.0).Within(1e-6));\n        Assert.That(lr.Slope, Is.EqualTo(2.0).Within(1e-6));\n        Assert.That(lr.Predict(5), Is.EqualTo(11.0).Within(1e-6));\n    }\n\n    [Test]\n    public void FitAndPredict_WorksForNegativeSlope()\n    {\n        // y = -3x + 4\n        var x = new List<double> { 0, 1, 2 };\n        var y = new List<double> { 4, 1, -2 };\n        var lr = new LinearRegression();\n        lr.Fit(x, y);\n        Assert.That(lr.Intercept, Is.EqualTo(4.0).Within(1e-6));\n        Assert.That(lr.Slope, Is.EqualTo(-3.0).Within(1e-6));\n        Assert.That(lr.Predict(3), Is.EqualTo(-5.0).Within(1e-6));\n    }\n\n    [Test]\n    public void Predict_List_WorksCorrectly()\n    {\n        var x = new List<double> { 1, 2, 3 };\n        var y = new List<double> { 2, 4, 6 };\n        var lr = new LinearRegression();\n        lr.Fit(x, y); // y = 2x\n        var predictions = lr.Predict(new List<double> { 4, 5 });\n        Assert.That(predictions[0], Is.EqualTo(8.0).Within(1e-6));\n        Assert.That(predictions[1], Is.EqualTo(10.0).Within(1e-6));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/MachineLearning/LogisticRegressionTests.cs",
    "content": "using NUnit.Framework;\nusing Algorithms.MachineLearning;\nusing System;\n\nnamespace Algorithms.Tests.MachineLearning;\n\n[TestFixture]\npublic class LogisticRegressionTests\n{\n    [Test]\n    public void Fit_ThrowsOnEmptyInput()\n    {\n        var model = new LogisticRegression();\n        Assert.Throws<ArgumentException>(() => model.Fit(Array.Empty<double[]>(), Array.Empty<int>()));\n    }\n\n    [Test]\n    public void Fit_ThrowsOnMismatchedLabels()\n    {\n        var model = new LogisticRegression();\n        double[][] X = { new double[] { 1, 2 } };\n        int[] y = { 1, 0 };\n        Assert.Throws<ArgumentException>(() => model.Fit(X, y));\n    }\n\n    [Test]\n    public void FitAndPredict_WorksOnSimpleData()\n    {\n        // Simple AND logic\n        double[][] X =\n        {\n            new[] { 0.0, 0.0 },\n            new[] { 0.0, 1.0 },\n            new[] { 1.0, 0.0 },\n            new[] { 1.0, 1.0 }\n        };\n        int[] y = { 0, 0, 0, 1 };\n        var model = new LogisticRegression();\n        model.Fit(X, y, epochs: 2000, learningRate: 0.1);\n        Assert.That(model.Predict(new double[] { 0, 0 }), Is.EqualTo(0));\n        Assert.That(model.Predict(new double[] { 0, 1 }), Is.EqualTo(0));\n        Assert.That(model.Predict(new double[] { 1, 0 }), Is.EqualTo(0));\n        Assert.That(model.Predict(new double[] { 1, 1 }), Is.EqualTo(1));\n    }\n\n    [Test]\n    public void PredictProbability_ThrowsOnFeatureMismatch()\n    {\n        var model = new LogisticRegression();\n        double[][] X = { new double[] { 1, 2 } };\n        int[] y = { 1 };\n        model.Fit(X, y);\n        Assert.Throws<ArgumentException>(() => model.PredictProbability(new double[] { 1 }));\n    }\n\n    [Test]\n    public void FeatureCount_ReturnsCorrectValue()\n    {\n        var model = new LogisticRegression();\n        double[][] X = { new double[] { 1, 2, 3 } };\n        int[] y = { 1 };\n        model.Fit(X, y);\n        Assert.That(model.FeatureCount, Is.EqualTo(3));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/ModularArithmetic/ChineseRemainderTheoremTest.cs",
    "content": "using Algorithms.ModularArithmetic;\n\nnamespace Algorithms.Tests.ModularArithmetic;\n\npublic static class ChineseRemainderTheoremTest\n{\n    [Test]\n    public static void TestCompute1()\n    {\n        var expected = 43L;\n\n        // Act\n        var x = ChineseRemainderTheorem.Compute(new List<long> { 1L, 1L, 3L, 1L }, new List<long> { 2L, 3L, 5L, 7L });\n\n        // Assert\n        Assert.That(x, Is.EqualTo(expected));\n    }\n\n    [Test]\n    public static void TestCompute2()\n    {\n        var expected = 100L;\n\n        // Act\n        var x = ChineseRemainderTheorem.Compute(new List<long> { 0L, 0L, 2L, 1L, 1L }, new List<long> { 2L, 5L, 7L, 9L, 11L });\n\n        // Assert\n        Assert.That(x, Is.EqualTo(expected));\n    }\n\n    [Test]\n    public static void TestCompute3()\n    {\n        var expected = 13L;\n\n        // Act\n        var x = ChineseRemainderTheorem.Compute(new List<long> { 1L, 4L, 13L }, new List<long> { 4L, 9L, 25L });\n\n        // Assert\n        Assert.That(x, Is.EqualTo(expected));\n    }\n\n    [Test]\n    public static void TestCompute_RequirementsNotMet_ArgumentLengthDifferent()\n    {\n        // Act\n        void Act() => ChineseRemainderTheorem.Compute(new List<long>(), new List<long> { 5L });\n\n        // Assert\n        _ = Assert.Throws<ArgumentException>(Act);\n    }\n\n    [Test]\n    public static void TestCompute_RequirementsNotMet_NTooSmall()\n    {\n        foreach (var n in new List<long> { long.MinValue, -1L, 0L, 1L })\n        {\n            // Act\n            void Act() => ChineseRemainderTheorem.Compute(new List<long> { 1L }, new List<long> { n });\n\n            // Assert\n            _ = Assert.Throws<ArgumentException>(Act);\n        }\n    }\n\n    [Test]\n    public static void TestCompute_RequirementsNotMet_ATooSmall()\n    {\n        foreach (var a in new List<long> { long.MinValue, -2L, -1L })\n        {\n            // Act\n            void Act() => ChineseRemainderTheorem.Compute(new List<long> { a }, new List<long> { 3L });\n\n            // Assert\n            _ = Assert.Throws<ArgumentException>(Act);\n        }\n    }\n\n    [Test]\n    public static void TestCompute_RequirementsNotMet_NNotCoprime()\n    {\n        foreach (var n in new List<long> { 3L, 9L, 15L, 27L })\n        {\n            // Act\n            void Act() => ChineseRemainderTheorem.Compute(new List<long> { 1L, 1L, 1L, 1L, 1L }, new List<long> { 2L, 3L, 5L, 7L, n });\n\n            // Assert\n            _ = Assert.Throws<ArgumentException>(Act);\n        }\n    }\n\n    [Test]\n    public static void TestCompute_BigInteger_1()\n    {\n        var expected = new BigInteger(43);\n\n        // Act\n        var x = ChineseRemainderTheorem.Compute(\n            new List<BigInteger> { BigInteger.One, BigInteger.One, new BigInteger(3), BigInteger.One },\n            new List<BigInteger> { new BigInteger(2), new BigInteger(3), new BigInteger(5), new BigInteger(7) }\n        );\n\n        // Assert\n        Assert.That(x, Is.EqualTo(expected));\n    }\n\n    [Test]\n    public static void TestCompute_BigInteger_2()\n    {\n        var expected = new BigInteger(100);\n\n        // Act\n        var x = ChineseRemainderTheorem.Compute(\n            new List<BigInteger> { BigInteger.Zero, BigInteger.Zero, new BigInteger(2), BigInteger.One, BigInteger.One },\n            new List<BigInteger> { new BigInteger(2), new BigInteger(5), new BigInteger(7), new BigInteger(9), new BigInteger(11) }\n        );\n\n        // Assert\n        Assert.That(x, Is.EqualTo(expected));\n    }\n\n    [Test]\n    public static void TestCompute_BigInteger_3()\n    {\n        var expected = new BigInteger(13);\n\n        // Act\n        var x = ChineseRemainderTheorem.Compute(\n            new List<BigInteger> { BigInteger.One, new BigInteger(4), new BigInteger(13) },\n            new List<BigInteger> { new BigInteger(4), new BigInteger(9), new BigInteger(25) }\n        );\n\n        // Assert\n        Assert.That(x, Is.EqualTo(expected));\n    }\n\n    [Test]\n    public static void TestCompute_BigInteger_RequirementsNotMet_ArgumentLengthDifferent()\n    {\n        // Act\n        void Act() => ChineseRemainderTheorem.Compute(new List<BigInteger>(), new List<BigInteger> { new BigInteger(5) });\n\n        // Assert\n        _ = Assert.Throws<ArgumentException>(Act);\n    }\n\n    [Test]\n    public static void TestCompute_BigInteger_RequirementsNotMet_NTooSmall()\n    {\n        foreach (var n in new List<BigInteger> { new BigInteger(long.MinValue), BigInteger.MinusOne, BigInteger.Zero, BigInteger.One })\n        {\n            // Act\n            void Act() => ChineseRemainderTheorem.Compute(new List<BigInteger> { BigInteger.One }, new List<BigInteger> { n });\n\n            // Assert\n            _ = Assert.Throws<ArgumentException>(Act);\n        }\n    }\n\n    [Test]\n    public static void TestCompute_BigInteger_RequirementsNotMet_ATooSmall()\n    {\n        foreach (var a in new List<BigInteger> { new BigInteger(long.MinValue), new BigInteger(-2), BigInteger.MinusOne })\n        {\n            // Act\n            void Act() => ChineseRemainderTheorem.Compute(new List<BigInteger> { a }, new List<BigInteger> { new BigInteger(3) });\n\n            // Assert\n            _ = Assert.Throws<ArgumentException>(Act);\n        }\n    }\n\n    [Test]\n    public static void TestCompute_BigInteger_RequirementsNotMet_NNotCoprime()\n    {\n        foreach (var n in new List<BigInteger> { new BigInteger(3), new BigInteger(9), new BigInteger(15), new BigInteger(27) })\n        {\n            // Act\n            void Act() => ChineseRemainderTheorem.Compute(\n                new List<BigInteger> { BigInteger.One, BigInteger.One, BigInteger.One, BigInteger.One, BigInteger.One },\n                new List<BigInteger> { new BigInteger(2), new BigInteger(3), new BigInteger(5), new BigInteger(7), n }\n            );\n\n            // Assert\n            _ = Assert.Throws<ArgumentException>(Act);\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/ModularArithmetic/ExtendedEuclideanAlgorithmTest.cs",
    "content": "using Algorithms.ModularArithmetic;\n\nnamespace Algorithms.Tests.ModularArithmetic;\n\npublic static class ExtendedEuclideanAlgorithmTest\n{\n    [TestCase(240, 46, 2, -9, 47)]\n    [TestCase(46, 240, 2, 47, -9)]\n    [TestCase(2, 3, 1, -1, 1)]\n    [TestCase(1, 1, 1, 0, 1)]\n    [TestCase(13, 17, 1, 4, -3)]\n    [TestCase(0, 17, 17, 0, 1)]\n    [TestCase(17, 0, 17, 1, 0)]\n    [TestCase(17, 17, 17, 0, 1)]\n    [TestCase(2 * 17, 17, 17, 0, 1)]\n    [TestCase(0, 0, 0, 1, 0)]\n    [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13, -1, 1)]\n    public static void TestCompute(long a, long b, long expectedGCD, long expectedBezoutOfA, long expectedBezoutOfB)\n    {\n        // Act\n        var eeaResult = ExtendedEuclideanAlgorithm.Compute(a, b);\n\n        // Assert\n        Assert.That(eeaResult.Gcd, Is.EqualTo(expectedGCD));\n        Assert.That(eeaResult.BezoutA, Is.EqualTo(expectedBezoutOfA));\n        Assert.That(eeaResult.BezoutB, Is.EqualTo(expectedBezoutOfB));\n    }\n\n    [TestCase(240, 46, 2, -9, 47)]\n    [TestCase(46, 240, 2, 47, -9)]\n    [TestCase(2, 3, 1, -1, 1)]\n    [TestCase(1, 1, 1, 0, 1)]\n    [TestCase(13, 17, 1, 4, -3)]\n    [TestCase(0, 17, 17, 0, 1)]\n    [TestCase(17, 0, 17, 1, 0)]\n    [TestCase(17, 17, 17, 0, 1)]\n    [TestCase(2 * 17, 17, 17, 0, 1)]\n    [TestCase(0, 0, 0, 1, 0)]\n    [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13, -1, 1)]\n    public static void TestCompute_BigInteger(long a, long b, long expectedGCD, long expectedBezoutOfA, long expectedBezoutOfB)\n    {\n        // Act\n        var eeaResult = ExtendedEuclideanAlgorithm.Compute(new BigInteger(a), new BigInteger(b));\n\n        // Assert\n        Assert.That(eeaResult.Gcd, Is.EqualTo(new BigInteger(expectedGCD)));\n        Assert.That(eeaResult.BezoutA, Is.EqualTo(new BigInteger(expectedBezoutOfA)));\n        Assert.That(eeaResult.BezoutB, Is.EqualTo(new BigInteger(expectedBezoutOfB)));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/ModularArithmetic/ModularMultiplicativeInverseTest.cs",
    "content": "using Algorithms.ModularArithmetic;\n\nnamespace Algorithms.Tests.ModularArithmetic;\n\npublic static class ModularMultiplicativeInverseTest\n{\n    [TestCase(2, 3, 2)]\n    [TestCase(1, 1, 0)]\n    [TestCase(13, 17, 4)]\n    public static void TestCompute(long a, long n, long expected)\n    {\n        // Act\n        var inverse = ModularMultiplicativeInverse.Compute(a, n);\n\n        // Assert\n        Assert.That(inverse, Is.EqualTo(expected));\n    }\n\n    [TestCase(46, 240)]\n    [TestCase(0, 17)]\n    [TestCase(17, 0)]\n    [TestCase(17, 17)]\n    [TestCase(0, 0)]\n    [TestCase(2 * 13 * 17, 4 * 9 * 13)]\n    public static void TestCompute_Irrevertible(long a, long n)\n    {\n        // Act\n        void Act() => ModularMultiplicativeInverse.Compute(a, n);\n\n        // Assert\n        _ = Assert.Throws<ArithmeticException>(Act);\n    }\n\n    [TestCase(2, 3, 2)]\n    [TestCase(1, 1, 0)]\n    [TestCase(13, 17, 4)]\n    public static void TestCompute_BigInteger(long a, long n, long expected)\n    {\n        // Act\n        var inverse = ModularMultiplicativeInverse.Compute(new BigInteger(a), new BigInteger(n));\n\n        // Assert\n        Assert.That(inverse, Is.EqualTo(new BigInteger(expected)));\n    }\n\n    [TestCase(46, 240)]\n    [TestCase(0, 17)]\n    [TestCase(17, 0)]\n    [TestCase(17, 17)]\n    [TestCase(0, 0)]\n    [TestCase(2 * 13 * 17, 4 * 9 * 13)]\n    public static void TestCompute_BigInteger_Irrevertible(long a, long n)\n    {\n        // Act\n        void Act() => ModularMultiplicativeInverse.Compute(new BigInteger(a), new BigInteger(n));\n\n        // Assert\n        _ = Assert.Throws<ArithmeticException>(Act);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/AbsTests.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class AbsTests\n{\n    [TestCase(0, 0)]\n    [TestCase(34, 34)]\n    [TestCase(-100000000000.0d, 100000000000.0d)]\n    [TestCase(-3, 3)]\n    [TestCase(-3.1443123d, 3.1443123d)]\n    public static void GetsAbsVal<T>(T inputNum, T expected) where T : INumber<T>\n    {\n        // Act\n        var result = Abs.AbsVal(inputNum);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected));\n    }\n\n    [TestCase(new[] { -3, -1, 2, -11 }, -11)]\n    [TestCase(new[] { 0, 5, 1, 11 }, 11)]\n    [TestCase(new[] { 3.0, -10.0, -2.0 }, -10.0d)]\n    public static void GetAbsMax<T>(T[] inputNums, T expected) where T : INumber<T>\n    {\n        // Act\n        var result = Abs.AbsMax(inputNums);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected));\n    }\n\n    [Test]\n    public static void AbsMaxThrowsArgumentException()\n    {\n        // Arrange\n        var inputNums = Array.Empty<int>();\n\n        // Assert\n        Assert.Throws<ArgumentException>(() => Abs.AbsMax(inputNums));\n    }\n\n    [TestCase(new[] { -3, -1, 2, -11 }, -1)]\n    [TestCase(new[] { -3, -5, 1, -11 }, 1)]\n    [TestCase(new[] { 0, 5, 1, 11 }, 0)]\n    public static void GetAbsMin<T>(T[] inputNums, T expected) where T : INumber<T>\n    {\n        // Act\n        var result = Abs.AbsMin(inputNums);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected));\n    }\n\n    [Test]\n    public static void AbsMinThrowsArgumentException()\n    {\n        // Arrange\n        var inputNums = Array.Empty<int>();\n\n        // Assert\n        Assert.Throws<ArgumentException>(() => Abs.AbsMin(inputNums));\n    }\n}"
  },
  {
    "path": "Algorithms.Tests/Numeric/AdditionWithoutArithmeticsTests.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class AdditionWithoutArithmeticTests\n{\n    [TestCase(3, 5, 8)]\n    [TestCase(13, 5, 18)]\n    [TestCase(-7, 2, -5)]\n    [TestCase(0, -7, -7)]\n    [TestCase(-321, 0, -321)]\n    public static void CalculateAdditionWithoutArithmetic_Test(int first, int second, int expectedResult)\n    {\n        // Act\n        var result = AdditionWithoutArithmetic.CalculateAdditionWithoutArithmetic(first, second);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expectedResult));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/AliquotSumCalculatorTests.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class AliquotSumCalculatorTests\n{\n    [TestCase(1, 0)]\n    [TestCase(3, 1)]\n    [TestCase(25, 6)]\n    [TestCase(99, 57)]\n    public static void CalculateSum_SumIsCorrect(int number, int expectedSum)\n    {\n        // Arrange\n\n        // Act\n        var result = AliquotSumCalculator.CalculateAliquotSum(number);\n\n        // Assert\n        result.Should().Be(expectedSum);\n    }\n\n    [TestCase(-2)]\n    public static void CalculateSum_NegativeInput_ExceptionIsThrown(int number)\n    {\n        // Arrange\n        Action act = () => AliquotSumCalculator.CalculateAliquotSum(number);\n\n        // Assert\n        act.Should().Throw<ArgumentException>();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/AmicableNumbersTest.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class AmicableNumbersTest\n{\n    [TestCase(220, 284)]\n    [TestCase(1184, 1210)]\n    [TestCase(2620, 2924)]\n    [TestCase(5020, 5564)]\n    public static void AmicableNumbersChecker_Test(int x, int y)\n    {\n        // Arrange\n\n        // Act\n        var result = AmicableNumbersChecker.AreAmicableNumbers(x, y);\n\n        // Assert\n        Assert.That(result, Is.True);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/AutomorphicNumberTests.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic class AutomorphicNumberTests\n{\n    [TestCase(1)]\n    [TestCase(5)]\n    [TestCase(6)]\n    [TestCase(25)]\n    [TestCase(76)]\n    [TestCase(376)]\n    [TestCase(625)]\n    [TestCase(9376)]\n    [TestCase(90625)]\n    [TestCase(109376)]\n\n    public void TestAutomorphicNumbers(int number)\n    {\n        Assert.That(AutomorphicNumber.IsAutomorphic(number), Is.True);\n    }\n\n    [TestCase(2)]\n    [TestCase(3)]\n    [TestCase(7)]\n    [TestCase(18)]\n    [TestCase(79)]\n    [TestCase(356)]\n    [TestCase(623)]\n    [TestCase(9876)]\n    [TestCase(90635)]\n    [TestCase(119376)]\n    [TestCase(891625)]\n    [TestCase(2990625)]\n    [TestCase(7209376)]\n    [TestCase(12891625)]\n    [TestCase(87129396)]\n    public void TestNonAutomorphicNumbers(int number)\n    {\n        Assert.That(AutomorphicNumber.IsAutomorphic(number), Is.False);\n    }\n\n    [TestCase(0)]\n    [TestCase(-1)]\n    public void TestInvalidAutomorphicNumbers(int number)\n    {\n        Assert.Throws(Is.TypeOf<ArgumentException>()\n            .And.Message.EqualTo($\"An automorphic number must always be positive.\"),\n            delegate\n            {\n                AutomorphicNumber.IsAutomorphic(number);\n            });\n    }\n\n    [TestCase(1, 100)]\n    public void TestAutomorphicNumberSequence(int lower, int upper)\n    {\n        List<long> automorphicList = [1, 5, 6, 25, 76];\n        Assert.That(AutomorphicNumber.GetAutomorphicNumbers(lower, upper), Is.EqualTo(automorphicList));\n    }\n\n    [TestCase(8, 12)]\n    public void TestNoAutomorphicNumberInTheSequence(int lower, int upper)\n    {\n        List<long> automorphicList = [];\n        Assert.That(AutomorphicNumber.GetAutomorphicNumbers(lower, upper), Is.EqualTo(automorphicList));\n    }\n\n    [TestCase(25, 25)]\n    public void TestAutomorphicNumberSequenceSameBounds(int lower, int upper)\n    {\n        List<long> automorphicList = [25];\n        Assert.That(AutomorphicNumber.GetAutomorphicNumbers(lower, upper), Is.EqualTo(automorphicList));\n    }\n\n    [TestCase(-1, 1)]\n    [TestCase(0, 1)]\n    public void TestAutomorphicNumberSequenceInvalidLowerBound(int lower, int upper)\n    {\n        Assert.Throws(Is.TypeOf<ArgumentException>()\n            .And.Message.EqualTo($\"Lower bound must be greater than 0.\"),\n            delegate\n            {\n                AutomorphicNumber.GetAutomorphicNumbers(lower, upper);\n            });\n    }\n\n    [TestCase(1, -1)]\n    [TestCase(10, -1)]\n    public void TestAutomorphicNumberSequenceInvalidUpperBound(int lower, int upper)\n    {\n        Assert.Throws(Is.TypeOf<ArgumentException>()\n            .And.Message.EqualTo($\"Upper bound must be greater than 0.\"),\n            delegate\n            {\n                AutomorphicNumber.GetAutomorphicNumbers(lower, upper);\n            });\n    }\n\n    [TestCase(25, 2)]\n    public void TestAutomorphicNumberSequenceReversedBounds(int lower, int upper)\n    {\n        Assert.Throws(Is.TypeOf<ArgumentException>()\n            .And.Message.EqualTo($\"The lower bound must be less than or equal to the upper bound.\"),\n            delegate\n            {\n                AutomorphicNumber.GetAutomorphicNumbers(lower, upper);\n            });\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/BinomialCoefficientTests.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class BinomialCoefficientTests\n{\n    [TestCase(4, 2, 6)]\n    [TestCase(7, 3, 35)]\n    public static void CalculateFromPairs(int n, int k, int expected)\n    {\n        // Arrange\n\n        // Act\n        var result = BinomialCoefficient.Calculate(new BigInteger(n), new BigInteger(k));\n\n        // Assert\n        Assert.That(result, Is.EqualTo(new BigInteger(expected)));\n    }\n\n    [TestCase(3, 7)]\n    public static void TeoremCalculateThrowsException(int n, int k)\n    {\n        // Arrange\n\n        // Act\n\n        // Assert\n        _ = Assert.Throws<ArgumentException>(() => BinomialCoefficient.Calculate(new BigInteger(n), new BigInteger(k)));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/CeilTests.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class CeilTests\n{\n    [TestCase(0.0, 0)]\n    [TestCase(1.1, 2)]\n    [TestCase(1.9, 2)]\n    [TestCase(1.0, 1)]\n    [TestCase(-1.1, -1)]\n    [TestCase(-1.9, -1)]\n    [TestCase(-1.0, -1)]\n    [TestCase(1000000000.1, 1000000001)]\n    [TestCase(1, 1)]\n    public static void GetsCeilVal<T>(T inputNum, T expected) where T : INumber<T>\n    {\n        // Act\n        var result = Ceil.CeilVal(inputNum);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected));\n    }\n}"
  },
  {
    "path": "Algorithms.Tests/Numeric/Decomposition/LUTests.cs",
    "content": "using Algorithms.Numeric.Decomposition;\n\nnamespace Algorithms.Tests.Numeric.Decomposition;\n\npublic class LuTests\n{\n    private readonly double epsilon = Math.Pow(10, -6);\n\n    [Test]\n    public void DecomposeIdentityMatrix()\n    {\n        // Arrange\n        var identityMatrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };\n        var expectedLower = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };\n        var expectedUpper = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };\n\n        // Act\n        (double[,] lower, double[,] upper) = Lu.Decompose(identityMatrix);\n\n        // Assert\n        Assert.That(lower, Is.EqualTo(expectedLower));\n        Assert.That(upper, Is.EqualTo(expectedUpper));\n        Assert.That(identityMatrix, Is.EqualTo(lower.Multiply(upper)));\n    }\n\n    [Test]\n    public void DecomposeMatrix_Case3X3()\n    {\n        // Arrange\n        var source = new double[,] { { 2, 1, 4 }, { 7, 1, 1 }, { 4, 2, 9 } };\n        var expectedLower = new[,] { { 1, 0, 0 }, { 3.5, 1, 0 }, { 2, 0, 1 } };\n        var expectedUpper = new[,] { { 2, 1, 4 }, { 0, -2.5, -13 }, { 0, 0, 1 } };\n\n        // Act\n        (double[,] lower, double[,] upper) = Lu.Decompose(source);\n\n        // Assert\n        Assert.That(lower, Is.EqualTo(expectedLower));\n        Assert.That(upper, Is.EqualTo(expectedUpper));\n        Assert.That(source, Is.EqualTo(lower.Multiply(upper)));\n    }\n\n    [Test]\n    public void DecomposeMatrix_Case4X4()\n    {\n        // Arrange\n        var source = new[,] { { 1, 2, 4.5, 7 }, { 3, 8, 0.5, 2 }, { 2, 6, 4, 1.5 }, { 4, 14, 2, 10.5 } };\n        var expectedLower = new[,] { { 1, 0, 0, 0 }, { 3, 1, 0, 0 }, { 2, 1, 1, 0 }, { 4, 3, 2.875, 1 } };\n        var expectedUpper = new[,] { { 1, 2, 4.5, 7 }, { 0, 2, -13, -19 }, { 0, 0, 8, 6.5 }, { 0, 0, 0, 20.8125 } };\n\n        // Act\n        (double[,] lower, double[,] upper) = Lu.Decompose(source);\n\n        // Assert\n        Assert.That(lower, Is.EqualTo(expectedLower));\n        Assert.That(upper, Is.EqualTo(expectedUpper));\n        Assert.That(source, Is.EqualTo(lower.Multiply(upper)));\n    }\n\n    [Test]\n    public void FailOnDecomposeNonSquareMatrix()\n    {\n        // Arrange\n        var nonSquareMatrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 0, 0, 0 } };\n\n        // Act\n        void Act(double[,] source) => Lu.Decompose(source);\n\n        // Assert\n        Assert.Throws<ArgumentException>(() => Act(nonSquareMatrix));\n    }\n\n    [Test]\n    public void EliminateIdentityEquation()\n    {\n        // Arrange\n        var identityMatrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };\n        var coefficients = new double[] { 1, 2, 3 };\n\n        // Act\n        var solution = Lu.Eliminate(identityMatrix, coefficients);\n\n        // Assert\n        Assert.That(solution, Is.EqualTo(coefficients));\n    }\n\n    [Test]\n    public void EliminateEquation_Case3X3()\n    {\n        // Arrange\n        var source = new double[,] { { 2, 1, -1 }, { -3, -1, 2 }, { -2, 1, 2 } };\n        var coefficients = new double[] { 8, -11, -3 };\n        var expectedSolution = new double[] { 2, 3, -1 };\n\n        // Act\n        var solution = Lu.Eliminate(source, coefficients);\n\n        // Assert\n        Assert.That(VectorMembersAreEqual(expectedSolution, solution), Is.True);\n    }\n\n    [Test]\n    public void EliminateEquation_Case4X4()\n    {\n        // Arrange\n        var source = new[,]\n        {\n            { 1.0, 2.0, -3.0, -1.0 },\n            { 0.0, -3.0, 2.0, 6.0 },\n            { 0.0, 5.0, -6.0, -2.0 },\n            { 0.0, -1.0, 8.0, 1.0 },\n        };\n        var coefficients = new[] { 0.0, -8.0, 0.0, -8.0 };\n        var expectedSolution = new[] { -1.0, -2.0, -1.0, -2.0 };\n\n        // Act\n        var solution = Lu.Eliminate(source, coefficients);\n\n        // Assert\n        Assert.That(VectorMembersAreEqual(expectedSolution, solution), Is.True);\n    }\n\n    [Test]\n    public void FailOnEliminateEquationWithNonSquareMatrix()\n    {\n        // Arrange\n        var nonSquareMatrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 0, 0, 0 } };\n        var coefficients = new double[] { 1, 2, 3, 4 };\n\n        // Act\n        void Act(double[,] source, double[] c) => Lu.Eliminate(source, c);\n\n        // Assert\n        Assert.Throws<ArgumentException>(() => Act(nonSquareMatrix, coefficients));\n    }\n\n    private bool VectorMembersAreEqual(double[] expected, double[] actual) =>\n        expected\n            .Zip(actual, (e, a) => new { Expected = e, Actual = a })\n            .All(pair => Math.Abs(pair.Expected - pair.Actual) < epsilon);\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/Decomposition/MaclaurinTests.cs",
    "content": "using Algorithms.Numeric.Series;\n\nnamespace Algorithms.Tests.Numeric.Decomposition;\n\npublic class MaclaurinTests\n{\n    [TestCase(0.01, 3, 0.01)]\n    [TestCase(1, 7, 0.001)]\n    [TestCase(-1.2, 7, 0.001)]\n    public void Exp_TermsForm_ValidCases(double point, int terms, double expectedError)\n    {\n        // Arrange\n        var expected = Math.Exp(point);\n\n        // Act\n        var actual = Maclaurin.Exp(point, terms);\n\n        // Assert\n        Assert.That(Math.Abs(expected - actual) < expectedError, Is.True);\n    }\n\n    [Test]\n    public void Exp_TermsForm_InvalidCase() =>\n        Assert.Throws<ArgumentOutOfRangeException>(() => Maclaurin.Exp(0, -1));\n\n    [TestCase(0, 1, 0.001)]\n    [TestCase(1, 7, 0.001)]\n    [TestCase(1.57, 7, 0.001)]\n    [TestCase(3.14, 7, 0.001)]\n    public void Sin_TermsForm_ValidCases(double point, int terms, double expectedError)\n    {\n        // Arrange\n        var expected = Math.Sin(point);\n\n        // Act\n        var actual = Maclaurin.Sin(point, terms);\n\n        // Assert\n        Assert.That(Math.Abs(expected - actual) < expectedError, Is.True);\n    }\n\n    [Test]\n    public void Sin_TermsForm_InvalidCase() =>\n        Assert.Throws<ArgumentOutOfRangeException>(() => Maclaurin.Sin(0, -1));\n\n    [TestCase(0, 1, 0.001)]\n    [TestCase(1, 7, 0.001)]\n    [TestCase(1.57, 7, 0.001)]\n    [TestCase(3.14, 7, 0.001)]\n    public void Cos_TermsForm_ValidCases(double point, int terms, double expectedError)\n    {\n        // Arrange\n        var expected = Math.Cos(point);\n\n        // Act\n        var actual = Maclaurin.Cos(point, terms);\n\n        // Assert\n        Assert.That(Math.Abs(expected - actual) < expectedError, Is.True);\n    }\n\n    [Test]\n    public void Cos_TermsForm_InvalidCase() =>\n        Assert.Throws<ArgumentOutOfRangeException>(() => Maclaurin.Cos(0, -1));\n\n    [TestCase(0.1, 0.001)]\n    [TestCase(0.1, 0.00001)]\n    [TestCase(2.1, 0.001)]\n    [TestCase(-1.2, 0.001)]\n    public void Exp_ErrorForm_ValidCases(double point, double error)\n    {\n        // Arrange\n        var expected = Math.Exp(point);\n\n        // Act\n        var actual = Maclaurin.Exp(point, error);\n\n        // Assert\n        Assert.That(Math.Abs(expected - actual) < error, Is.True);\n    }\n\n    [TestCase(0.0)]\n    [TestCase(1.0)]\n    public void Exp_ErrorForm_InvalidCases(double error) =>\n        Assert.Throws<ArgumentException>(() => Maclaurin.Exp(0.0, error));\n\n    [TestCase(0, 0.001)]\n    [TestCase(1, 0.00001)]\n    [TestCase(1.57, 0.0001)]\n    [TestCase(3.14, 0.0001)]\n    public void Sin_ErrorForm_ValidCases(double point, double error)\n    {\n        // Arrange\n        var expected = Math.Sin(point);\n\n        // Act\n        var actual = Maclaurin.Sin(point, error);\n\n        // Assert\n        Assert.That(Math.Abs(expected - actual) < error, Is.True);\n    }\n\n    [TestCase(0.0)]\n    [TestCase(1.0)]\n    public void Sin_ErrorForm_InvalidCases(double error) =>\n        Assert.Throws<ArgumentException>(() => Maclaurin.Sin(0.0, error));\n\n    [TestCase(0, 0.001)]\n    [TestCase(1, 0.00001)]\n    [TestCase(1.57, 0.0001)]\n    [TestCase(3.14, 0.0001)]\n    public void Cos_ErrorForm_ValidCases(double point, double error)\n    {\n        // Arrange\n        var expected = Math.Cos(point);\n\n        // Act\n        var actual = Maclaurin.Cos(point, error);\n\n        // Assert\n        Assert.That(Math.Abs(expected - actual) < error, Is.True);\n    }\n\n    [TestCase(0.0)]\n    [TestCase(1.0)]\n    public void Cos_ErrorForm_InvalidCases(double error) =>\n        Assert.Throws<ArgumentException>(() => Maclaurin.Cos(0.0, error));\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/Decomposition/SVDTests.cs",
    "content": "using Algorithms.Numeric.Decomposition;\n\nnamespace Algorithms.Tests.Numeric.Decomposition;\n\npublic class SvdTests\n{\n    [Test]\n    public void RandomUnitVector()\n    {\n        var epsilon = 0.0001;\n        // unit vector should have length 1\n        ThinSvd.RandomUnitVector(10).Magnitude().Should().BeApproximately(1, epsilon);\n        // unit vector with single element should be [-1] or [+1]\n        Math.Abs(ThinSvd.RandomUnitVector(1)[0]).Should().BeApproximately(1, epsilon);\n        // two randomly generated unit vectors should not be equal \n        ThinSvd.RandomUnitVector(10).Should().NotBeEquivalentTo(ThinSvd.RandomUnitVector(10));\n    }\n\n    [Test]\n    public void Svd_Decompose()\n    {\n        CheckSvd(new double[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } });\n        CheckSvd(new double[,] { { 1, 2, 3 }, { 4, 5, 6 } });\n        CheckSvd(new double[,] { { 1, 0, 0, 0, 2 }, { 0, 3, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 2, 0, 0, 0 } });\n    }\n\n    [Test]\n    public void Svd_Random([Random(3, 10, 5)] int m, [Random(3, 10, 5)] int n)\n    {\n        double[,] matrix = GenerateRandomMatrix(m, n);\n        CheckSvd(matrix);\n    }\n\n    private void AssertMatrixEqual(double[,] matrix1, double[,] matrix2, double epsilon)\n    {\n        matrix1.GetLength(0).Should().Be(matrix2.GetLength(0));\n        matrix1.GetLength(1).Should().Be(matrix2.GetLength(1));\n        for (var i = 0; i < matrix1.GetLength(0); i++)\n        {\n            for (var j = 0; j < matrix1.GetLength(1); j++)\n            {\n                Assert.That(matrix1[i, j], Is.EqualTo(matrix2[i, j]).Within(epsilon), $\"At index ({i}, {j})\");\n            }\n        }\n    }\n\n    private double[,] GenerateRandomMatrix(int m, int n)\n    {\n        double[,] result = new double[m, n];\n        Random random = new();\n        for (var i = 0; i < m; i++)\n        {\n            for (var j = 0; j < n; j++)\n            {\n                result[i, j] = random.NextDouble() - 0.5;\n            }\n        }\n\n        return result;\n    }\n\n    private void CheckSvd(double[,] testMatrix)\n    {\n        var epsilon = 1E-6;\n        double[,] u;\n        double[,] v;\n        double[] s;\n        (u, s, v) = ThinSvd.Decompose(testMatrix, 1e-6 * epsilon, 1000);\n\n        for (var i = 1; i < s.Length; i++)\n        {\n            // singular values should be arranged from greatest to smallest\n            // but there are rounding errors\n            (s[i] - s[i - 1]).Should().BeLessThan(1);\n        }\n\n        for (var i = 0; i < u.GetLength(1); i++)\n        {\n            double[] extracted = new double[u.GetLength(0)];\n            // extract a column of u\n            for (var j = 0; j < extracted.Length; j++)\n            {\n                extracted[j] = u[j, i];\n            }\n\n            if (s[i] > epsilon)\n            {\n                // if the singular value is non-zero, then the basis vector in u should be a unit vector\n                extracted.Magnitude().Should().BeApproximately(1, epsilon);\n            }\n            else\n            {\n                // if the singular value is zero, then the basis vector in u should be zeroed out\n                extracted.Magnitude().Should().BeApproximately(0, epsilon);\n            }\n        }\n\n        for (var i = 0; i < v.GetLength(1); i++)\n        {\n            double[] extracted = new double[v.GetLength(0)];\n            // extract column of v\n            for (var j = 0; j < extracted.Length; j++)\n            {\n                extracted[j] = v[j, i];\n            }\n\n            if (s[i] > epsilon)\n            {\n                // if the singular value is non-zero, then the basis vector in v should be a unit vector\n                Assert.That(extracted.Magnitude(), Is.EqualTo(1).Within(epsilon));\n            }\n            else\n            {\n                // if the singular value is zero, then the basis vector in v should be zeroed out\n                Assert.That(extracted.Magnitude(), Is.EqualTo(0).Within(epsilon));\n            }\n        }\n\n        // convert singular values to a diagonal matrix\n        double[,] expanded = new double[s.Length, s.Length];\n        for (var i = 0; i < s.Length; i++)\n        {\n            expanded[i, i] = s[i];\n        }\n\n\n        // matrix = U * S * V^t, definition of Singular Vector Decomposition\n        AssertMatrixEqual(testMatrix, u.Multiply(expanded).Multiply(v.Transpose()), epsilon);\n        AssertMatrixEqual(testMatrix, u.Multiply(expanded.Multiply(v.Transpose())), epsilon);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/DoubleFactorialTests.cs",
    "content": "using System.Numerics;\nusing Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\n/// <summary>\n/// Tests for the DoubleFactorial class methods.\n/// </summary>\npublic static class DoubleFactorialTests\n{\n    /// <summary>\n    /// Tests the calculation of double factorial for non-negative integers.\n    /// Includes base cases (0, 1), odd numbers (5, 11), even numbers (6, 12), \n    /// and a large number (20) that benefits from BigInteger.\n    /// </summary>\n    /// <param name=\"input\">The number N to calculate N!!.</param>\n    /// <param name=\"expected\">The expected result as a string (for BigInteger parsing).</param>\n    [TestCase(0, \"1\")]     // Base Case: 0!! = 1\n    [TestCase(1, \"1\")]     // Base Case: 1!! = 1\n    [TestCase(5, \"15\")]    // Odd: 5 * 3 * 1 = 15\n    [TestCase(6, \"48\")]    // Even: 6 * 4 * 2 = 48\n    [TestCase(11, \"10395\")]// Larger Odd: 11 * 9 * 7 * 5 * 3 * 1 = 10395\n    [TestCase(12, \"46080\")] // Larger Even: 12 * 10 * 8 * 6 * 4 * 2 = 46080\n    [TestCase(20, \"3715891200\")] // Large Even\n    public static void GetsDoubleFactorial(int input, string expected)\n    {\n        // Arrange\n        BigInteger expectedBigInt = BigInteger.Parse(expected);\n\n        // Act\n        var result = DoubleFactorial.Calculate(input);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expectedBigInt));\n    }\n\n    /// <summary>\n    /// Tests that calculating double factorial for negative numbers throws an ArgumentException.\n    /// </summary>\n    /// <param name=\"num\">A negative integer input.</param>\n    [TestCase(-1)]\n    [TestCase(-5)]\n    [TestCase(-10)]\n    public static void GetsDoubleFactorialExceptionForNegativeNumbers(int num)\n    {\n        // Arrange\n\n        // Act\n        void Act() => DoubleFactorial.Calculate(num);\n\n        // Assert\n        _ = Assert.Throws<ArgumentException>(Act);\n    }\n}"
  },
  {
    "path": "Algorithms.Tests/Numeric/EulerMethodTest.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class EulerMethodTest\n{\n    [Test]\n    public static void TestLinearEquation()\n    {\n        Func<double, double, double> exampleEquation = (x, _) => x;\n        List<double[]> points = EulerMethod.EulerFull(0, 4, 0.001, 0, exampleEquation);\n        var yEnd = points[^1][1];\n        yEnd.Should().BeApproximately(8, 0.01);\n    }\n\n    [Test]\n    public static void TestExampleWikipedia()\n    {\n        // example from https://en.wikipedia.org/wiki/Euler_method\n        Func<double, double, double> exampleEquation = (_, y) => y;\n        List<double[]> points = EulerMethod.EulerFull(0, 4, 0.0125, 1, exampleEquation);\n        var yEnd = points[^1][1];\n        yEnd.Should().BeApproximately(53.26, 0.01);\n    }\n\n    [Test]\n    public static void TestExampleGeeksForGeeks()\n    {\n        // example from https://www.geeksforgeeks.org/euler-method-solving-differential-equation/\n        // Euler method: y_n+1 = y_n + stepSize * f(x_n, y_n)\n        // differential equation: f(x, y) = x + y + x * y\n        // initial conditions: x_0 = 0; y_0 = 1; stepSize = 0.025\n        // solution:\n        //     y_1 = 1 + 0.025 * (0 + 1 + 0 * 1) = 1.025\n        //     y_2 = 1.025 + 0.025 * (0.025 + 1.025 + 0.025 * 1.025) = 1.051890625\n        Func<double, double, double> exampleEquation = (x, y) => x + y + x * y;\n        List<double[]> points = EulerMethod.EulerFull(0, 0.05, 0.025, 1, exampleEquation);\n        var y1 = points[1][1];\n        var y2 = points[2][1];\n        Assert.That(1.025, Is.EqualTo(y1));\n        Assert.That(1.051890625, Is.EqualTo(y2));\n    }\n\n    [Test]\n    public static void StepsizeIsZeroOrNegative_ThrowsArgumentOutOfRangeException()\n    {\n        Func<double, double, double> exampleEquation = (x, _) => x;\n        Assert.Throws<ArgumentOutOfRangeException>(() => EulerMethod.EulerFull(0, 4, 0, 0, exampleEquation));\n    }\n\n    [Test]\n    public static void StartIsLargerThanEnd_ThrowsArgumentOutOfRangeException()\n    {\n        Func<double, double, double> exampleEquation = (x, _) => x;\n        Assert.Throws<ArgumentOutOfRangeException>(() => EulerMethod.EulerFull(0, -4, 0.1, 0, exampleEquation));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/FactorialTests.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class FactorialTests\n{\n    [TestCase(0, \"1\")]\n    [TestCase(1, \"1\")]\n    [TestCase(4, \"24\")]\n    [TestCase(10, \"3628800\")]\n    [TestCase(18, \"6402373705728000\")]\n    public static void GetsFactorial(int input, string expected)\n    {\n        // Arrange\n        BigInteger expectedBigInt = BigInteger.Parse(expected);\n\n        // Act\n        var result = Factorial.Calculate(input);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expectedBigInt));\n    }\n\n    [TestCase(-5)]\n    [TestCase(-10)]\n    public static void GetsFactorialExceptionForNegativeNumbers(int num)\n    {\n        // Arrange\n\n        // Act\n        void Act() => Factorial.Calculate(num);\n\n        // Assert\n        _ = Assert.Throws<ArgumentException>(Act);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/Factorization/TrialDivisionFactorizerTests.cs",
    "content": "using Algorithms.Numeric.Factorization;\n\nnamespace Algorithms.Tests.Numeric.Factorization;\n\npublic static class TrialDivisionFactorizerTests\n{\n    [TestCase(2)]\n    [TestCase(3)]\n    [TestCase(29)]\n    [TestCase(31)]\n    public static void PrimeNumberFactorizationFails(int p)\n    {\n        // Arrange\n        var factorizer = new TrialDivisionFactorizer();\n\n        // Act\n        var success = factorizer.TryFactor(p, out _);\n\n        // Assert\n        Assert.That(success, Is.False);\n    }\n\n    [TestCase(4, 2)]\n    [TestCase(6, 2)]\n    [TestCase(8, 2)]\n    [TestCase(9, 3)]\n    [TestCase(15, 3)]\n    [TestCase(35, 5)]\n    [TestCase(49, 7)]\n    [TestCase(77, 7)]\n    public static void PrimeNumberFactorizationSucceeds(int n, int expected)\n    {\n        // Arrange\n        var factorizer = new TrialDivisionFactorizer();\n\n        // Act\n        var success = factorizer.TryFactor(n, out var factor);\n\n        // Assert\n        Assert.That(success, Is.True);\n        Assert.That(factor, Is.EqualTo(expected));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/FloorTests.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class FloorTests\n{\n    [TestCase(0.0, 0)]\n    [TestCase(1.1, 1)]\n    [TestCase(1.9, 1)]\n    [TestCase(1.0, 1)]\n    [TestCase(-1.1, -2)]\n    [TestCase(-1.9, -2)]\n    [TestCase(-1.0, -1)]\n    [TestCase(1000000000.1, 1000000000)]\n    [TestCase(1, 1)]\n    public static void GetsFloorVal<T>(T inputNum, T expected) where T : INumber<T>\n    {\n        // Act\n        var result = Floor.FloorVal(inputNum);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected));\n    }\n}"
  },
  {
    "path": "Algorithms.Tests/Numeric/GaussJordanEliminationTests.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\n/// <summary>\n///     Class for testing Gauss-Jordan Elimination Algorithm.\n/// </summary>\npublic static class GaussJordanEliminationTests\n{\n    [Test]\n    public static void NonSquaredMatrixThrowsException()\n    {\n        // Arrange\n        var solver = new GaussJordanElimination();\n        var input = new double[,] { { 2, -1, 5 }, { 0, 2, 1 }, { 3, 17, 7 } };\n\n        // Act\n        void Act() => solver.Solve(input);\n\n        // Assert\n        _ = Assert.Throws<ArgumentException>(Act);\n    }\n\n    [Test]\n    public static void UnableToSolveSingularMatrix()\n    {\n        // Arrange\n        var solver = new GaussJordanElimination();\n        var input = new double[,] { { 0, 0, 0 }, { 0, 0, 0 } };\n\n        // Act\n        var result = solver.Solve(input);\n\n        // Assert\n        Assert.That(result, Is.False);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinderTests.cs",
    "content": "using Algorithms.Numeric.GreatestCommonDivisor;\n\nnamespace Algorithms.Tests.Numeric.GreatestCommonDivisor;\n\npublic static class BinaryGreatestCommonDivisorFinderTests\n{\n    [TestCase(2, 3, 1)]\n    [TestCase(1, 1, 1)]\n    [TestCase(13, 17, 1)]\n    [TestCase(0, 17, 17)]\n    [TestCase(17, 0, 17)]\n    [TestCase(17, 17, 17)]\n    [TestCase(2 * 17, 17, 17)]\n    [TestCase(0, 0, 0)]\n    [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13)]\n    public static void GreatestCommonDivisorCorrect(int a, int b, int expectedGcd)\n    {\n        // Arrange\n        var gcdFinder = new BinaryGreatestCommonDivisorFinder();\n\n        // Act\n        var actualGcd = gcdFinder.FindGcd(a, b);\n\n        // Assert\n        Assert.That(actualGcd, Is.EqualTo(expectedGcd));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinderTests.cs",
    "content": "using Algorithms.Numeric.GreatestCommonDivisor;\n\nnamespace Algorithms.Tests.Numeric.GreatestCommonDivisor;\n\npublic static class EuclideanGreatestCommonDivisorFinderTests\n{\n    [TestCase(2, 3, 1)]\n    [TestCase(1, 1, 1)]\n    [TestCase(13, 17, 1)]\n    [TestCase(0, 17, 17)]\n    [TestCase(17, 0, 17)]\n    [TestCase(17, 17, 17)]\n    [TestCase(2 * 17, 17, 17)]\n    [TestCase(0, 0, int.MaxValue)]\n    [TestCase(2 * 13 * 17, 4 * 9 * 13, 2 * 13)]\n    public static void GreatestCommonDivisorCorrect(int a, int b, int expectedGcd)\n    {\n        // Arrange\n        var gcdFinder = new EuclideanGreatestCommonDivisorFinder();\n\n        // Act\n        var actualGcd = gcdFinder.FindGcd(a, b);\n\n        // Assert\n        Assert.That(actualGcd, Is.EqualTo(expectedGcd));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/JosephusProblemTest.cs",
    "content": "﻿using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic class JosephusProblemTest\n{\n\n    [TestCase(10, 0)]\n    [TestCase(10, -1)]\n    public void JosephusProblemInvalidStepSize(long groupSize, long step)\n    {\n        Assert.Throws(Is.TypeOf<ArgumentException>()\n                .And.Message.EqualTo(\"The step cannot be smaller than 1\"),\n            delegate { JosephusProblem.FindWinner(groupSize, step); });\n    }\n\n    [TestCase(10, 12)]\n    public void JosephusProblemStepSizeGreaterThanGroup(long groupSize, long step)\n    {\n        Assert.Throws(Is.TypeOf<ArgumentException>()\n                .And.Message.EqualTo(\"The step cannot be greater than the size of the group\"),\n            delegate { JosephusProblem.FindWinner(groupSize, step); });\n    }\n\n    [TestCase(10, 2, 5)]\n    [TestCase(10, 8, 1)]\n    [TestCase(254, 18, 92)]\n    [TestCase(3948, 614, 2160)]\n    [TestCase(86521, 65903, 29473)]\n    public void JosephusProblemWinnerCalculation(long groupSize, long step, long position)\n    {\n        Assert.That(JosephusProblem.FindWinner(groupSize, step), Is.EqualTo(position));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/KeithNumberTest.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class KeithNumberTest\n{\n    [TestCase(14)]\n    [TestCase(47)]\n    [TestCase(197)]\n    [TestCase(7909)]\n    public static void KeithNumberWork(int number)\n    {\n        // Act\n        var result = KeithNumberChecker.IsKeithNumber(number);\n\n        // Assert\n        Assert.That(result, Is.True);\n    }\n\n    [TestCase(-2)]\n    public static void KeithNumberShouldThrowEx(int number)\n    {\n        // Arrange\n\n        // Assert\n        Assert.Throws<ArgumentException>(() => KeithNumberChecker.IsKeithNumber(number));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/KrishnamurthyNumberCheckerTests.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic class KrishnamurthyNumberCheckerTests\n{\n    [TestCase(1)]\n    [TestCase(2)]\n    [TestCase(145)]\n    [TestCase(40585)]\n    public void KrishnamurthyNumberCheckerKnownNumbers(int number)\n    {\n        var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number);\n        Assert.That(result, Is.True);\n    }\n\n    [TestCase(3)]\n    [TestCase(4)]\n    [TestCase(239847)]\n    [TestCase(12374)]\n    [TestCase(0)]\n    [TestCase(-1)]\n    public void KrishnamurthyNumberCheckerNotKMNumber(int number)\n    {\n        var result = KrishnamurthyNumberChecker.IsKMurthyNumber(number);\n        Assert.That(result, Is.False);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/MillerRabinPrimalityTest.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class MillerRabinPrimalityTest\n{\n    [TestCase(\"7\", ExpectedResult = true)]  // true\n    [TestCase(\"47\", ExpectedResult = true)] // true\n    [TestCase(\"247894109041876714378152933343208766493\", ExpectedResult = true)] // true\n    [TestCase(\"247894109041876714378152933343208766493\", 1, ExpectedResult = true)] // true\n    [TestCase(\"315757551269487563269454472438030700351\", ExpectedResult = true)] // true\n    [TestCase(\"2476099\", 12445, ExpectedResult = false)] // false 19^5\n    // false 247894109041876714378152933343208766493*315757551269487563269454472438030700351\n    [TestCase(\"78274436845194327170519855212507883195883737501141260366253362532531612139043\", ExpectedResult = false)]\n    [Retry(3)]\n    public static bool MillerRabinPrimalityWork(string testcase, int? seed = null)\n    {\n        // Arrange\n        BigInteger number = BigInteger.Parse(testcase);\n\n        // Recommended number of checks' rounds = Log2(number) as BigInteger has no Log2 function we need to convert Log10\n        BigInteger rounds = (BigInteger)(BigInteger.Log10(number) / BigInteger.Log10(2));\n\n        // Act\n        var result = MillerRabinPrimalityChecker.IsProbablyPrimeNumber(number, rounds, seed);\n\n        // Assert\n        return result;\n    }\n\n    [TestCase(\"-2\")]\n    [TestCase(\"0\")]\n    [TestCase(\"3\")]\n    // By the algorithm definition the number which is checked should be more than 3\n    public static void MillerRabinPrimalityShouldThrowEx(string testcase)\n    {\n        // Arrange\n        BigInteger number = BigInteger.Parse(testcase);\n        BigInteger rounds = 1;\n        // Assert\n        Assert.Throws<ArgumentException>(() => MillerRabinPrimalityChecker.IsProbablyPrimeNumber(number, rounds));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/ModularExponentiationTest.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic class ModularExponentiationTest\n{\n    [TestCase(3, 6, 11, 3)]\n    [TestCase(5, 3, 13, 8)]\n    [TestCase(2, 7, 17, 9)]\n    [TestCase(7, 4, 16, 1)]\n    [TestCase(7, 2, 11, 5)]\n    [TestCase(4, 13, 497, 445)]\n    [TestCase(13, 3, 1, 0)]\n    public void ModularExponentiationCorrect(int b, int e, int m, int expectedRes)\n    {\n        var modularExponentiation = new ModularExponentiation();\n        var actualRes = modularExponentiation.ModularPow(b, e, m);\n        actualRes.Should().Be(expectedRes);\n    }\n\n    [TestCase(17, 7, -3)]\n    [TestCase(11, 3, -5)]\n    [TestCase(14, 3, 0)]\n    public void ModularExponentiationNegativeMod(int b, int e, int m)\n    {\n        var modularExponentiation = new ModularExponentiation();\n        Action res = () => modularExponentiation.ModularPow(b, e, m);\n        res.Should().Throw<ArgumentException>()\n        .WithMessage(String.Format(\"{0} is not a positive integer\", m));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/NarcissisticNumberTest.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class NarcissisticNumberTest\n{\n    [TestCase(2, ExpectedResult = true)]\n    [TestCase(3, ExpectedResult = true)]\n    [TestCase(28, ExpectedResult = false)]\n    [TestCase(153, ExpectedResult = true)]\n    [TestCase(170, ExpectedResult = false)]\n    [TestCase(371, ExpectedResult = true)]\n    public static bool NarcissisticNumberWork(int number)\n    {\n        // Arrange\n\n        // Act\n        var result = NarcissisticNumberChecker.IsNarcissistic(number);\n\n        // Assert\n        return result;\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/NewtonSquareRootTests.cs",
    "content": "namespace Algorithms.Tests.Numeric;\n\npublic class NewtonSquareRootTests\n{\n    private static readonly object[] CalculateSquareRootInput =\n    [\n        new object[] {BigInteger.One, BigInteger.One},\n        new object[] {new BigInteger(221295376), new BigInteger(14876)},\n        new object[] {new BigInteger(2530995481), new BigInteger(50309)},\n        new object[] {new BigInteger(3144293476), new BigInteger(56074)},\n        new object[] {new BigInteger(3844992064), new BigInteger(62008)},\n        new object[] {new BigInteger(5301150481), new BigInteger(72809)},\n        new object[] {new BigInteger(5551442064), new BigInteger(74508)},\n        new object[] {new BigInteger(6980435401), new BigInteger(83549)},\n        new object[] {new BigInteger(8036226025), new BigInteger(89645)},\n    ];\n\n    [TestCaseSource(nameof(CalculateSquareRootInput))]\n    public void CalculateSquareRootTest(BigInteger number, BigInteger result)\n    {\n        Assert.That(NewtonSquareRoot.Calculate(number), Is.EqualTo(result));\n    }\n\n    [Test]\n    public void CalculateSquareRootOfZero()\n    {\n        Assert.That(NewtonSquareRoot.Calculate(0), Is.EqualTo(BigInteger.Zero));\n    }\n\n    [Test]\n    public void CalculateSquareRootNegativeNumber()\n    {\n        Assert.Throws(Is.TypeOf<ArgumentException>()\n            .And.Message.EqualTo(\"Cannot calculate the square root of a negative number.\"),\n            delegate\n            {\n                NewtonSquareRoot.Calculate(BigInteger.MinusOne);\n            });\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/PerfectCubeTests.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class PerfectCubeTests\n{\n    [TestCase(-27, ExpectedResult = true)]\n    [TestCase(27, ExpectedResult = true)]\n    [TestCase(4, ExpectedResult = false)]\n    [TestCase(64, ExpectedResult = true)]\n    [TestCase(0, ExpectedResult = true)]\n    [TestCase(1, ExpectedResult = true)]\n    [TestCase(8, ExpectedResult = true)]\n    [TestCase(9, ExpectedResult = false)]\n    public static bool IsPerfectCube_ResultIsCorrect(int number)\n    {\n        // Act\n        var result = PerfectCubeChecker.IsPerfectCube(number);\n\n        // Assert\n        return result;\n    }\n\n    [TestCase(-27, ExpectedResult = true)]\n    [TestCase(27, ExpectedResult = true)]\n    [TestCase(4, ExpectedResult = false)]\n    [TestCase(64, ExpectedResult = true)]\n    [TestCase(0, ExpectedResult = true)]\n    [TestCase(1, ExpectedResult = true)]\n    [TestCase(8, ExpectedResult = true)]\n    [TestCase(9, ExpectedResult = false)]\n    public static bool IsPerfectCubeBinarySearch_ResultIsCorrect(int number)\n    {\n        // Act\n        var result = PerfectCubeChecker.IsPerfectCubeBinarySearch(number);\n\n        // Assert\n        return result;\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/PerfectNumberTest.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class PerfectNumberTests\n{\n    [TestCase(6)]\n    [TestCase(28)]\n    [TestCase(496)]\n    [TestCase(8128)]\n    public static void PerfectNumberWork(int number)\n    {\n        // Arrange\n\n        // Act\n        var result = PerfectNumberChecker.IsPerfectNumber(number);\n\n        // Assert\n        Assert.That(result, Is.True);\n    }\n\n    [TestCase(-2)]\n    public static void PerfectNumberShouldThrowEx(int number)\n    {\n        // Arrange\n\n        // Assert\n        Assert.Throws<ArgumentException>(() => PerfectNumberChecker.IsPerfectNumber(number));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/PerfectSquareTest.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class PerfectSquareTests\n{\n    [TestCase(-4, ExpectedResult = false)]\n    [TestCase(4, ExpectedResult = true)]\n    [TestCase(9, ExpectedResult = true)]\n    [TestCase(10, ExpectedResult = false)]\n    [TestCase(16, ExpectedResult = true)]\n    [TestCase(70, ExpectedResult = false)]\n    [TestCase(81, ExpectedResult = true)]\n    public static bool IsPerfectSquare_ResultIsCorrect(int number)\n    {\n        // Arrange\n\n        // Act\n        var result = PerfectSquareChecker.IsPerfectSquare(number);\n\n        // Assert\n        return result;\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/PrimeNumberTest.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class PrimeNumberTests\n{\n    /// <summary>\n    ///     Tests the PrimeChecker.IsPrime method with various inputs (primes, composites, edge cases)\n    ///     to ensure the result is correct.\n    /// </summary>\n    [TestCase(-5, ExpectedResult = false)] // Negative number\n    [TestCase(0, ExpectedResult = false)] // Zero\n    [TestCase(1, ExpectedResult = false)] // One\n    [TestCase(2, ExpectedResult = true)] // Smallest prime\n    [TestCase(3, ExpectedResult = true)] // Prime\n    [TestCase(4, ExpectedResult = false)] // Composite (2*2)\n    [TestCase(7, ExpectedResult = true)] // Prime\n    [TestCase(9, ExpectedResult = false)] // Composite (3*3)\n    [TestCase(13, ExpectedResult = true)] // Prime\n    [TestCase(15, ExpectedResult = false)] // Composite (3*5)\n    [TestCase(25, ExpectedResult = false)] // Composite (5*5)\n    [TestCase(29, ExpectedResult = true)] // Prime\n    [TestCase(35, ExpectedResult = false)] // Composite (5*7)\n    [TestCase(49, ExpectedResult = false)] // Composite (7*7)\n    [TestCase(97, ExpectedResult = true)] // Larger prime\n    [TestCase(100, ExpectedResult = false)] // Larger composite\n    public static bool IsPrime_ResultIsCorrect(int number)\n    {\n        // Arrange is implicit here\n\n        // Act\n        var result = PrimeChecker.IsPrime(number);\n\n        // Assert\n        return result;\n    }\n}"
  },
  {
    "path": "Algorithms.Tests/Numeric/PseudoInverse/PseudoInverseTests.cs",
    "content": "namespace Algorithms.Tests.Numeric.PseudoInverse;\n\npublic static class PseudoInverseTests\n{\n    [Test]\n    public static void SquaredMatrixInverseWorks()\n    {\n        // Arrange\n        var inMat = new double[,] { { 2, 4, 6 }, { 2, 0, 2 }, { 6, 8, 14 } };\n        var inMatCopy = new double[,] { { 2, 4, 6 }, { 2, 0, 2 }, { 6, 8, 14 } };\n\n        // Act\n        // using AA+A = A\n        var result = Algorithms.Numeric.Pseudoinverse.PseudoInverse.PInv(inMat);\n        var aainva = inMatCopy.Multiply(result).Multiply(inMatCopy);\n\n        var rounded = aainva.RoundToNextInt();\n        var isequal = rounded.IsEqual(inMatCopy);\n        // Assert\n        Assert.That(isequal, Is.True);\n    }\n\n    [Test]\n    public static void NonSquaredMatrixPseudoInverseMatrixWorks()\n    {\n        // Arrange\n        var inMat = new double[,] { { 1, 2, 3, 4 }, { 0, 1, 4, 7 }, { 5, 6, 0, 1 } };\n        var inMatCopy = new double[,] { { 1, 2, 3, 4 }, { 0, 1, 4, 7 }, { 5, 6, 0, 1 } };\n\n        // Act\n        // using (A+)+ = A\n        var result = Algorithms.Numeric.Pseudoinverse.PseudoInverse.PInv(inMat);\n        var result2 = Algorithms.Numeric.Pseudoinverse.PseudoInverse.PInv(result);\n\n        var rounded = result2.RoundToNextInt();\n\n        var isequal = rounded.IsEqual(inMatCopy);\n        // Assert\n        Assert.That(isequal, Is.True);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/ReluTest.cs",
    "content": "using Algorithms.Numeric;\nusing NUnit.Framework;\nusing System;\n\nnamespace Algorithms.Tests.Numeric;\n\n[TestFixture]\npublic static class ReluTests\n{\n    // Tolerance for floating-point comparisons\n    private const double Tolerance = 1e-9;\n\n    // --- SCALAR TESTS (Relu.Compute(double)) ---\n\n    [TestCase(0.0, 0.0)]\n    [TestCase(1.0, 1.0)]\n    [TestCase(-1.0, 0.0)]\n    [TestCase(5.0, 5.0)]\n    [TestCase(-5.0, 0.0)]\n    public static void ReluFunction_Scalar_ReturnsCorrectValue(double input, double expected)\n    {\n        var result = Relu.Compute(input);\n        Assert.That(result, Is.EqualTo(expected).Within(Tolerance));\n    }\n\n    [Test]\n    public static void ReluFunction_Scalar_HandlesLimitsAndNaN()\n    {\n        // Positive infinity stays +Infinity, negative infinity becomes 0, NaN propagates\n        Assert.That(RelUComputePositiveInfinity(), Is.EqualTo(double.PositiveInfinity));\n        Assert.That(RelUComputeNegativeInfinity(), Is.EqualTo(0.0).Within(Tolerance));\n        Assert.That(RelUComputeNaN(), Is.NaN);\n\n        static double RelUComputePositiveInfinity() => Relu.Compute(double.PositiveInfinity);\n        static double RelUComputeNegativeInfinity() => Relu.Compute(double.NegativeInfinity);\n        static double RelUComputeNaN() => Relu.Compute(double.NaN);\n    }\n\n    [TestCase(100.0)]\n    [TestCase(0.0001)]\n    [TestCase(-100.0)]\n    public static void ReluFunction_Scalar_ResultIsNonNegative(double input)\n    {\n        var result = Relu.Compute(input);\n        Assert.That(result, Is.GreaterThanOrEqualTo(0.0));\n    }\n\n    // --- VECTOR TESTS (Relu.Compute(double[])) ---\n\n    [Test]\n    public static void ReluFunction_Vector_ReturnsCorrectValues()\n    {\n        var input = new[] { 0.0, 1.0, -2.0 };\n        var expected = new[] { 0.0, 1.0, 0.0 };\n\n        var result = Relu.Compute(input);\n\n        Assert.That(result, Is.EqualTo(expected).Within(Tolerance));\n    }\n\n    [Test]\n    public static void ReluFunction_Vector_HandlesLimitsAndNaN()\n    {\n        var input = new[] { double.PositiveInfinity, 0.0, double.NaN };\n        var result = Relu.Compute(input);\n\n        Assert.That(result.Length, Is.EqualTo(input.Length));\n        Assert.That(result[0], Is.EqualTo(double.PositiveInfinity));\n        Assert.That(result[1], Is.EqualTo(0.0).Within(Tolerance));\n        Assert.That(result[2], Is.NaN);\n    }\n\n    // --- EXCEPTION TESTS ---\n\n    [Test]\n    public static void ReluFunction_Vector_ThrowsOnNullInput()\n    {\n        double[]? input = null;\n        Assert.Throws<ArgumentNullException>(() => Relu.Compute(input!));\n    }\n\n    [Test]\n    public static void ReluFunction_Vector_ThrowsOnEmptyInput()\n    {\n        var input = Array.Empty<double>();\n        Assert.Throws<ArgumentException>(() => Relu.Compute(input));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/RungeKuttaMethodTest.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class RungeKuttaTest\n{\n    [Test]\n    public static void TestLinearEquation()\n    {\n        Func<double, double, double> exampleEquation = (x, _) => x;\n        List<double[]> points = RungeKuttaMethod.ClassicRungeKuttaMethod(0, 4, 0.001, 0, exampleEquation);\n        var yEnd = points[^1][1];\n        yEnd.Should().BeApproximately(8, 0.01);\n    }\n\n    [Test]\n    public static void TestExampleFunciton()\n    {\n        Func<double, double, double> exampleEquation = (_, y) => y;\n        List<double[]> points = RungeKuttaMethod.ClassicRungeKuttaMethod(0, 4, 0.0125, 1, exampleEquation);\n        var yEnd = points[^1][1];\n        yEnd.Should().BeApproximately(54.598, 0.0005);\n    }\n\n    [Test]\n    public static void StepsizeIsZeroOrNegative_ThrowsArgumentOutOfRangeException()\n    {\n        Func<double, double, double> exampleEquation = (x, _) => x;\n        Assert.Throws<ArgumentOutOfRangeException>(() => RungeKuttaMethod.ClassicRungeKuttaMethod(0, 4, 0, 0, exampleEquation));\n    }\n\n    [Test]\n    public static void StartIsLargerThanEnd_ThrowsArgumentOutOfRangeException()\n    {\n        Func<double, double, double> exampleEquation = (x, _) => x;\n        Assert.Throws<ArgumentOutOfRangeException>(() => RungeKuttaMethod.ClassicRungeKuttaMethod(0, -4, 0.1, 0, exampleEquation));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/SigmoidTests.cs",
    "content": "using Algorithms.Numeric;\nusing NUnit.Framework;\nusing System;\n\nnamespace Algorithms.Tests.Numeric;\n\n/// <summary>\n/// Tests for the Sigmoid class, which implements the sigmoid activation function.\n/// </summary>\npublic static class SigmoidTests\n{\n    // Standard tolerance for floating-point comparisons.\n    private const double Tolerance = 1e-15;\n\n    /// <summary>\n    /// Tests that the sigmoid function correctly calculates the center point (x=0).\n    /// Sigmoid(0) should equal 0.5.\n    /// </summary>\n    [Test]\n    public static void GetsCenterValue()\n    {\n        // Arrange\n        double x = 0.0;\n        double expected = 0.5;\n\n        // Act\n        var result = Sigmoid.Calculate(x);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected).Within(Tolerance));\n    }\n\n    /// <summary>\n    /// Tests that the sigmoid function approaches 1 for large positive inputs (asymptotic behavior).\n    /// </summary>\n    [Test]\n    public static void GetsAsymptoticValueForLargePositiveX()\n    {\n        // Arrange\n        double x = 100.0;\n        double expected = 1.0; \n\n        // Act\n        var result = Sigmoid.Calculate(x);\n\n        // Assert\n        // The result should be extremely close to 1.0. \n        Assert.That(result, Is.EqualTo(expected).Within(1e-10));\n    }\n    \n    /// <summary>\n    /// Tests that the sigmoid function approaches 0 for large negative inputs (asymptotic behavior).\n    /// </summary>\n    [Test]\n    public static void GetsAsymptoticValueForLargeNegativeX()\n    {\n        // Arrange\n        double x = -100.0;\n        double expected = 0.0;\n\n        // Act\n        var result = Sigmoid.Calculate(x);\n\n        // Assert\n        // The result should be extremely close to 0.0.\n        Assert.That(result, Is.EqualTo(expected).Within(1e-10));\n    }\n\n    /// <summary>\n    /// Tests the sigmoid calculation for various general positive and negative values.\n    /// Values are confirmed against a reference calculation (or manually verified).\n    /// </summary>\n    /// <param name=\"input\">The input value.</param>\n    /// <param name=\"expected\">The expected sigmoid output.</param>\n    [TestCase(1.0, 0.7310585786300049)]\n    [TestCase(5.0, 0.9933071490757153)]\n    [TestCase(-1.0, 0.2689414213699951)]\n    [TestCase(-5.0, 0.006692850924284855)]\n    [TestCase(0.5, 0.6224593312018546)]\n    [TestCase(-0.5, 0.3775406687981454)]\n    public static void GetsStandardSigmoidValues(double input, double expected)\n    {\n        // Act\n        var result = Sigmoid.Calculate(input);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected).Within(Tolerance));\n    }\n\n    /// <summary>\n    /// Tests that the calculation correctly handles floating-point values and large numbers.\n    /// </summary>\n    [Test]\n    public static void HandlesFractionalAndLargeInput()\n    {\n        // Arrange\n        double x1 = 3.14159; // PI approximation\n        // Corrected expected value: 1 / (1 + e^-3.14159)\n        double expected1 = 0.9585760624650355; \n\n        double x2 = -20.0; \n        // Expected = 1 / (1 + e^20) - Should be very close to 0\n        double expected2 = 2.0611536224385583E-9;\n\n        // Act & Assert 1\n        var result1 = Sigmoid.Calculate(x1);\n        Assert.That(result1, Is.EqualTo(expected1).Within(Tolerance));\n        \n        // Act & Assert 2\n        var result2 = Sigmoid.Calculate(x2);\n        Assert.That(result2, Is.EqualTo(expected2).Within(Tolerance));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/SoftMaxTests.cs",
    "content": "using Algorithms.Numeric;\n\nnamespace Algorithms.Tests.Numeric;\n\npublic static class SoftMaxTests\n{\n    [TestCase(new[] { 5.0, 5.0 }, new[] { 0.5, 0.5 })]\n    [TestCase(new[] { 1.0, 2.0, 3.0 }, new[] { 0.09003057317038046, 0.24472847105479767, 0.6652409557748219 })]\n    [TestCase(new[] { 0.0 }, new[] { 1.0 })]\n    public static void SoftMaxFunction(double[] input, double[] expected)\n    {\n        // Act\n        var result = SoftMax.Compute(input);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected).Within(1e-9));\n    }\n\n    [Test]\n    public static void SoftMaxFunctionThrowsArgumentException()\n    {\n        // Arrange\n        var input = Array.Empty<double>();\n\n        // Assert\n        Assert.Throws<ArgumentException>(() => SoftMax.Compute(input));\n    }\n\n    [TestCase(new[] { 1.0, 2.0, 3.0, 4.0, 5.0 })]\n    [TestCase(new[] { 0.0, 0.0, 0.0, 0.0, 0.0 })]\n    [TestCase(new[] { 5.0 })]\n    public static void SoftMaxFunctionSumsToOne(double[] input)\n    {\n        // Act\n        var result = SoftMax.Compute(input);\n\n        var sum = 0.0;\n        foreach (var value in result)\n        {\n            sum += value;\n        }\n\n        // Assert\n        Assert.That(sum, Is.EqualTo(1.0).Within(1e-9));\n    }\n}"
  },
  {
    "path": "Algorithms.Tests/Numeric/SumOfDigitsTest.cs",
    "content": "using Algorithms.Numeric;\nusing NUnit.Framework;\nusing System;\n\nnamespace Algorithms.Tests.Numeric;\n\n/// <summary>\n/// Tests for the SumOfDigits class.\n/// </summary>\npublic static class SumOfDigitsTests\n{\n    /// <summary>\n    /// Tests the calculation of the sum of digits for various non-negative integers.\n    /// </summary>\n    /// <param name=\"input\">The input number.</param>\n    /// <param name=\"expectedSum\">The expected sum of its digits.</param>\n    [TestCase(0, 0)]\n    [TestCase(7, 7)]\n    [TestCase(10, 1)]\n    [TestCase(42, 6)]\n    [TestCase(12345, 15)]\n    [TestCase(9999, 36)]\n    [TestCase(8675309, 38)]\n    [TestCase(2147483647, 46)] // Max value for int\n    public static void GetsCorrectSumOfDigits(int input, int expectedSum)\n    {\n        // Act\n        var result = SumOfDigits.Calculate(input);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expectedSum));\n    }\n\n    /// <summary>\n    /// Tests that the method throws an ArgumentException when a negative number is provided.\n    /// </summary>\n    /// <param name=\"num\">The negative input number.</param>\n    [TestCase(-1)]\n    [TestCase(-100)]\n    [TestCase(-54321)]\n    public static void ThrowsExceptionForNegativeNumbers(int num)\n    {\n        // Act\n        void Act() => SumOfDigits.Calculate(num);\n\n        // Assert\n        _ = Assert.Throws<ArgumentException>(Act);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Numeric/TanhTest.cs",
    "content": "using Algorithms.Numeric;\nusing NUnit.Framework;\nusing System;\n\nnamespace Algorithms.Tests.Numeric;\n\n[TestFixture]\npublic static class TanhTests\n{\n    // Tolerance for floating-point comparisons\n    private const double Tolerance = 1e-9; \n\n    // --- SCALAR TESTS (Tanh.Compute(double)) ---\n\n    /// <summary>\n    /// Tests Tanh function for specific values, including zero and symmetric positive/negative inputs.\n    /// </summary>\n    [TestCase(0.0, 0.0)]\n    [TestCase(1.0, 0.7615941559557649)]\n    [TestCase(-1.0, -0.7615941559557649)]\n    [TestCase(5.0, 0.999909204262595)]\n    [TestCase(-5.0, -0.999909204262595)]\n    public static void TanhFunction_Scalar_ReturnsCorrectValue(double input, double expected)\n    {\n        var result = Tanh.Compute(input);\n        Assert.That(result, Is.EqualTo(expected).Within(Tolerance));\n    }\n    \n    /// <summary>\n    /// Ensures the Tanh output approaches 1.0 for positive infinity and -1.0 for negative infinity.\n    /// </summary>\n    [Test]\n    public static void TanhFunction_Scalar_ApproachesLimits()\n    {\n        Assert.That(Tanh.Compute(double.PositiveInfinity), Is.EqualTo(1.0).Within(Tolerance));\n        Assert.That(Tanh.Compute(double.NegativeInfinity), Is.EqualTo(-1.0).Within(Tolerance));\n        Assert.That(Tanh.Compute(double.NaN), Is.NaN);\n    }\n\n    /// <summary>\n    /// Checks that the Tanh result is always bounded between -1.0 and 1.0.\n    /// </summary>\n    [TestCase(100.0)]\n    [TestCase(-100.0)]\n    [TestCase(0.0001)]\n    public static void TanhFunction_Scalar_ResultIsBounded(double input)\n    {\n        var result = Tanh.Compute(input);\n        Assert.That(result, Is.GreaterThanOrEqualTo(-1.0));\n        Assert.That(result, Is.LessThanOrEqualTo(1.0));\n    }\n\n    // --- VECTOR TESTS (Tanh.Compute(double[])) ---\n\n    /// <summary>\n    /// Tests the element-wise computation for a vector input.\n    /// </summary>\n    [Test]\n    public static void TanhFunction_Vector_ReturnsCorrectValues()\n    {\n        // Input: [0.0, 1.0, -2.0]\n        var input = new[] { 0.0, 1.0, -2.0 }; \n        // Expected: [Tanh(0.0), Tanh(1.0), Tanh(-2.0)]\n        var expected = new[] { 0.0, 0.7615941559557649, -0.9640275800758169 };\n\n        var result = Tanh.Compute(input);\n        \n        // Assert deep equality within tolerance\n        Assert.That(result, Is.EqualTo(expected).Within(Tolerance));\n    }\n    \n    /// <summary>\n    /// Tests vector handling of edge cases like infinity and NaN.\n    /// </summary>\n    [Test]\n    public static void TanhFunction_Vector_HandlesLimitsAndNaN()\n    {\n        var input = new[] { double.PositiveInfinity, 0.0, double.NaN }; \n        var expected = new[] { 1.0, 0.0, double.NaN };\n\n        var result = Tanh.Compute(input);\n\n        Assert.That(result.Length, Is.EqualTo(expected.Length));\n        Assert.That(result[0], Is.EqualTo(expected[0]).Within(Tolerance)); // Pos Inf -> 1.0\n        Assert.That(result[2], Is.NaN); // NaN\n    }\n    \n    // --- EXCEPTION TESTS ---\n\n    /// <summary>\n    /// Checks if the vector computation throws ArgumentNullException for null input.\n    /// </summary>\n    [Test]\n    public static void TanhFunction_Vector_ThrowsOnNullInput()\n    {\n        double[]? input = null; \n        Assert.Throws<ArgumentNullException>(() => Tanh.Compute(input!));\n    }\n\n    /// <summary>\n    /// Checks if the vector computation throws ArgumentException for an empty input array.\n    /// </summary>\n    [Test]\n    public static void TanhFunction_Vector_ThrowsOnEmptyInput()\n    {\n        var input = Array.Empty<double>();\n        Assert.Throws<ArgumentException>(() => Tanh.Compute(input));\n    }\n}"
  },
  {
    "path": "Algorithms.Tests/Other/BoyerMooreMajorityVoteTests.cs",
    "content": "using Algorithms.Other;\nusing NUnit.Framework;\nusing FluentAssertions;\n\nnamespace Algorithms.Tests.Other;\n\npublic class BoyerMooreMajorityVoteTests\n{\n    [Test]\n    public void FindMajority_SimpleMajority_ReturnsCorrectElement()\n    {\n        var nums = new[] { 3, 3, 4, 2, 3, 3, 3 };\n        var result = BoyerMooreMajorityVote.FindMajority(nums);\n        result.Should().Be(3);\n    }\n\n    [Test]\n    public void FindMajority_AllSameElements_ReturnsThatElement()\n    {\n        var nums = new[] { 5, 5, 5, 5 };\n        var result = BoyerMooreMajorityVote.FindMajority(nums);\n        result.Should().Be(5);\n    }\n\n    [Test]\n    public void FindMajority_NoMajority_ReturnsNull()\n    {\n        var nums = new[] { 1, 2, 3, 4 };\n        var result = BoyerMooreMajorityVote.FindMajority(nums);\n        result.Should().BeNull();\n    }\n\n    [Test]\n    public void FindMajority_EmptyArray_ReturnsNull()\n    {\n        var nums = Array.Empty<int>();\n        var result = BoyerMooreMajorityVote.FindMajority(nums);\n        result.Should().BeNull();\n    }\n\n    [Test]\n    public void FindMajority_NullArray_ReturnsNull()\n    {\n        int[]? nums = null;\n        var result = BoyerMooreMajorityVote.FindMajority(nums!);\n        result.Should().BeNull();\n    }\n\n    [Test]\n    public void FindMajority_SingleElement_ReturnsThatElement()\n    {\n        var nums = new[] { 7 };\n        var result = BoyerMooreMajorityVote.FindMajority(nums);\n        result.Should().Be(7);\n    }\n\n    [Test]\n    public void FindMajority_MajorityAtEnd_ReturnsCorrectElement()\n    {\n        var nums = new[] { 1, 2, 2, 2, 2 };\n        var result = BoyerMooreMajorityVote.FindMajority(nums);\n        result.Should().Be(2);\n    }\n\n    [Test]\n    public void FindMajority_MajorityAtStart_ReturnsCorrectElement()\n    {\n        var nums = new[] { 8, 8, 8, 8, 1, 2 };\n        var result = BoyerMooreMajorityVote.FindMajority(nums);\n        result.Should().Be(8);\n    }\n\n    [Test]\n    public void FindMajority_NegativeNumbers_ReturnsCorrectElement()\n    {\n        var nums = new[] { -1, -1, -1, 2, 2 };\n        var result = BoyerMooreMajorityVote.FindMajority(nums);\n        result.Should().Be(-1);\n    }\n\n    [Test]\n    public void FindMajority_ExactlyHalf_ReturnsNull()\n    {\n        var nums = new[] { 1, 1, 2, 2 };\n        var result = BoyerMooreMajorityVote.FindMajority(nums);\n        result.Should().BeNull();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/DecisionsConvolutionsTest.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other;\n\npublic static class DecisionsConvolutionsTest\n{\n    [Test]\n    public static void Verify_Linear_Convolution()\n    {\n        // Arrange\n        var matrix = new List<List<decimal>>\n        {\n            new List<decimal> { 7, 6, 5, 8, 5, 6 },\n            new List<decimal> { 4, 8, 4, 4, 5, 3 },\n            new List<decimal> { 3, 8, 1, 4, 5, 2 },\n            new List<decimal> { 5, 6, 3, 6, 4, 5 },\n            new List<decimal> { 1, 4, 8, 6, 3, 6 },\n            new List<decimal> { 5, 1, 8, 6, 5, 1 },\n            new List<decimal> { 6, 8, 3, 6, 3, 5 }\n        };\n\n        var expectedMatrix = new List<decimal> { 7, 6, 5, 8, 5, 6 };\n\n        var priorities = new List<decimal> { 1, 1, 1, 1, 0.545m, 0.583m };\n\n        // Act\n        var optimizedMatrix = DecisionsConvolutions.Linear(matrix, priorities);\n\n        // Assert\n        Assert.That(expectedMatrix, Is.EqualTo(optimizedMatrix));\n    }\n\n    [Test]\n    public static void Verify_MaxMin_Convolution()\n    {\n        // Arrange\n        var matrix = new List<List<decimal>>\n        {\n            new List<decimal> { 7, 6, 5, 8, 5, 6 },\n            new List<decimal> { 4, 8, 4, 4, 5, 3 },\n            new List<decimal> { 3, 8, 1, 4, 5, 2 },\n            new List<decimal> { 5, 6, 3, 6, 4, 5 },\n            new List<decimal> { 1, 4, 8, 6, 3, 6 },\n            new List<decimal> { 5, 1, 8, 6, 5, 1 },\n            new List<decimal> { 6, 8, 3, 6, 3, 5 }\n        };\n\n        var expectedMatrix = new List<decimal> { 7, 6, 5, 8, 5, 6 };\n\n        var priorities = new List<decimal> { 1, 1, 1, 1, 0.545m, 0.583m };\n\n        // Act\n        var optimizedMatrix = DecisionsConvolutions.MaxMin(matrix, priorities);\n\n        // Assert\n        Assert.That(expectedMatrix, Is.EqualTo(optimizedMatrix));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/FermatPrimeCheckerTests.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other;\n\npublic static class FermatPrimeCheckerTests\n{\n    [TestCase(5, true)]\n    [TestCase(2633, true)]\n    [TestCase(9439, true)]\n    [TestCase(1, false)]\n    [TestCase(8, false)]\n    public static void IsProbablePrime(int inputNum, bool expected)\n    {\n        // Arrange\n        var random = new Randomizer();\n        var times = random.Next(1, 1000);\n\n        // Act\n        var result = FermatPrimeChecker.IsPrime(inputNum, times);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/FloodFillTest.cs",
    "content": "using SkiaSharp;\n\nnamespace Algorithms.Tests.Other;\n\npublic static class Tests\n{\n    private const byte Alpha = 255;\n    private static readonly SKColor Black = new(0, 0, 0, Alpha);\n    private static readonly SKColor Green = new(0, 255, 0, Alpha);\n    private static readonly SKColor Violet = new(255, 0, 255, Alpha);\n    private static readonly SKColor White = new(255, 255, 255, Alpha);\n    private static readonly SKColor Orange = new(255, 128, 0, Alpha);\n\n    [Test]\n    public static void BreadthFirstSearch_ThrowsArgumentOutOfRangeException()\n    {\n        Action act = () => Algorithms.Other.FloodFill.BreadthFirstSearch(GenerateTestBitmap(), (10, 10), Black, White);\n        act.Should().Throw<ArgumentOutOfRangeException>();\n    }\n\n    [Test]\n    public static void DepthFirstSearch_ThrowsArgumentOutOfRangeException()\n    {\n        Action act = () => Algorithms.Other.FloodFill.DepthFirstSearch(GenerateTestBitmap(), (-1, -1), Black, White);\n        act.Should().Throw<ArgumentOutOfRangeException>();\n    }\n\n    [Test]\n    public static void BreadthFirstSearch_Test1()\n    {\n        TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), Green, Orange, (1, 1), Orange);\n    }\n\n    [Test]\n    public static void BreadthFirstSearch_Test2()\n    {\n        TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), Green, Orange, (0, 1), Violet);\n    }\n\n    [Test]\n    public static void BreadthFirstSearch_Test3()\n    {\n        TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), Green, Orange, (6, 4), White);\n    }\n\n    [Test]\n    public static void DepthFirstSearch_Test1()\n    {\n        TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), Green, Orange, (1, 1), Orange);\n    }\n\n    [Test]\n    public static void DepthFirstSearch_Test2()\n    {\n        TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), Green, Orange, (0, 1), Violet);\n    }\n\n    [Test]\n    public static void DepthFirstSearch_Test3()\n    {\n        TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), Green, Orange, (6, 4), White);\n    }\n\n    private static SKBitmap GenerateTestBitmap()\n    {\n        SKColor[,] layout =\n        {\n            {Violet, Violet, Green, Green, Black, Green, Green},\n            {Violet, Green, Green, Black, Green, Green, Green},\n            {Green, Green, Green, Black, Green, Green, Green},\n            {Black, Black, Green, Black, White, White, Green},\n            {Violet, Violet, Black, Violet, Violet, White, White},\n            {Green, Green, Green, Violet, Violet, Violet, Violet},\n            {Violet, Violet, Violet, Violet, Violet, Violet, Violet},\n        };\n\n        SKBitmap bitmap = new(7, 7);\n        for (int x = 0; x < layout.GetLength(0); x++)\n        {\n            for (int y = 0; y < layout.GetLength(1); y++)\n            {\n                bitmap.SetPixel(x, y, layout[y, x]);\n            }\n        }\n\n        return bitmap;\n    }\n\n    private static void TestAlgorithm(\n        Action<SKBitmap, ValueTuple<int, int>, SKColor, SKColor> algorithm,\n        ValueTuple<int, int> fillLocation,\n        SKColor targetColor,\n        SKColor replacementColor,\n        ValueTuple<int, int> testLocation,\n        SKColor expectedColor)\n    {\n        SKBitmap bitmap = GenerateTestBitmap();\n        algorithm(bitmap, fillLocation, targetColor, replacementColor);\n        SKColor actualColor = bitmap.GetPixel(testLocation.Item1, testLocation.Item2);\n        actualColor.Should().Be(expectedColor);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/GaussOptimizationTest.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other;\n\npublic static class GaussOptimizationTest\n{\n    [Test]\n    public static void Verify_Gauss_Optimization_Positive()\n    {\n        // Arrange\n        var gaussOptimization = new GaussOptimization();\n\n        // Declaration of the constants that are used in the function\n        var coefficients = new List<double> { 0.3, 0.6, 2.6, 0.3, 0.2, 1.4 };\n\n        // Description of the function\n        var func = (double x1, double x2) =>\n        {\n            if (x1 > 1 || x1 < 0 || x2 > 1 || x2 < 0)\n            {\n                return 0;\n            }\n\n            return coefficients[0] + coefficients[1] * x1 + coefficients[2] * x2 + coefficients[3] * x1 * x2 +\n                coefficients[4] * x1 * x1 + coefficients[5] * x2 * x2;\n        };\n\n        // The parameter that identifies how much step size will be decreased each iteration\n        double n = 2.4;\n\n        // Default values of x1 and x2. These values will be used for the calculation of the next\n        // coordinates by Gauss optimization method\n        double x1 = 0.5;\n        double x2 = 0.5;\n\n        // Default optimization step\n        double step = 0.5;\n\n        // This value is used to control the accuracy of the optimization. In case if the error is less\n        // than eps, optimization will be stopped\n        double eps = Math.Pow(0.1, 10);\n\n        // Act\n        (x1, x2) = gaussOptimization.Optimize(func, n, step, eps, x1, x2);\n\n        // Assert\n        Assert.That(x1, Is.EqualTo(1).Within(0.3));\n        Assert.That(x2, Is.EqualTo(1).Within(0.3));\n    }\n\n    [Test]\n    public static void Verify_Gauss_Optimization_Negative()\n    {\n        // Arrange\n        var gaussOptimization = new GaussOptimization();\n\n        // Declaration of the constants that are used in the function\n        var coefficients = new List<double> { -0.3, -0.6, -2.6, -0.3, -0.2, -1.4 };\n\n        // Description of the function\n        var func = (double x1, double x2) =>\n        {\n            if (x1 > 0 || x1 < -1 || x2 > 0 || x2 < -1)\n            {\n                return 0;\n            }\n\n            return coefficients[0] + coefficients[1] * x1 + coefficients[2] * x2 + coefficients[3] * x1 * x2 +\n                coefficients[4] * x1 * x1 + coefficients[5] * x2 * x2;\n        };\n\n        // The parameter that identifies how much step size will be decreased each iteration\n        double n = 2.4;\n\n        // Default values of x1 and x2. These values will be used for the calculation of the next\n        // coordinates by Gauss optimization method\n        double x1 = -0.5;\n        double x2 = -0.5;\n\n        // Default optimization step\n        double step = 0.5;\n\n        // This value is used to control the accuracy of the optimization. In case if the error is less\n        // than eps, optimization will be stopped\n        double eps = Math.Pow(0.1, 10);\n\n        // Act\n        (x1, x2) = gaussOptimization.Optimize(func, n, step, eps, x1, x2);\n\n        // Assert\n        Assert.That(x1, Is.EqualTo(-1).Within(0.3));\n        Assert.That(x2, Is.EqualTo(-1).Within(0.3));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/GeoLocationTests.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other;\n\npublic static class GeoLocationTests\n{\n    [TestCase(53.430488d, -2.96129d, 53.430488d, -2.96129d, 0d)]\n    [TestCase(53.430971d, -2.959806d, 53.430242d, -2.960830d, 105d)]\n    public static void CalculateDistanceFromLatLngTest(\n        double lat1,\n        double lng1,\n        double lat2,\n        double lng2,\n        double expectedValue)\n    {\n        var result = GeoLocation.CalculateDistanceFromLatLng(lat1, lng1, lat2, lng2);\n        var actualValue = Convert.ToDouble(result);\n\n        // Assert\n        Assert.That(actualValue, Is.EqualTo(expectedValue).Within(1d)); // Accept if distance diff is +/-1 meters.\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/GeofenceTests.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other\n{\n    [TestFixture]\n    public class GeofenceTests\n    {\n        private Geofence? geofence;\n\n        [SetUp]\n        public void Setup()\n        {\n            geofence = new Geofence(10.8231, 106.6297, 500);\n        }\n\n        [Test]\n        public void IsInside_ShouldReturnTrue_WhenUserIsInsideGeofence()\n        {\n            double userLat = 10.8221;\n            double userLon = 106.6289;\n\n            bool? result = geofence?.IsInside(userLat, userLon);\n\n            Assert.That(result, Is.True);\n        }\n\n        [Test]\n        public void IsInside_ShouldReturnFalse_WhenUserIsOutsideGeofence()\n        {\n            double userLat = 10.8300;\n            double userLon = 106.6400;\n\n            bool? result = geofence?.IsInside(userLat, userLon);\n\n            Assert.That(result, Is.False);\n        }\n\n        [Test]\n        public void IsInside_ShouldReturnTrue_WhenUserIsExactlyOnGeofenceBoundary()\n        {\n            double userLat = 10.8231;\n            double userLon = 106.6297;\n\n            bool? result = geofence?.IsInside(userLat, userLon);\n\n            Assert.That(result, Is.True);\n        }\n\n        [Test]\n        public void IsInside_ShouldReturnFalse_WhenUserIsFarFromGeofence()\n        {\n            double userLat = 20.0000;\n            double userLon = 100.0000;\n\n            bool? result = geofence?.IsInside(userLat, userLon);\n\n            Assert.That(result, Is.False);\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/GeohashTests.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other\n{\n    [TestFixture]\n    public class GeohashTests\n    {\n        [Test]\n        public void Encode_ShouldReturnCorrectGeohash_ForHoChiMinhCity()\n        {\n            double latitude = 10.8231;\n            double longitude = 106.6297;\n            string result = Geohash.Encode(latitude, longitude);\n            Assert.That(result, Is.EqualTo(\"w3gvd6m3hh54\"));\n        }\n\n        [Test]\n        public void Encode_ShouldReturnCorrectGeohash_ForHanoi()\n        {\n            double latitude = 21.0285;\n            double longitude = 105.8542;\n            string result = Geohash.Encode(latitude, longitude);\n            Assert.That(result, Is.EqualTo(\"w7er8u0evss2\"));\n        }\n\n        [Test]\n        public void Encode_ShouldReturnCorrectGeohash_ForDaNang()\n        {\n            double latitude = 16.0544;\n            double longitude = 108.2022;\n            string result = Geohash.Encode(latitude, longitude);\n            Assert.That(result, Is.EqualTo(\"w6ugq4w7wj04\"));\n        }\n\n        [Test]\n        public void Encode_ShouldReturnCorrectGeohash_ForNhaTrang()\n        {\n            double latitude = 12.2388;\n            double longitude = 109.1967;\n            string result = Geohash.Encode(latitude, longitude);\n            Assert.That(result, Is.EqualTo(\"w6jtsu485t8v\"));\n        }\n\n        [Test]\n        public void Encode_ShouldReturnCorrectGeohash_ForVungTau()\n        {\n            double latitude = 10.3460;\n            double longitude = 107.0843;\n            string result = Geohash.Encode(latitude, longitude);\n            Assert.That(result, Is.EqualTo(\"w3u4ug2mv41m\"));\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/Int2BinaryTests.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other;\n\npublic static class Int2BinaryTests\n{\n    [TestCase((ushort)0, \"0000000000000000\")]\n    [TestCase((ushort)0b1, \"0000000000000001\")]\n    [TestCase((ushort)0b0001010100111000, \"0001010100111000\")]\n    [TestCase((ushort)0b1110111100110010, \"1110111100110010\")]\n    [TestCase((ushort)(ushort.MaxValue - 1), \"1111111111111110\")]\n    [TestCase(ushort.MaxValue, \"1111111111111111\")]\n    public static void GetsBinary(ushort input, string expected)\n    {\n        // Arrange\n\n        // Act\n        var result = Int2Binary.Int2Bin(input);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected));\n    }\n\n\n    [TestCase((uint)0, \"00000000000000000000000000000000\")]\n    [TestCase((uint)0b1, \"00000000000000000000000000000001\")]\n    [TestCase((uint)0b0001010100111000, \"00000000000000000001010100111000\")]\n    [TestCase((uint)0b1110111100110010, \"00000000000000001110111100110010\")]\n    [TestCase(0b10101100001110101110111100110010, \"10101100001110101110111100110010\")]\n    [TestCase(uint.MaxValue - 1, \"11111111111111111111111111111110\")]\n    [TestCase(uint.MaxValue, \"11111111111111111111111111111111\")]\n    public static void GetsBinary(uint input, string expected)\n    {\n        // Arrange\n\n        // Act\n        var result = Int2Binary.Int2Bin(input);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected));\n    }\n\n    [TestCase((ulong)0, \"0000000000000000000000000000000000000000000000000000000000000000\")]\n    [TestCase((ulong)0b1, \"0000000000000000000000000000000000000000000000000000000000000001\")]\n    [TestCase((ulong)0b0001010100111000, \"0000000000000000000000000000000000000000000000000001010100111000\")]\n    [TestCase((ulong)0b1110111100110010, \"0000000000000000000000000000000000000000000000001110111100110010\")]\n    [TestCase((ulong)0b10101100001110101110111100110010,\n        \"0000000000000000000000000000000010101100001110101110111100110010\")]\n    [TestCase(0b1000101110100101000011010101110101010101110101001010000011111000,\n        \"1000101110100101000011010101110101010101110101001010000011111000\")]\n    [TestCase(ulong.MaxValue - 1, \"1111111111111111111111111111111111111111111111111111111111111110\")]\n    [TestCase(ulong.MaxValue, \"1111111111111111111111111111111111111111111111111111111111111111\")]\n    public static void GetsBinary(ulong input, string expected)\n    {\n        // Arrange\n\n        // Act\n        var result = Int2Binary.Int2Bin(input);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/JulianEasterTests.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other;\n\n/// <summary>\n///     A class for testing the Meeus's Julian Easter algorithm.\n/// </summary>\npublic static class JulianEasterTest\n{\n    [TestCaseSource(nameof(CalculateCases))]\n    public static void CalculateTest(int year, DateTime expected)\n    {\n        var result = JulianEaster.Calculate(year);\n\n        Assert.That(result, Is.EqualTo(expected));\n    }\n\n    private static readonly object[] CalculateCases =\n    [\n        new object[] { 1800, new DateTime(1800, 04, 08, 00, 00, 00, DateTimeKind.Utc) },\n        new object[] { 1950, new DateTime(1950, 03, 27, 00, 00, 00, DateTimeKind.Utc) },\n        new object[] { 1991, new DateTime(1991, 03, 25, 00, 00, 00, DateTimeKind.Utc) },\n        new object[] { 2000, new DateTime(2000, 04, 17, 00, 00, 00, DateTimeKind.Utc) },\n        new object[] { 2199, new DateTime(2199, 04, 07, 00, 00, 00, DateTimeKind.Utc) }\n    ];\n\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/KadanesAlgorithmTests.cs",
    "content": "using Algorithms.Other;\nusing NUnit.Framework;\nusing System;\n\nnamespace Algorithms.Tests.Other;\n\n/// <summary>\n///     Comprehensive test suite for Kadane's Algorithm implementation.\n///     Tests cover various scenarios including:\n///     - Arrays with all positive numbers\n///     - Arrays with mixed positive and negative numbers\n///     - Arrays with all negative numbers\n///     - Edge cases (single element, empty array, null array)\n///     - Index tracking functionality\n///     - Long integer support for large numbers\n/// </summary>\npublic static class KadanesAlgorithmTests\n{\n    [Test]\n    public static void FindMaximumSubarraySum_WithPositiveNumbers_ReturnsCorrectSum()\n    {\n        // Arrange: When all numbers are positive, the entire array is the maximum subarray\n        int[] array = { 1, 2, 3, 4, 5 };\n\n        // Act\n        int result = KadanesAlgorithm.FindMaximumSubarraySum(array);\n\n        // Assert: Sum of all elements = 1 + 2 + 3 + 4 + 5 = 15\n        Assert.That(result, Is.EqualTo(15));\n    }\n\n    [Test]\n    public static void FindMaximumSubarraySum_WithMixedNumbers_ReturnsCorrectSum()\n    {\n        // Arrange: Classic example with mixed positive and negative numbers\n        // The maximum subarray is [4, -1, 2, 1] starting at index 3\n        int[] array = { -2, 1, -3, 4, -1, 2, 1, -5, 4 };\n\n        // Act\n        int result = KadanesAlgorithm.FindMaximumSubarraySum(array);\n\n        // Assert: Maximum sum is 4 + (-1) + 2 + 1 = 6\n        Assert.That(result, Is.EqualTo(6)); // Subarray [4, -1, 2, 1]\n    }\n\n    [Test]\n    public static void FindMaximumSubarraySum_WithAllNegativeNumbers_ReturnsLargestNegative()\n    {\n        // Arrange: When all numbers are negative, the algorithm returns the least negative number\n        // This represents a subarray of length 1 containing the largest (least negative) element\n        int[] array = { -5, -2, -8, -1, -4 };\n\n        // Act\n        int result = KadanesAlgorithm.FindMaximumSubarraySum(array);\n\n        // Assert: -1 is the largest (least negative) number in the array\n        Assert.That(result, Is.EqualTo(-1));\n    }\n\n    [Test]\n    public static void FindMaximumSubarraySum_WithSingleElement_ReturnsThatElement()\n    {\n        // Arrange: Edge case with only one element\n        // The only possible subarray is the element itself\n        int[] array = { 42 };\n\n        // Act\n        int result = KadanesAlgorithm.FindMaximumSubarraySum(array);\n\n        // Assert: The single element is both the subarray and its sum\n        Assert.That(result, Is.EqualTo(42));\n    }\n\n    [Test]\n    public static void FindMaximumSubarraySum_WithNullArray_ThrowsArgumentException()\n    {\n        // Arrange: Test defensive programming - null input validation\n        int[]? array = null;\n\n        // Act & Assert: Should throw ArgumentException for null input\n        Assert.Throws<ArgumentException>(() => KadanesAlgorithm.FindMaximumSubarraySum(array!));\n    }\n\n    [Test]\n    public static void FindMaximumSubarraySum_WithEmptyArray_ThrowsArgumentException()\n    {\n        // Arrange\n        int[] array = Array.Empty<int>();\n\n        // Act & Assert\n        Assert.Throws<ArgumentException>(() => KadanesAlgorithm.FindMaximumSubarraySum(array));\n    }\n\n    [Test]\n    public static void FindMaximumSubarraySum_WithAlternatingNumbers_ReturnsCorrectSum()\n    {\n        // Arrange: Alternating positive and negative numbers\n        // Despite negative values, the entire array gives the maximum sum\n        int[] array = { 5, -3, 5, -3, 5 };\n\n        // Act\n        int result = KadanesAlgorithm.FindMaximumSubarraySum(array);\n\n        // Assert: Sum of entire array = 5 - 3 + 5 - 3 + 5 = 9\n        Assert.That(result, Is.EqualTo(9)); // Entire array\n    }\n\n    [Test]\n    public static void FindMaximumSubarrayWithIndices_ReturnsCorrectIndices()\n    {\n        // Arrange: Test the variant that returns indices of the maximum subarray\n        // Array: [-2, 1, -3, 4, -1, 2, 1, -5, 4]\n        // Index:   0  1   2  3   4  5  6   7  8\n        int[] array = { -2, 1, -3, 4, -1, 2, 1, -5, 4 };\n\n        // Act\n        var (maxSum, startIndex, endIndex) = KadanesAlgorithm.FindMaximumSubarrayWithIndices(array);\n\n        // Assert: Maximum subarray is [4, -1, 2, 1] from index 3 to 6\n        Assert.That(maxSum, Is.EqualTo(6));\n        Assert.That(startIndex, Is.EqualTo(3));\n        Assert.That(endIndex, Is.EqualTo(6));\n    }\n\n    [Test]\n    public static void FindMaximumSubarrayWithIndices_WithSingleElement_ReturnsZeroIndices()\n    {\n        // Arrange\n        int[] array = { 10 };\n\n        // Act\n        var (maxSum, startIndex, endIndex) = KadanesAlgorithm.FindMaximumSubarrayWithIndices(array);\n\n        // Assert\n        Assert.That(maxSum, Is.EqualTo(10));\n        Assert.That(startIndex, Is.EqualTo(0));\n        Assert.That(endIndex, Is.EqualTo(0));\n    }\n\n    [Test]\n    public static void FindMaximumSubarrayWithIndices_WithNullArray_ThrowsArgumentException()\n    {\n        // Arrange\n        int[]? array = null;\n\n        // Act & Assert\n        Assert.Throws<ArgumentException>(() => KadanesAlgorithm.FindMaximumSubarrayWithIndices(array!));\n    }\n\n    [Test]\n    public static void FindMaximumSubarraySum_WithLongArray_ReturnsCorrectSum()\n    {\n        // Arrange: Test the long integer overload with same values as int test\n        // Verifies that the algorithm works correctly with long data type\n        long[] array = { -2L, 1L, -3L, 4L, -1L, 2L, 1L, -5L, 4L };\n\n        // Act\n        long result = KadanesAlgorithm.FindMaximumSubarraySum(array);\n\n        // Assert: Should produce same result as int version\n        Assert.That(result, Is.EqualTo(6L));\n    }\n\n    [Test]\n    public static void FindMaximumSubarraySum_WithLargeLongNumbers_ReturnsCorrectSum()\n    {\n        // Arrange: Test with large numbers that would overflow int type\n        // This demonstrates why the long overload is necessary\n        // Sum would be 1,500,000,000 which fits in long but is near int.MaxValue\n        long[] array = { 1000000000L, -500000000L, 1000000000L };\n\n        // Act\n        long result = KadanesAlgorithm.FindMaximumSubarraySum(array);\n\n        // Assert: Entire array sum = 1,000,000,000 - 500,000,000 + 1,000,000,000 = 1,500,000,000\n        Assert.That(result, Is.EqualTo(1500000000L));\n    }\n\n    [Test]\n    public static void FindMaximumSubarraySum_WithLongNullArray_ThrowsArgumentException()\n    {\n        // Arrange\n        long[]? array = null;\n\n        // Act & Assert\n        Assert.Throws<ArgumentException>(() => KadanesAlgorithm.FindMaximumSubarraySum(array!));\n    }\n\n    [Test]\n    public static void FindMaximumSubarraySum_WithZeros_ReturnsZero()\n    {\n        // Arrange: Edge case with all zeros\n        // Any subarray will have sum of 0\n        int[] array = { 0, 0, 0, 0 };\n\n        // Act\n        int result = KadanesAlgorithm.FindMaximumSubarraySum(array);\n\n        // Assert: Maximum sum is 0\n        Assert.That(result, Is.EqualTo(0));\n    }\n\n    [Test]\n    public static void FindMaximumSubarraySum_WithMixedZerosAndNegatives_ReturnsZero()\n    {\n        // Arrange: Mix of zeros and negative numbers\n        // The best subarray is any single zero (or multiple zeros)\n        int[] array = { -5, 0, -3, 0, -2 };\n\n        // Act\n        int result = KadanesAlgorithm.FindMaximumSubarraySum(array);\n\n        // Assert: Zero is better than any negative number\n        Assert.That(result, Is.EqualTo(0));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/KochSnowflakeTest.cs",
    "content": "using Algorithms.Other;\nusing SkiaSharp;\n\nnamespace Algorithms.Tests.Other;\n\npublic static class KochSnowflakeTest\n{\n    [Test]\n    public static void TestIterateMethod()\n    {\n        List<Vector2> vectors = [new Vector2(0, 0), new Vector2(1, 0)];\n        List<Vector2> result = KochSnowflake.Iterate(vectors, 1);\n        result[0].Should().Be(new Vector2(0, 0));\n        result[1].Should().Be(new Vector2((float)1 / 3, 0));\n\n        /* Should().BeApproximately() is not defined for Vector2 or float\n        so the x-y-components have to be tested separately and the y-component needs to be cast to double */\n        result[2].X.Should().Be(0.5f);\n        ((double)result[2].Y).Should().BeApproximately(Math.Sin(Math.PI / 3) / 3, 0.0001);\n\n        result[3].Should().Be(new Vector2((float)2 / 3, 0));\n        result[4].Should().Be(new Vector2(1, 0));\n    }\n\n    [Test]\n    public static void BitmapWidthIsZeroOrNegative_ThrowsArgumentOutOfRangeException()\n    {\n        Assert.Throws<ArgumentOutOfRangeException>(() => KochSnowflake.GetKochSnowflake(-200));\n    }\n\n    [Test]\n    public static void TestKochSnowflakeExample()\n    {\n        var bitmapWidth = 600;\n        var offsetX = bitmapWidth / 10f;\n        var offsetY = bitmapWidth / 3.7f;\n        SKBitmap bitmap = KochSnowflake.GetKochSnowflake();\n        bitmap.GetPixel(0, 0)\n            .Should()\n            .Be(new SKColor(255, 255, 255, 255), \"because the background should be white\");\n        bitmap.GetPixel((int)offsetX, (int)offsetY)\n            .Should()\n            .Be(new SKColor(0, 0, 0, 255), \"because the snowflake is drawn in black and this is the position of the first vector\");\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/LuhnTests.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other;\n\n/// <summary>\n///     A class for testing the Luhn algorithm.\n/// </summary>\npublic class LuhnTests\n{\n    [TestCase(\"89014103211118510720\")] // ICCID\n    [TestCase(\"071052120\")] // Social Security Code\n    [TestCase(\"449125546588769\")] // IMEI\n    [TestCase(\"4417123456789113\")] // Bank card\n    public void ValidateTrue(string number)\n    {\n        // Arrange\n        bool validate;\n\n        // Act\n        validate = Luhn.Validate(number);\n\n        // Assert\n        Assert.That(validate, Is.True);\n    }\n\n    [TestCase(\"89012104211118510720\")] // ICCID\n    [TestCase(\"021053120\")] // Social Security Code\n    [TestCase(\"449145545588969\")] // IMEI\n    [TestCase(\"4437113456749113\")] // Bank card\n    public void ValidateFalse(string number)\n    {\n        // Arrange\n        bool validate;\n\n        // Act\n        validate = Luhn.Validate(number);\n\n        // Assert\n        Assert.That(validate, Is.False);\n    }\n\n    [TestCase(\"x9012104211118510720\")] // ICCID\n    [TestCase(\"0210x3120\")] // Social Security Code\n    [TestCase(\"44914554558896x\")] // IMEI\n    [TestCase(\"4437113456x49113\")] // Bank card\n    public void GetLostNum(string number)\n    {\n        // Arrange\n        int lostNum;\n        bool validate;\n\n        // Act\n        lostNum = Luhn.GetLostNum(number);\n        validate = Luhn.Validate(number.Replace(\"x\", lostNum.ToString()));\n\n        // Assert\n        Assert.That(validate, Is.True);\n    }\n\n    [TestCase(\"\")]\n    [TestCase(\"xxxx\")] \n    [TestCase(\"abcde\")]\n    [TestCase(\"1x345678901234567\")]\n    [TestCase(\"x1234567890123456\")]\n    [TestCase(\"1234567890123456x\")]\n    [TestCase(\"1111111111111111\")]\n    [TestCase(\"1a2b3c4d5e6f7g8h9i0j\")]\n    public void EdgeCases_GetLostNum(string number)\n    {\n        // Act\n        int lostNum = Luhn.GetLostNum(number.Replace(\"x\", \"0\"));\n        // Assert\n        Assert.That(lostNum, Is.InRange(0, 9));\n    }\n\n    [TestCase(\"1a2b3c4d5e6f7g8h9i0j\")]\n    public void EdgeCases_Validate(string number)\n    {\n        // Act\n        bool result = Luhn.Validate(number);\n        // Assert\n        Assert.That(result, Is.False);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/MandelbrotTest.cs",
    "content": "using Algorithms.Other;\nusing SkiaSharp;\n\nnamespace Algorithms.Tests.Other;\n\npublic static class MandelbrotTest\n{\n    [Test]\n    public static void BitmapWidthIsZeroOrNegative_ThrowsArgumentOutOfRangeException()\n    {\n        Assert.Throws<ArgumentOutOfRangeException>(() => Mandelbrot.GetBitmap(-200));\n    }\n\n    [Test]\n    public static void BitmapHeightIsZeroOrNegative_ThrowsArgumentOutOfRangeException()\n    {\n        Assert.Throws<ArgumentOutOfRangeException>(() => Mandelbrot.GetBitmap(bitmapHeight: 0));\n    }\n\n    [Test]\n    public static void MaxStepIsZeroOrNegative_ThrowsArgumentOutOfRangeException()\n    {\n        Assert.Throws<ArgumentOutOfRangeException>(() => Mandelbrot.GetBitmap(maxStep: -1));\n    }\n\n    [Test]\n    public static void TestBlackAndWhite()\n    {\n        SKBitmap bitmap = Mandelbrot.GetBitmap(useDistanceColorCoding: false);\n        // Pixel outside the Mandelbrot set should be white.\n        Assert.That(new SKColor(255, 255, 255, 255), Is.EqualTo(bitmap.GetPixel(0, 0)));\n\n        // Pixel inside the Mandelbrot set should be black.\n        Assert.That(new SKColor(0, 0, 0, 255), Is.EqualTo(bitmap.GetPixel(400, 300)));\n    }\n\n    [Test]\n    public static void TestColorCoded()\n    {\n        SKBitmap bitmap = Mandelbrot.GetBitmap(useDistanceColorCoding: true);\n        // Pixel distant to the Mandelbrot set should be red.\n        Assert.That(new SKColor(255, 0, 0, 255), Is.EqualTo(bitmap.GetPixel(0, 0)));\n\n        // Pixel inside the Mandelbrot set should be black.\n        Assert.That(new SKColor(0, 0, 0, 255), Is.EqualTo(bitmap.GetPixel(400, 300)));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/ParetoOptimizationTests.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other;\n\npublic static class ParetoOptimizationTests\n{\n    [Test]\n    public static void Verify_Pareto_Optimization()\n    {\n        // Arrange\n        var paretoOptimization = new ParetoOptimization();\n\n        var matrix = new List<List<decimal>>\n        {\n            new List<decimal> { 7, 6, 5, 8, 5, 6 },\n            new List<decimal> { 4, 8, 4, 4, 5, 3 },\n            new List<decimal> { 3, 8, 1, 4, 5, 2 },\n            new List<decimal> { 5, 6, 3, 6, 4, 5 },\n            new List<decimal> { 1, 4, 8, 6, 3, 6 },\n            new List<decimal> { 5, 1, 8, 6, 5, 1 },\n            new List<decimal> { 6, 8, 3, 6, 3, 5 }\n        };\n\n        var expectedMatrix = new List<List<decimal>>\n        {\n            new List<decimal> { 7, 6, 5, 8, 5, 6 },\n            new List<decimal> { 4, 8, 4, 4, 5, 3 },\n            new List<decimal> { 1, 4, 8, 6, 3, 6 },\n            new List<decimal> { 5, 1, 8, 6, 5, 1 },\n            new List<decimal> { 6, 8, 3, 6, 3, 5 }\n        };\n\n        // Act\n        var optimizedMatrix = paretoOptimization.Optimize(matrix);\n\n        // Assert\n        Assert.That(expectedMatrix, Is.EqualTo(optimizedMatrix));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/PollardsRhoFactorizingTests.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other;\n\npublic class PollardsRhoFactorizingTests\n{\n    [TestCase(8051, 97)]\n    [TestCase(105, 21)]\n    [TestCase(253, 11)]\n    [TestCase(10403, 101)]\n    [TestCase(187, 11)]\n    public void SimpleTest(int number, int expectedResult)\n    {\n        var result = PollardsRhoFactorizing.Calculate(number);\n        Assert.That(result, Is.EqualTo(expectedResult));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/RGBHSVConversionTest.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other;\n\npublic static class RgbHsvConversionTest\n{\n    [Test]\n    public static void HueOutOfRange_ThrowsArgumentOutOfRangeException()\n    {\n        Action act = () => RgbHsvConversion.HsvToRgb(400, 0, 0);\n        act.Should().Throw<ArgumentOutOfRangeException>();\n    }\n\n    [Test]\n    public static void SaturationOutOfRange_ThrowsArgumentOutOfRangeException()\n    {\n        Action act = () => RgbHsvConversion.HsvToRgb(0, 2, 0);\n        act.Should().Throw<ArgumentOutOfRangeException>();\n    }\n\n    [Test]\n    public static void ValueOutOfRange_ThrowsArgumentOutOfRangeException()\n    {\n        Action act = () => RgbHsvConversion.HsvToRgb(0, 0, 2);\n        act.Should().Throw<ArgumentOutOfRangeException>();\n    }\n\n    // expected RGB-values taken from https://www.rapidtables.com/convert/color/hsv-to-rgb.html\n    [TestCase(0, 0, 0, 0, 0, 0)]\n    [TestCase(0, 0, 1, 255, 255, 255)]\n    [TestCase(0, 1, 1, 255, 0, 0)]\n    [TestCase(60, 1, 1, 255, 255, 0)]\n    [TestCase(120, 1, 1, 0, 255, 0)]\n    [TestCase(240, 1, 1, 0, 0, 255)]\n    [TestCase(300, 1, 1, 255, 0, 255)]\n    [TestCase(180, 0.5, 0.5, 64, 128, 128)]\n    [TestCase(234, 0.14, 0.88, 193, 196, 224)]\n    [TestCase(330, 0.75, 0.5, 128, 32, 80)]\n    public static void TestRgbOutput(\n        double hue,\n        double saturation,\n        double value,\n        byte expectedRed,\n        byte exptectedGreen,\n        byte exptectedBlue)\n    {\n        var rgb = RgbHsvConversion.HsvToRgb(hue, saturation, value);\n        rgb.Item1.Should().Be(expectedRed);\n        rgb.Item2.Should().Be(exptectedGreen);\n        rgb.Item3.Should().Be(exptectedBlue);\n    }\n\n    // Parameters of test-cases for TestRGBOutput reversed\n    [TestCase(0, 0, 0, 0, 0, 0)]\n    [TestCase(255, 255, 255, 0, 0, 1)]\n    [TestCase(255, 0, 0, 0, 1, 1)]\n    [TestCase(255, 255, 0, 60, 1, 1)]\n    [TestCase(0, 255, 0, 120, 1, 1)]\n    [TestCase(0, 0, 255, 240, 1, 1)]\n    [TestCase(255, 0, 255, 300, 1, 1)]\n    [TestCase(64, 128, 128, 180, 0.5, 0.5)]\n    [TestCase(193, 196, 224, 234, 0.14, 0.88)]\n    [TestCase(128, 32, 80, 330, 0.75, 0.5)]\n    public static void TestHsvOutput(\n        byte red,\n        byte green,\n        byte blue,\n        double expectedHue,\n        double expectedSaturation,\n        double expectedValue)\n    {\n        var hsv = RgbHsvConversion.RgbToHsv(red, green, blue);\n\n        // approximate-assertions needed because of small deviations due to converting between byte-values and double-values.\n        hsv.Item1.Should().BeApproximately(expectedHue, 0.2);\n        hsv.Item2.Should().BeApproximately(expectedSaturation, 0.002);\n        hsv.Item3.Should().BeApproximately(expectedValue, 0.002);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/SieveOfEratosthenesTests.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other;\n\npublic static class SieveOfEratosthenesTests\n{\n    private static readonly long[] First10000PrimeNumbers =\n    [\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, 97, 101, 103,\n        107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,\n        227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347,\n        349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,\n        467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607,\n        613, 617, 619, 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, 877, 881, 883,\n        887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031,\n        1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153,\n        1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289,\n        1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433,\n        1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553,\n        1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669,\n        1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823,\n        1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979,\n        1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099,\n        2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251,\n        2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381,\n        2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539,\n        2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683,\n        2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797,\n        2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953,\n        2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109,\n        3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259,\n        3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407,\n        3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547,\n        3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691,\n        3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847,\n        3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001,\n        4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133,\n        4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273,\n        4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451,\n        4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603,\n        4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759,\n        4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933,\n        4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059,\n        5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231,\n        5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407,\n        5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527,\n        5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689,\n        5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843,\n        5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011,\n        6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163,\n        6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311,\n        6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469,\n        6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653,\n        6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793,\n        6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959,\n        6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109,\n        7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283,\n        7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481,\n        7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591,\n        7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753,\n        7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927,\n        7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101,\n        8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269,\n        8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431,\n        8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623,\n        8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747,\n        8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923,\n        8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067,\n        9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239,\n        9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403,\n        9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539,\n        9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721,\n        9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, 9859,\n        9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061,\n        10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169,\n        10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303,\n        10313, 10321, 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457,\n        10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, 10589, 10597, 10601, 10607,\n        10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733,\n        10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889,\n        10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057,\n        11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173,\n        11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321,\n        11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483,\n        11489, 11491, 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633,\n        11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, 11779, 11783, 11789, 11801,\n        11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927,\n        11933, 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049,\n        12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203,\n        12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343,\n        12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479,\n        12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589,\n        12601, 12611, 12613, 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721,\n        12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, 12841, 12853, 12889, 12893,\n        12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003,\n        13007, 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151,\n        13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297,\n        13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451,\n        13457, 13463, 13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613,\n        13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, 13709, 13711, 13721, 13723,\n        13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877,\n        13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, 13999, 14009, 14011,\n        14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177,\n        14197, 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369,\n        14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503,\n        14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633,\n        14639, 14653, 14657, 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759,\n        14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869, 14879, 14887,\n        14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061,\n        15073, 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, 15187, 15193,\n        15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313,\n        15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443,\n        15451, 15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601,\n        15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, 15683, 15727, 15731, 15733,\n        15737, 15739, 15749, 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877,\n        15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007,\n        16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141,\n        16183, 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, 16333,\n        16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477,\n        16481, 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633,\n        16649, 16651, 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787,\n        16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, 16921, 16927, 16931, 16937,\n        16943, 16963, 16979, 16981, 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077,\n        17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231,\n        17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387,\n        17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497,\n        17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659,\n        17669, 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827,\n        17837, 17839, 17851, 17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959,\n        17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, 18061, 18077, 18089, 18097,\n        18119, 18121, 18127, 18131, 18133, 18143, 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229,\n        18233, 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341, 18353, 18367,\n        18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503,\n        18517, 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691,\n        18701, 18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869,\n        18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, 19013, 19031, 19037, 19051,\n        19069, 19073, 19079, 19081, 19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213,\n        19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, 19333, 19373, 19379, 19381,\n        19387, 19391, 19403, 19417, 19421, 19423, 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471,\n        19477, 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597, 19603,\n        19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777,\n        19793, 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937,\n        19949, 19961, 19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063,\n        20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, 20161, 20173, 20177, 20183,\n        20201, 20219, 20231, 20233, 20249, 20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353,\n        20357, 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477, 20479, 20483, 20507,\n        20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681,\n        20693, 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809,\n        20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981,\n        20983, 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121,\n        21139, 21143, 21149, 21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269,\n        21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, 21391, 21397, 21401, 21407,\n        21419, 21433, 21467, 21481, 21487, 21491, 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559,\n        21563, 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661, 21673, 21683,\n        21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839,\n        21841, 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997,\n        22003, 22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111,\n        22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, 22247, 22259, 22271, 22273,\n        22277, 22279, 22283, 22291, 22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433,\n        22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, 22549, 22567, 22571, 22573,\n        22613, 22619, 22621, 22637, 22639, 22643, 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721,\n        22727, 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861, 22871,\n        22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027,\n        23029, 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159,\n        23167, 23173, 23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311,\n        23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, 23459, 23473, 23497, 23509,\n        23531, 23537, 23539, 23549, 23557, 23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627,\n        23629, 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747, 23753, 23761, 23767,\n        23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899,\n        23909, 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043,\n        24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151,\n        24169, 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359,\n        24371, 24373, 24379, 24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509,\n        24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, 24671, 24677, 24683, 24691,\n        24697, 24709, 24733, 24749, 24763, 24767, 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859,\n        24877, 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989, 25013, 25031,\n        25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171,\n        25183, 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339,\n        25343, 25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469,\n        25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, 25609, 25621, 25633, 25639,\n        25643, 25657, 25667, 25673, 25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793,\n        25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, 25919, 25931, 25933, 25939,\n        25943, 25951, 25969, 25981, 25997, 25999, 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107,\n        26111, 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237, 26249,\n        26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393,\n        26399, 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557,\n        26561, 26573, 26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701,\n        26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, 26813, 26821, 26833, 26839,\n        26849, 26861, 26863, 26879, 26881, 26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981,\n        26987, 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091, 27103, 27107, 27109,\n        27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299,\n        27329, 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487,\n        27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689,\n        27691, 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793,\n        27799, 27803, 27809, 27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943,\n        27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, 28057, 28069, 28081, 28087,\n        28097, 28099, 28109, 28111, 28123, 28151, 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279,\n        28283, 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411, 28429, 28433,\n        28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573,\n        28579, 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669,\n        28687, 28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817,\n        28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, 28949, 28961, 28979, 29009,\n        29017, 29021, 29023, 29027, 29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153,\n        29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, 29269, 29287, 29297, 29303,\n        29311, 29327, 29333, 29339, 29347, 29363, 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437,\n        29443, 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599, 29611,\n        29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803,\n        29819, 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983,\n        29989, 30011, 30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133,\n        30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, 30253, 30259, 30269, 30271,\n        30293, 30307, 30313, 30319, 30323, 30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467,\n        30469, 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577, 30593, 30631, 30637,\n        30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781,\n        30803, 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931,\n        30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081,\n        31091, 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223,\n        31231, 31237, 31247, 31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337,\n        31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, 31513, 31517, 31531, 31541,\n        31543, 31547, 31567, 31573, 31583, 31601, 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699,\n        31721, 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849, 31859, 31873,\n        31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059,\n        32063, 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191,\n        32203, 32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341,\n        32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, 32429, 32441, 32443, 32467,\n        32479, 32491, 32497, 32503, 32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603,\n        32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, 32719, 32749, 32771, 32779,\n        32783, 32789, 32797, 32801, 32803, 32831, 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933,\n        32939, 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049, 33053,\n        33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203,\n        33211, 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359,\n        33377, 33391, 33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529,\n        33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, 33617, 33619, 33623, 33629,\n        33637, 33641, 33647, 33679, 33703, 33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791,\n        33797, 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911, 33923, 33931, 33937,\n        33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147,\n        34157, 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297,\n        34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439,\n        34457, 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589,\n        34591, 34603, 34607, 34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729,\n        34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, 34849, 34871, 34877, 34883,\n        34897, 34913, 34919, 34939, 34949, 34961, 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081,\n        35083, 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201, 35221, 35227,\n        35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393,\n        35401, 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533,\n        35537, 35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753,\n        35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, 35869, 35879, 35897, 35899,\n        35911, 35923, 35933, 35951, 35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037,\n        36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, 36187, 36191, 36209, 36217,\n        36229, 36241, 36251, 36263, 36269, 36277, 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373,\n        36383, 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529, 36541,\n        36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683,\n        36691, 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809,\n        36821, 36833, 36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943,\n        36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, 37061, 37087, 37097, 37117,\n        37123, 37139, 37159, 37171, 37181, 37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307,\n        37309, 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409, 37423, 37441, 37447,\n        37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571,\n        37573, 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717,\n        37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907,\n        37951, 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113,\n        38119, 38149, 38153, 38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273,\n        38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, 38377, 38393, 38431, 38447,\n        38449, 38453, 38459, 38461, 38501, 38543, 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629,\n        38639, 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729, 38737, 38747,\n        38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917,\n        38921, 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089,\n        39097, 39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217,\n        39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, 39341, 39343, 39359, 39367,\n        39371, 39373, 39383, 39397, 39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521,\n        39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, 39671, 39679, 39703, 39709,\n        39719, 39727, 39733, 39749, 39761, 39769, 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847,\n        39857, 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989, 40009,\n        40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163,\n        40169, 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357,\n        40361, 40387, 40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529,\n        40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, 40693, 40697, 40699, 40709,\n        40739, 40751, 40759, 40763, 40771, 40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853,\n        40867, 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993, 41011, 41017, 41023,\n        41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179,\n        41183, 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299,\n        41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491,\n        41507, 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621,\n        41627, 41641, 41647, 41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777,\n        41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, 41903, 41911, 41927, 41941,\n        41947, 41953, 41957, 41959, 41969, 41981, 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071,\n        42073, 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197, 42209, 42221,\n        42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373,\n        42379, 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473,\n        42487, 42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667,\n        42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, 42751, 42767, 42773, 42787,\n        42793, 42797, 42821, 42829, 42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943,\n        42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, 43063, 43067, 43093, 43103,\n        43117, 43133, 43151, 43159, 43177, 43189, 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313,\n        43319, 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487, 43499,\n        43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651,\n        43661, 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801,\n        43853, 43867, 43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997,\n        44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, 44111, 44119, 44123, 44129,\n        44131, 44159, 44171, 44179, 44189, 44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273,\n        44279, 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453, 44483, 44491, 44497,\n        44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633,\n        44641, 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777,\n        44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939,\n        44953, 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127,\n        45131, 45137, 45139, 45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293,\n        45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, 45413, 45427, 45433, 45439,\n        45481, 45491, 45497, 45503, 45523, 45533, 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631,\n        45641, 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767, 45779, 45817,\n        45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971,\n        45979, 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147,\n        46153, 46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307,\n        46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, 46451, 46457, 46471, 46477,\n        46489, 46499, 46507, 46511, 46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639,\n        46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, 46751, 46757, 46769, 46771,\n        46807, 46811, 46817, 46819, 46829, 46831, 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957,\n        46993, 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137, 47143,\n        47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309,\n        47317, 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491,\n        47497, 47501, 47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623,\n        47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, 47737, 47741, 47743, 47777,\n        47779, 47791, 47797, 47807, 47809, 47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933,\n        47939, 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073, 48079, 48091, 48109,\n        48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281,\n        48299, 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463,\n        48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593,\n        48611, 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767,\n        48779, 48781, 48787, 48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889,\n        48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, 49037, 49043, 49057, 49069,\n        49081, 49103, 49109, 49117, 49121, 49123, 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207,\n        49211, 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367, 49369, 49391,\n        49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531,\n        49537, 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697,\n        49711, 49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843,\n        49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, 49991, 49993, 49999, 50021,\n        50023, 50033, 50047, 50051, 50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131,\n        50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, 50287, 50291, 50311, 50321,\n        50329, 50333, 50341, 50359, 50363, 50377, 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497,\n        50503, 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647, 50651,\n        50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857,\n        50867, 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031,\n        51043, 51047, 51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199,\n        51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, 51341, 51343, 51347, 51349,\n        51361, 51383, 51407, 51413, 51419, 51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481,\n        51487, 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599, 51607, 51613, 51631,\n        51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797,\n        51803, 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941,\n        51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121,\n        52127, 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267,\n        52289, 52291, 52301, 52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489,\n        52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, 52583, 52609, 52627, 52631,\n        52639, 52667, 52673, 52691, 52697, 52709, 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807,\n        52813, 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951, 52957, 52963,\n        52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113,\n        53117, 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269,\n        53279, 53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437,\n        53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, 53597, 53609, 53611, 53617,\n        53623, 53629, 53633, 53639, 53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777,\n        53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, 53897, 53899, 53917, 53923,\n        53927, 53939, 53951, 53959, 53987, 53993, 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101,\n        54121, 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293, 54311,\n        54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437,\n        54443, 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577,\n        54581, 54583, 54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727,\n        54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, 54881, 54907, 54917, 54919,\n        54941, 54949, 54959, 54973, 54979, 54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079,\n        55103, 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219, 55229, 55243, 55249,\n        55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441,\n        55457, 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631,\n        55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787,\n        55793, 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901,\n        55903, 55921, 55927, 55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081,\n        56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, 56197, 56207, 56209, 56237,\n        56239, 56249, 56263, 56267, 56269, 56299, 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417,\n        56431, 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519, 56527, 56531,\n        56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701,\n        56711, 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843,\n        56857, 56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983,\n        56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, 57107, 57119, 57131, 57139,\n        57143, 57149, 57163, 57173, 57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271,\n        57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, 57397, 57413, 57427, 57457,\n        57467, 57487, 57493, 57503, 57527, 57529, 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649,\n        57653, 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781, 57787,\n        57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943,\n        57947, 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109,\n        58111, 58129, 58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231,\n        58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, 58391, 58393, 58403, 58411,\n        58417, 58427, 58439, 58441, 58451, 58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579,\n        58601, 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727, 58733, 58741, 58757,\n        58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963,\n        58967, 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083,\n        59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221,\n        59233, 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393,\n        59399, 59407, 59417, 59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539,\n        59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, 59663, 59669, 59671, 59693,\n        59699, 59707, 59723, 59729, 59743, 59747, 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879,\n        59887, 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041, 60077, 60083,\n        60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223,\n        60251, 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413,\n        60427, 60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617,\n        60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, 60727, 60733, 60737, 60757,\n        60761, 60763, 60773, 60779, 60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917,\n        60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, 61051, 61057, 61091, 61099,\n        61121, 61129, 61141, 61151, 61153, 61169, 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331,\n        61333, 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471, 61483,\n        61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627,\n        61631, 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757,\n        61781, 61813, 61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979,\n        61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, 62081, 62099, 62119, 62129,\n        62131, 62137, 62141, 62143, 62171, 62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299,\n        62303, 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467, 62473, 62477, 62483,\n        62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639,\n        62653, 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827,\n        62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987,\n        62989, 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197,\n        63199, 63211, 63241, 63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361,\n        63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, 63467, 63473, 63487, 63493,\n        63499, 63521, 63527, 63533, 63541, 63559, 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629,\n        63647, 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737, 63743, 63761,\n        63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913,\n        63929, 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123,\n        64151, 64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303,\n        64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, 64483, 64489, 64499, 64513,\n        64553, 64567, 64577, 64579, 64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679,\n        64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, 64853, 64871, 64877, 64879,\n        64891, 64901, 64919, 64921, 64927, 64937, 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053,\n        65063, 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173, 65179,\n        65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371,\n        65381, 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, 65519, 65521, 65537, 65539,\n        65543, 65551, 65557, 65563, 65579, 65581, 65587, 65599, 65609, 65617, 65629, 65633, 65647, 65651, 65657,\n        65677, 65687, 65699, 65701, 65707, 65713, 65717, 65719, 65729, 65731, 65761, 65777, 65789, 65809, 65827,\n        65831, 65837, 65839, 65843, 65851, 65867, 65881, 65899, 65921, 65927, 65929, 65951, 65957, 65963, 65981,\n        65983, 65993, 66029, 66037, 66041, 66047, 66067, 66071, 66083, 66089, 66103, 66107, 66109, 66137, 66161,\n        66169, 66173, 66179, 66191, 66221, 66239, 66271, 66293, 66301, 66337, 66343, 66347, 66359, 66361, 66373,\n        66377, 66383, 66403, 66413, 66431, 66449, 66457, 66463, 66467, 66491, 66499, 66509, 66523, 66529, 66533,\n        66541, 66553, 66569, 66571, 66587, 66593, 66601, 66617, 66629, 66643, 66653, 66683, 66697, 66701, 66713,\n        66721, 66733, 66739, 66749, 66751, 66763, 66791, 66797, 66809, 66821, 66841, 66851, 66853, 66863, 66877,\n        66883, 66889, 66919, 66923, 66931, 66943, 66947, 66949, 66959, 66973, 66977, 67003, 67021, 67033, 67043,\n        67049, 67057, 67061, 67073, 67079, 67103, 67121, 67129, 67139, 67141, 67153, 67157, 67169, 67181, 67187,\n        67189, 67211, 67213, 67217, 67219, 67231, 67247, 67261, 67271, 67273, 67289, 67307, 67339, 67343, 67349,\n        67369, 67391, 67399, 67409, 67411, 67421, 67427, 67429, 67433, 67447, 67453, 67477, 67481, 67489, 67493,\n        67499, 67511, 67523, 67531, 67537, 67547, 67559, 67567, 67577, 67579, 67589, 67601, 67607, 67619, 67631,\n        67651, 67679, 67699, 67709, 67723, 67733, 67741, 67751, 67757, 67759, 67763, 67777, 67783, 67789, 67801,\n        67807, 67819, 67829, 67843, 67853, 67867, 67883, 67891, 67901, 67927, 67931, 67933, 67939, 67943, 67957,\n        67961, 67967, 67979, 67987, 67993, 68023, 68041, 68053, 68059, 68071, 68087, 68099, 68111, 68113, 68141,\n        68147, 68161, 68171, 68207, 68209, 68213, 68219, 68227, 68239, 68261, 68279, 68281, 68311, 68329, 68351,\n        68371, 68389, 68399, 68437, 68443, 68447, 68449, 68473, 68477, 68483, 68489, 68491, 68501, 68507, 68521,\n        68531, 68539, 68543, 68567, 68581, 68597, 68611, 68633, 68639, 68659, 68669, 68683, 68687, 68699, 68711,\n        68713, 68729, 68737, 68743, 68749, 68767, 68771, 68777, 68791, 68813, 68819, 68821, 68863, 68879, 68881,\n        68891, 68897, 68899, 68903, 68909, 68917, 68927, 68947, 68963, 68993, 69001, 69011, 69019, 69029, 69031,\n        69061, 69067, 69073, 69109, 69119, 69127, 69143, 69149, 69151, 69163, 69191, 69193, 69197, 69203, 69221,\n        69233, 69239, 69247, 69257, 69259, 69263, 69313, 69317, 69337, 69341, 69371, 69379, 69383, 69389, 69401,\n        69403, 69427, 69431, 69439, 69457, 69463, 69467, 69473, 69481, 69491, 69493, 69497, 69499, 69539, 69557,\n        69593, 69623, 69653, 69661, 69677, 69691, 69697, 69709, 69737, 69739, 69761, 69763, 69767, 69779, 69809,\n        69821, 69827, 69829, 69833, 69847, 69857, 69859, 69877, 69899, 69911, 69929, 69931, 69941, 69959, 69991,\n        69997, 70001, 70003, 70009, 70019, 70039, 70051, 70061, 70067, 70079, 70099, 70111, 70117, 70121, 70123,\n        70139, 70141, 70157, 70163, 70177, 70181, 70183, 70199, 70201, 70207, 70223, 70229, 70237, 70241, 70249,\n        70271, 70289, 70297, 70309, 70313, 70321, 70327, 70351, 70373, 70379, 70381, 70393, 70423, 70429, 70439,\n        70451, 70457, 70459, 70481, 70487, 70489, 70501, 70507, 70529, 70537, 70549, 70571, 70573, 70583, 70589,\n        70607, 70619, 70621, 70627, 70639, 70657, 70663, 70667, 70687, 70709, 70717, 70729, 70753, 70769, 70783,\n        70793, 70823, 70841, 70843, 70849, 70853, 70867, 70877, 70879, 70891, 70901, 70913, 70919, 70921, 70937,\n        70949, 70951, 70957, 70969, 70979, 70981, 70991, 70997, 70999, 71011, 71023, 71039, 71059, 71069, 71081,\n        71089, 71119, 71129, 71143, 71147, 71153, 71161, 71167, 71171, 71191, 71209, 71233, 71237, 71249, 71257,\n        71261, 71263, 71287, 71293, 71317, 71327, 71329, 71333, 71339, 71341, 71347, 71353, 71359, 71363, 71387,\n        71389, 71399, 71411, 71413, 71419, 71429, 71437, 71443, 71453, 71471, 71473, 71479, 71483, 71503, 71527,\n        71537, 71549, 71551, 71563, 71569, 71593, 71597, 71633, 71647, 71663, 71671, 71693, 71699, 71707, 71711,\n        71713, 71719, 71741, 71761, 71777, 71789, 71807, 71809, 71821, 71837, 71843, 71849, 71861, 71867, 71879,\n        71881, 71887, 71899, 71909, 71917, 71933, 71941, 71947, 71963, 71971, 71983, 71987, 71993, 71999, 72019,\n        72031, 72043, 72047, 72053, 72073, 72077, 72089, 72091, 72101, 72103, 72109, 72139, 72161, 72167, 72169,\n        72173, 72211, 72221, 72223, 72227, 72229, 72251, 72253, 72269, 72271, 72277, 72287, 72307, 72313, 72337,\n        72341, 72353, 72367, 72379, 72383, 72421, 72431, 72461, 72467, 72469, 72481, 72493, 72497, 72503, 72533,\n        72547, 72551, 72559, 72577, 72613, 72617, 72623, 72643, 72647, 72649, 72661, 72671, 72673, 72679, 72689,\n        72701, 72707, 72719, 72727, 72733, 72739, 72763, 72767, 72797, 72817, 72823, 72859, 72869, 72871, 72883,\n        72889, 72893, 72901, 72907, 72911, 72923, 72931, 72937, 72949, 72953, 72959, 72973, 72977, 72997, 73009,\n        73013, 73019, 73037, 73039, 73043, 73061, 73063, 73079, 73091, 73121, 73127, 73133, 73141, 73181, 73189,\n        73237, 73243, 73259, 73277, 73291, 73303, 73309, 73327, 73331, 73351, 73361, 73363, 73369, 73379, 73387,\n        73417, 73421, 73433, 73453, 73459, 73471, 73477, 73483, 73517, 73523, 73529, 73547, 73553, 73561, 73571,\n        73583, 73589, 73597, 73607, 73609, 73613, 73637, 73643, 73651, 73673, 73679, 73681, 73693, 73699, 73709,\n        73721, 73727, 73751, 73757, 73771, 73783, 73819, 73823, 73847, 73849, 73859, 73867, 73877, 73883, 73897,\n        73907, 73939, 73943, 73951, 73961, 73973, 73999, 74017, 74021, 74027, 74047, 74051, 74071, 74077, 74093,\n        74099, 74101, 74131, 74143, 74149, 74159, 74161, 74167, 74177, 74189, 74197, 74201, 74203, 74209, 74219,\n        74231, 74257, 74279, 74287, 74293, 74297, 74311, 74317, 74323, 74353, 74357, 74363, 74377, 74381, 74383,\n        74411, 74413, 74419, 74441, 74449, 74453, 74471, 74489, 74507, 74509, 74521, 74527, 74531, 74551, 74561,\n        74567, 74573, 74587, 74597, 74609, 74611, 74623, 74653, 74687, 74699, 74707, 74713, 74717, 74719, 74729,\n        74731, 74747, 74759, 74761, 74771, 74779, 74797, 74821, 74827, 74831, 74843, 74857, 74861, 74869, 74873,\n        74887, 74891, 74897, 74903, 74923, 74929, 74933, 74941, 74959, 75011, 75013, 75017, 75029, 75037, 75041,\n        75079, 75083, 75109, 75133, 75149, 75161, 75167, 75169, 75181, 75193, 75209, 75211, 75217, 75223, 75227,\n        75239, 75253, 75269, 75277, 75289, 75307, 75323, 75329, 75337, 75347, 75353, 75367, 75377, 75389, 75391,\n        75401, 75403, 75407, 75431, 75437, 75479, 75503, 75511, 75521, 75527, 75533, 75539, 75541, 75553, 75557,\n        75571, 75577, 75583, 75611, 75617, 75619, 75629, 75641, 75653, 75659, 75679, 75683, 75689, 75703, 75707,\n        75709, 75721, 75731, 75743, 75767, 75773, 75781, 75787, 75793, 75797, 75821, 75833, 75853, 75869, 75883,\n        75913, 75931, 75937, 75941, 75967, 75979, 75983, 75989, 75991, 75997, 76001, 76003, 76031, 76039, 76079,\n        76081, 76091, 76099, 76103, 76123, 76129, 76147, 76157, 76159, 76163, 76207, 76213, 76231, 76243, 76249,\n        76253, 76259, 76261, 76283, 76289, 76303, 76333, 76343, 76367, 76369, 76379, 76387, 76403, 76421, 76423,\n        76441, 76463, 76471, 76481, 76487, 76493, 76507, 76511, 76519, 76537, 76541, 76543, 76561, 76579, 76597,\n        76603, 76607, 76631, 76649, 76651, 76667, 76673, 76679, 76697, 76717, 76733, 76753, 76757, 76771, 76777,\n        76781, 76801, 76819, 76829, 76831, 76837, 76847, 76871, 76873, 76883, 76907, 76913, 76919, 76943, 76949,\n        76961, 76963, 76991, 77003, 77017, 77023, 77029, 77041, 77047, 77069, 77081, 77093, 77101, 77137, 77141,\n        77153, 77167, 77171, 77191, 77201, 77213, 77237, 77239, 77243, 77249, 77261, 77263, 77267, 77269, 77279,\n        77291, 77317, 77323, 77339, 77347, 77351, 77359, 77369, 77377, 77383, 77417, 77419, 77431, 77447, 77471,\n        77477, 77479, 77489, 77491, 77509, 77513, 77521, 77527, 77543, 77549, 77551, 77557, 77563, 77569, 77573,\n        77587, 77591, 77611, 77617, 77621, 77641, 77647, 77659, 77681, 77687, 77689, 77699, 77711, 77713, 77719,\n        77723, 77731, 77743, 77747, 77761, 77773, 77783, 77797, 77801, 77813, 77839, 77849, 77863, 77867, 77893,\n        77899, 77929, 77933, 77951, 77969, 77977, 77983, 77999, 78007, 78017, 78031, 78041, 78049, 78059, 78079,\n        78101, 78121, 78137, 78139, 78157, 78163, 78167, 78173, 78179, 78191, 78193, 78203, 78229, 78233, 78241,\n        78259, 78277, 78283, 78301, 78307, 78311, 78317, 78341, 78347, 78367, 78401, 78427, 78437, 78439, 78467,\n        78479, 78487, 78497, 78509, 78511, 78517, 78539, 78541, 78553, 78569, 78571, 78577, 78583, 78593, 78607,\n        78623, 78643, 78649, 78653, 78691, 78697, 78707, 78713, 78721, 78737, 78779, 78781, 78787, 78791, 78797,\n        78803, 78809, 78823, 78839, 78853, 78857, 78877, 78887, 78889, 78893, 78901, 78919, 78929, 78941, 78977,\n        78979, 78989, 79031, 79039, 79043, 79063, 79087, 79103, 79111, 79133, 79139, 79147, 79151, 79153, 79159,\n        79181, 79187, 79193, 79201, 79229, 79231, 79241, 79259, 79273, 79279, 79283, 79301, 79309, 79319, 79333,\n        79337, 79349, 79357, 79367, 79379, 79393, 79397, 79399, 79411, 79423, 79427, 79433, 79451, 79481, 79493,\n        79531, 79537, 79549, 79559, 79561, 79579, 79589, 79601, 79609, 79613, 79621, 79627, 79631, 79633, 79657,\n        79669, 79687, 79691, 79693, 79697, 79699, 79757, 79769, 79777, 79801, 79811, 79813, 79817, 79823, 79829,\n        79841, 79843, 79847, 79861, 79867, 79873, 79889, 79901, 79903, 79907, 79939, 79943, 79967, 79973, 79979,\n        79987, 79997, 79999, 80021, 80039, 80051, 80071, 80077, 80107, 80111, 80141, 80147, 80149, 80153, 80167,\n        80173, 80177, 80191, 80207, 80209, 80221, 80231, 80233, 80239, 80251, 80263, 80273, 80279, 80287, 80309,\n        80317, 80329, 80341, 80347, 80363, 80369, 80387, 80407, 80429, 80447, 80449, 80471, 80473, 80489, 80491,\n        80513, 80527, 80537, 80557, 80567, 80599, 80603, 80611, 80621, 80627, 80629, 80651, 80657, 80669, 80671,\n        80677, 80681, 80683, 80687, 80701, 80713, 80737, 80747, 80749, 80761, 80777, 80779, 80783, 80789, 80803,\n        80809, 80819, 80831, 80833, 80849, 80863, 80897, 80909, 80911, 80917, 80923, 80929, 80933, 80953, 80963,\n        80989, 81001, 81013, 81017, 81019, 81023, 81031, 81041, 81043, 81047, 81049, 81071, 81077, 81083, 81097,\n        81101, 81119, 81131, 81157, 81163, 81173, 81181, 81197, 81199, 81203, 81223, 81233, 81239, 81281, 81283,\n        81293, 81299, 81307, 81331, 81343, 81349, 81353, 81359, 81371, 81373, 81401, 81409, 81421, 81439, 81457,\n        81463, 81509, 81517, 81527, 81533, 81547, 81551, 81553, 81559, 81563, 81569, 81611, 81619, 81629, 81637,\n        81647, 81649, 81667, 81671, 81677, 81689, 81701, 81703, 81707, 81727, 81737, 81749, 81761, 81769, 81773,\n        81799, 81817, 81839, 81847, 81853, 81869, 81883, 81899, 81901, 81919, 81929, 81931, 81937, 81943, 81953,\n        81967, 81971, 81973, 82003, 82007, 82009, 82013, 82021, 82031, 82037, 82039, 82051, 82067, 82073, 82129,\n        82139, 82141, 82153, 82163, 82171, 82183, 82189, 82193, 82207, 82217, 82219, 82223, 82231, 82237, 82241,\n        82261, 82267, 82279, 82301, 82307, 82339, 82349, 82351, 82361, 82373, 82387, 82393, 82421, 82457, 82463,\n        82469, 82471, 82483, 82487, 82493, 82499, 82507, 82529, 82531, 82549, 82559, 82561, 82567, 82571, 82591,\n        82601, 82609, 82613, 82619, 82633, 82651, 82657, 82699, 82721, 82723, 82727, 82729, 82757, 82759, 82763,\n        82781, 82787, 82793, 82799, 82811, 82813, 82837, 82847, 82883, 82889, 82891, 82903, 82913, 82939, 82963,\n        82981, 82997, 83003, 83009, 83023, 83047, 83059, 83063, 83071, 83077, 83089, 83093, 83101, 83117, 83137,\n        83177, 83203, 83207, 83219, 83221, 83227, 83231, 83233, 83243, 83257, 83267, 83269, 83273, 83299, 83311,\n        83339, 83341, 83357, 83383, 83389, 83399, 83401, 83407, 83417, 83423, 83431, 83437, 83443, 83449, 83459,\n        83471, 83477, 83497, 83537, 83557, 83561, 83563, 83579, 83591, 83597, 83609, 83617, 83621, 83639, 83641,\n        83653, 83663, 83689, 83701, 83717, 83719, 83737, 83761, 83773, 83777, 83791, 83813, 83833, 83843, 83857,\n        83869, 83873, 83891, 83903, 83911, 83921, 83933, 83939, 83969, 83983, 83987, 84011, 84017, 84047, 84053,\n        84059, 84061, 84067, 84089, 84121, 84127, 84131, 84137, 84143, 84163, 84179, 84181, 84191, 84199, 84211,\n        84221, 84223, 84229, 84239, 84247, 84263, 84299, 84307, 84313, 84317, 84319, 84347, 84349, 84377, 84389,\n        84391, 84401, 84407, 84421, 84431, 84437, 84443, 84449, 84457, 84463, 84467, 84481, 84499, 84503, 84509,\n        84521, 84523, 84533, 84551, 84559, 84589, 84629, 84631, 84649, 84653, 84659, 84673, 84691, 84697, 84701,\n        84713, 84719, 84731, 84737, 84751, 84761, 84787, 84793, 84809, 84811, 84827, 84857, 84859, 84869, 84871,\n        84913, 84919, 84947, 84961, 84967, 84977, 84979, 84991, 85009, 85021, 85027, 85037, 85049, 85061, 85081,\n        85087, 85091, 85093, 85103, 85109, 85121, 85133, 85147, 85159, 85193, 85199, 85201, 85213, 85223, 85229,\n        85237, 85243, 85247, 85259, 85297, 85303, 85313, 85331, 85333, 85361, 85363, 85369, 85381, 85411, 85427,\n        85429, 85439, 85447, 85451, 85453, 85469, 85487, 85513, 85517, 85523, 85531, 85549, 85571, 85577, 85597,\n        85601, 85607, 85619, 85621, 85627, 85639, 85643, 85661, 85667, 85669, 85691, 85703, 85711, 85717, 85733,\n        85751, 85781, 85793, 85817, 85819, 85829, 85831, 85837, 85843, 85847, 85853, 85889, 85903, 85909, 85931,\n        85933, 85991, 85999, 86011, 86017, 86027, 86029, 86069, 86077, 86083, 86111, 86113, 86117, 86131, 86137,\n        86143, 86161, 86171, 86179, 86183, 86197, 86201, 86209, 86239, 86243, 86249, 86257, 86263, 86269, 86287,\n        86291, 86293, 86297, 86311, 86323, 86341, 86351, 86353, 86357, 86369, 86371, 86381, 86389, 86399, 86413,\n        86423, 86441, 86453, 86461, 86467, 86477, 86491, 86501, 86509, 86531, 86533, 86539, 86561, 86573, 86579,\n        86587, 86599, 86627, 86629, 86677, 86689, 86693, 86711, 86719, 86729, 86743, 86753, 86767, 86771, 86783,\n        86813, 86837, 86843, 86851, 86857, 86861, 86869, 86923, 86927, 86929, 86939, 86951, 86959, 86969, 86981,\n        86993, 87011, 87013, 87037, 87041, 87049, 87071, 87083, 87103, 87107, 87119, 87121, 87133, 87149, 87151,\n        87179, 87181, 87187, 87211, 87221, 87223, 87251, 87253, 87257, 87277, 87281, 87293, 87299, 87313, 87317,\n        87323, 87337, 87359, 87383, 87403, 87407, 87421, 87427, 87433, 87443, 87473, 87481, 87491, 87509, 87511,\n        87517, 87523, 87539, 87541, 87547, 87553, 87557, 87559, 87583, 87587, 87589, 87613, 87623, 87629, 87631,\n        87641, 87643, 87649, 87671, 87679, 87683, 87691, 87697, 87701, 87719, 87721, 87739, 87743, 87751, 87767,\n        87793, 87797, 87803, 87811, 87833, 87853, 87869, 87877, 87881, 87887, 87911, 87917, 87931, 87943, 87959,\n        87961, 87973, 87977, 87991, 88001, 88003, 88007, 88019, 88037, 88069, 88079, 88093, 88117, 88129, 88169,\n        88177, 88211, 88223, 88237, 88241, 88259, 88261, 88289, 88301, 88321, 88327, 88337, 88339, 88379, 88397,\n        88411, 88423, 88427, 88463, 88469, 88471, 88493, 88499, 88513, 88523, 88547, 88589, 88591, 88607, 88609,\n        88643, 88651, 88657, 88661, 88663, 88667, 88681, 88721, 88729, 88741, 88747, 88771, 88789, 88793, 88799,\n        88801, 88807, 88811, 88813, 88817, 88819, 88843, 88853, 88861, 88867, 88873, 88883, 88897, 88903, 88919,\n        88937, 88951, 88969, 88993, 88997, 89003, 89009, 89017, 89021, 89041, 89051, 89057, 89069, 89071, 89083,\n        89087, 89101, 89107, 89113, 89119, 89123, 89137, 89153, 89189, 89203, 89209, 89213, 89227, 89231, 89237,\n        89261, 89269, 89273, 89293, 89303, 89317, 89329, 89363, 89371, 89381, 89387, 89393, 89399, 89413, 89417,\n        89431, 89443, 89449, 89459, 89477, 89491, 89501, 89513, 89519, 89521, 89527, 89533, 89561, 89563, 89567,\n        89591, 89597, 89599, 89603, 89611, 89627, 89633, 89653, 89657, 89659, 89669, 89671, 89681, 89689, 89753,\n        89759, 89767, 89779, 89783, 89797, 89809, 89819, 89821, 89833, 89839, 89849, 89867, 89891, 89897, 89899,\n        89909, 89917, 89923, 89939, 89959, 89963, 89977, 89983, 89989, 90001, 90007, 90011, 90017, 90019, 90023,\n        90031, 90053, 90059, 90067, 90071, 90073, 90089, 90107, 90121, 90127, 90149, 90163, 90173, 90187, 90191,\n        90197, 90199, 90203, 90217, 90227, 90239, 90247, 90263, 90271, 90281, 90289, 90313, 90353, 90359, 90371,\n        90373, 90379, 90397, 90401, 90403, 90407, 90437, 90439, 90469, 90473, 90481, 90499, 90511, 90523, 90527,\n        90529, 90533, 90547, 90583, 90599, 90617, 90619, 90631, 90641, 90647, 90659, 90677, 90679, 90697, 90703,\n        90709, 90731, 90749, 90787, 90793, 90803, 90821, 90823, 90833, 90841, 90847, 90863, 90887, 90901, 90907,\n        90911, 90917, 90931, 90947, 90971, 90977, 90989, 90997, 91009, 91019, 91033, 91079, 91081, 91097, 91099,\n        91121, 91127, 91129, 91139, 91141, 91151, 91153, 91159, 91163, 91183, 91193, 91199, 91229, 91237, 91243,\n        91249, 91253, 91283, 91291, 91297, 91303, 91309, 91331, 91367, 91369, 91373, 91381, 91387, 91393, 91397,\n        91411, 91423, 91433, 91453, 91457, 91459, 91463, 91493, 91499, 91513, 91529, 91541, 91571, 91573, 91577,\n        91583, 91591, 91621, 91631, 91639, 91673, 91691, 91703, 91711, 91733, 91753, 91757, 91771, 91781, 91801,\n        91807, 91811, 91813, 91823, 91837, 91841, 91867, 91873, 91909, 91921, 91939, 91943, 91951, 91957, 91961,\n        91967, 91969, 91997, 92003, 92009, 92033, 92041, 92051, 92077, 92083, 92107, 92111, 92119, 92143, 92153,\n        92173, 92177, 92179, 92189, 92203, 92219, 92221, 92227, 92233, 92237, 92243, 92251, 92269, 92297, 92311,\n        92317, 92333, 92347, 92353, 92357, 92363, 92369, 92377, 92381, 92383, 92387, 92399, 92401, 92413, 92419,\n        92431, 92459, 92461, 92467, 92479, 92489, 92503, 92507, 92551, 92557, 92567, 92569, 92581, 92593, 92623,\n        92627, 92639, 92641, 92647, 92657, 92669, 92671, 92681, 92683, 92693, 92699, 92707, 92717, 92723, 92737,\n        92753, 92761, 92767, 92779, 92789, 92791, 92801, 92809, 92821, 92831, 92849, 92857, 92861, 92863, 92867,\n        92893, 92899, 92921, 92927, 92941, 92951, 92957, 92959, 92987, 92993, 93001, 93047, 93053, 93059, 93077,\n        93083, 93089, 93097, 93103, 93113, 93131, 93133, 93139, 93151, 93169, 93179, 93187, 93199, 93229, 93239,\n        93241, 93251, 93253, 93257, 93263, 93281, 93283, 93287, 93307, 93319, 93323, 93329, 93337, 93371, 93377,\n        93383, 93407, 93419, 93427, 93463, 93479, 93481, 93487, 93491, 93493, 93497, 93503, 93523, 93529, 93553,\n        93557, 93559, 93563, 93581, 93601, 93607, 93629, 93637, 93683, 93701, 93703, 93719, 93739, 93761, 93763,\n        93787, 93809, 93811, 93827, 93851, 93871, 93887, 93889, 93893, 93901, 93911, 93913, 93923, 93937, 93941,\n        93949, 93967, 93971, 93979, 93983, 93997, 94007, 94009, 94033, 94049, 94057, 94063, 94079, 94099, 94109,\n        94111, 94117, 94121, 94151, 94153, 94169, 94201, 94207, 94219, 94229, 94253, 94261, 94273, 94291, 94307,\n        94309, 94321, 94327, 94331, 94343, 94349, 94351, 94379, 94397, 94399, 94421, 94427, 94433, 94439, 94441,\n        94447, 94463, 94477, 94483, 94513, 94529, 94531, 94541, 94543, 94547, 94559, 94561, 94573, 94583, 94597,\n        94603, 94613, 94621, 94649, 94651, 94687, 94693, 94709, 94723, 94727, 94747, 94771, 94777, 94781, 94789,\n        94793, 94811, 94819, 94823, 94837, 94841, 94847, 94849, 94873, 94889, 94903, 94907, 94933, 94949, 94951,\n        94961, 94993, 94999, 95003, 95009, 95021, 95027, 95063, 95071, 95083, 95087, 95089, 95093, 95101, 95107,\n        95111, 95131, 95143, 95153, 95177, 95189, 95191, 95203, 95213, 95219, 95231, 95233, 95239, 95257, 95261,\n        95267, 95273, 95279, 95287, 95311, 95317, 95327, 95339, 95369, 95383, 95393, 95401, 95413, 95419, 95429,\n        95441, 95443, 95461, 95467, 95471, 95479, 95483, 95507, 95527, 95531, 95539, 95549, 95561, 95569, 95581,\n        95597, 95603, 95617, 95621, 95629, 95633, 95651, 95701, 95707, 95713, 95717, 95723, 95731, 95737, 95747,\n        95773, 95783, 95789, 95791, 95801, 95803, 95813, 95819, 95857, 95869, 95873, 95881, 95891, 95911, 95917,\n        95923, 95929, 95947, 95957, 95959, 95971, 95987, 95989, 96001, 96013, 96017, 96043, 96053, 96059, 96079,\n        96097, 96137, 96149, 96157, 96167, 96179, 96181, 96199, 96211, 96221, 96223, 96233, 96259, 96263, 96269,\n        96281, 96289, 96293, 96323, 96329, 96331, 96337, 96353, 96377, 96401, 96419, 96431, 96443, 96451, 96457,\n        96461, 96469, 96479, 96487, 96493, 96497, 96517, 96527, 96553, 96557, 96581, 96587, 96589, 96601, 96643,\n        96661, 96667, 96671, 96697, 96703, 96731, 96737, 96739, 96749, 96757, 96763, 96769, 96779, 96787, 96797,\n        96799, 96821, 96823, 96827, 96847, 96851, 96857, 96893, 96907, 96911, 96931, 96953, 96959, 96973, 96979,\n        96989, 96997, 97001, 97003, 97007, 97021, 97039, 97073, 97081, 97103, 97117, 97127, 97151, 97157, 97159,\n        97169, 97171, 97177, 97187, 97213, 97231, 97241, 97259, 97283, 97301, 97303, 97327, 97367, 97369, 97373,\n        97379, 97381, 97387, 97397, 97423, 97429, 97441, 97453, 97459, 97463, 97499, 97501, 97511, 97523, 97547,\n        97549, 97553, 97561, 97571, 97577, 97579, 97583, 97607, 97609, 97613, 97649, 97651, 97673, 97687, 97711,\n        97729, 97771, 97777, 97787, 97789, 97813, 97829, 97841, 97843, 97847, 97849, 97859, 97861, 97871, 97879,\n        97883, 97919, 97927, 97931, 97943, 97961, 97967, 97973, 97987, 98009, 98011, 98017, 98041, 98047, 98057,\n        98081, 98101, 98123, 98129, 98143, 98179, 98207, 98213, 98221, 98227, 98251, 98257, 98269, 98297, 98299,\n        98317, 98321, 98323, 98327, 98347, 98369, 98377, 98387, 98389, 98407, 98411, 98419, 98429, 98443, 98453,\n        98459, 98467, 98473, 98479, 98491, 98507, 98519, 98533, 98543, 98561, 98563, 98573, 98597, 98621, 98627,\n        98639, 98641, 98663, 98669, 98689, 98711, 98713, 98717, 98729, 98731, 98737, 98773, 98779, 98801, 98807,\n        98809, 98837, 98849, 98867, 98869, 98873, 98887, 98893, 98897, 98899, 98909, 98911, 98927, 98929, 98939,\n        98947, 98953, 98963, 98981, 98993, 98999, 99013, 99017, 99023, 99041, 99053, 99079, 99083, 99089, 99103,\n        99109, 99119, 99131, 99133, 99137, 99139, 99149, 99173, 99181, 99191, 99223, 99233, 99241, 99251, 99257,\n        99259, 99277, 99289, 99317, 99347, 99349, 99367, 99371, 99377, 99391, 99397, 99401, 99409, 99431, 99439,\n        99469, 99487, 99497, 99523, 99527, 99529, 99551, 99559, 99563, 99571, 99577, 99581, 99607, 99611, 99623,\n        99643, 99661, 99667, 99679, 99689, 99707, 99709, 99713, 99719, 99721, 99733, 99761, 99767, 99787, 99793,\n        99809, 99817, 99823, 99829, 99833, 99839, 99859, 99871, 99877, 99881, 99901, 99907, 99923, 99929, 99961,\n        99971, 99989, 99991, 100003, 100019, 100043, 100049, 100057, 100069, 100103, 100109, 100129, 100151, 100153,\n        100169, 100183, 100189, 100193, 100207, 100213, 100237, 100267, 100271, 100279, 100291, 100297, 100313,\n        100333, 100343, 100357, 100361, 100363, 100379, 100391, 100393, 100403, 100411, 100417, 100447, 100459,\n        100469, 100483, 100493, 100501, 100511, 100517, 100519, 100523, 100537, 100547, 100549, 100559, 100591,\n        100609, 100613, 100621, 100649, 100669, 100673, 100693, 100699, 100703, 100733, 100741, 100747, 100769,\n        100787, 100799, 100801, 100811, 100823, 100829, 100847, 100853, 100907, 100913, 100927, 100931, 100937,\n        100943, 100957, 100981, 100987, 100999, 101009, 101021, 101027, 101051, 101063, 101081, 101089, 101107,\n        101111, 101113, 101117, 101119, 101141, 101149, 101159, 101161, 101173, 101183, 101197, 101203, 101207,\n        101209, 101221, 101267, 101273, 101279, 101281, 101287, 101293, 101323, 101333, 101341, 101347, 101359,\n        101363, 101377, 101383, 101399, 101411, 101419, 101429, 101449, 101467, 101477, 101483, 101489, 101501,\n        101503, 101513, 101527, 101531, 101533, 101537, 101561, 101573, 101581, 101599, 101603, 101611, 101627,\n        101641, 101653, 101663, 101681, 101693, 101701, 101719, 101723, 101737, 101741, 101747, 101749, 101771,\n        101789, 101797, 101807, 101833, 101837, 101839, 101863, 101869, 101873, 101879, 101891, 101917, 101921,\n        101929, 101939, 101957, 101963, 101977, 101987, 101999, 102001, 102013, 102019, 102023, 102031, 102043,\n        102059, 102061, 102071, 102077, 102079, 102101, 102103, 102107, 102121, 102139, 102149, 102161, 102181,\n        102191, 102197, 102199, 102203, 102217, 102229, 102233, 102241, 102251, 102253, 102259, 102293, 102299,\n        102301, 102317, 102329, 102337, 102359, 102367, 102397, 102407, 102409, 102433, 102437, 102451, 102461,\n        102481, 102497, 102499, 102503, 102523, 102533, 102539, 102547, 102551, 102559, 102563, 102587, 102593,\n        102607, 102611, 102643, 102647, 102653, 102667, 102673, 102677, 102679, 102701, 102761, 102763, 102769,\n        102793, 102797, 102811, 102829, 102841, 102859, 102871, 102877, 102881, 102911, 102913, 102929, 102931,\n        102953, 102967, 102983, 103001, 103007, 103043, 103049, 103067, 103069, 103079, 103087, 103091, 103093,\n        103099, 103123, 103141, 103171, 103177, 103183, 103217, 103231, 103237, 103289, 103291, 103307, 103319,\n        103333, 103349, 103357, 103387, 103391, 103393, 103399, 103409, 103421, 103423, 103451, 103457, 103471,\n        103483, 103511, 103529, 103549, 103553, 103561, 103567, 103573, 103577, 103583, 103591, 103613, 103619,\n        103643, 103651, 103657, 103669, 103681, 103687, 103699, 103703, 103723, 103769, 103787, 103801, 103811,\n        103813, 103837, 103841, 103843, 103867, 103889, 103903, 103913, 103919, 103951, 103963, 103967, 103969,\n        103979, 103981, 103991, 103993, 103997, 104003, 104009, 104021, 104033, 104047, 104053, 104059, 104087,\n        104089, 104107, 104113, 104119, 104123, 104147, 104149, 104161, 104173, 104179, 104183, 104207, 104231,\n        104233, 104239, 104243, 104281, 104287, 104297, 104309, 104311, 104323, 104327, 104347, 104369, 104381,\n        104383, 104393, 104399, 104417, 104459, 104471, 104473, 104479, 104491, 104513, 104527, 104537, 104543,\n        104549, 104551, 104561, 104579, 104593, 104597, 104623, 104639, 104651, 104659, 104677, 104681, 104683,\n        104693, 104701, 104707, 104711, 104717, 104723, 104729,\n    ];\n\n    [Test]\n    public static void First10_000PrimesCorrect() =>\n        Assert.That(new SieveOfEratosthenes(104729).GetPrimes(), Is.EqualTo(First10000PrimeNumbers));\n\n    [Test]\n    public static void TestMaxNumber() => Assert.That(new SieveOfEratosthenes(69).MaximumNumber, Is.EqualTo(69));\n\n    [TestCase(13, true)]\n    [TestCase(10, false)]\n    public static void TestIsPrime(int input, bool expected)\n    {\n        Assert.That(expected, Is.EqualTo(new SieveOfEratosthenes(100).IsPrime(input)));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/TriangulatorTests.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other\n{\n    [TestFixture]\n    public class TriangulatorTests\n    {\n        [Test]\n        public void CalculatePosition_ValidCoordinatesAndDistances_ReturnsExpectedPosition()\n        {\n            var triangulator = new Triangulator();\n            var baseLocations = new List<(double Latitude, double Longitude)>\n            {\n                (16.054407, 108.202167),\n                (16.049807, 108.218991),\n                (16.063597, 108.215553)\n            };\n\n            var distances = new List<double> { 0.5, 0.7, 0.6 };\n\n            var expectedPosition = (Latitude: 16.054, Longitude: 108.210);\n            var result = triangulator.CalculatePosition(baseLocations, distances);\n\n            Assert.That(result.Latitude, Is.EqualTo(expectedPosition.Latitude).Within(0.01));\n            Assert.That(result.Longitude, Is.EqualTo(expectedPosition.Longitude).Within(0.01));\n        }\n\n        [Test]\n        public void CalculatePosition_InvalidBaseLocations_ThrowsArgumentException()\n        {\n            var triangulator = new Triangulator();\n            var baseLocations = new List<(double Latitude, double Longitude)>\n        {\n            (10.762622, 106.660172)\n        };\n            var distances = new List<double> { 1.0 };\n\n            Assert.That(() => triangulator.CalculatePosition(baseLocations, distances), Throws.ArgumentException);\n        }\n\n        [Test]\n        public void CalculatePosition_InvalidDistances_ThrowsArgumentException()\n        {\n            var triangulator = new Triangulator();\n            var baseLocations = new List<(double Latitude, double Longitude)>\n        {\n            (10.762622, 106.660172),\n            (10.774981, 106.665504),\n            (10.771817, 106.681179)\n        };\n            var distances = new List<double> { 1.0 };\n\n            Assert.That(() => triangulator.CalculatePosition(baseLocations, distances), Throws.ArgumentException);\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Other/WelfordsVarianceTest.cs",
    "content": "using Algorithms.Other;\n\nnamespace Algorithms.Tests.Other;\n\npublic class WelfordsVarianceTest\n{\n    [Test]\n    public void WelfordVariance_Example1()\n    {\n        var welfordsVariance = new WelfordsVariance();\n        welfordsVariance.AddValue(4);\n        welfordsVariance.AddValue(7);\n        welfordsVariance.AddValue(13);\n        welfordsVariance.AddValue(16);\n\n        Assert.That(welfordsVariance.Count, Is.EqualTo(4));\n        Assert.That(welfordsVariance.Mean, Is.EqualTo(10).Within(0.0000001));\n        Assert.That(welfordsVariance.Variance, Is.EqualTo(22.5).Within(0.0000001));\n        Assert.That(welfordsVariance.SampleVariance, Is.EqualTo(30).Within(0.0000001));\n    }\n\n    [Test]\n    public void WelfordVariance_Example2()\n    {\n        var stats = new WelfordsVariance();\n        stats.AddValue(100000004);\n        stats.AddValue(100000007);\n        stats.AddValue(100000013);\n        stats.AddValue(100000016);\n        Assert.That(stats.Count, Is.EqualTo(4));\n        Assert.That(stats.Mean, Is.EqualTo(100000010).Within(0.0000001));\n        Assert.That(stats.Variance, Is.EqualTo(22.5).Within(0.0000001));\n        Assert.That(stats.SampleVariance, Is.EqualTo(30).Within(0.0000001));\n    }\n\n    [Test]\n    public void WelfordVariance_Example3()\n    {\n        var stats = new WelfordsVariance();\n        stats.AddValue(1000000004);\n        stats.AddValue(1000000007);\n        stats.AddValue(1000000013);\n        stats.AddValue(1000000016);\n        Assert.That(stats.Count, Is.EqualTo(4));\n        Assert.That(stats.Mean, Is.EqualTo(1000000010).Within(0.0000001));\n        Assert.That(stats.Variance, Is.EqualTo(22.5).Within(0.0000001));\n        Assert.That(stats.SampleVariance, Is.EqualTo(30).Within(0.0000001));\n    }\n\n    [Test]\n    public void WelfordVariance_Example4()\n    {\n        var stats = new WelfordsVariance();\n        stats.AddValue(6);\n        stats.AddValue(2);\n        stats.AddValue(3);\n        stats.AddValue(1);\n        Assert.That(stats.Count, Is.EqualTo(4));\n        Assert.That(stats.Mean, Is.EqualTo(3).Within(0.0000001));\n        Assert.That(stats.Variance, Is.EqualTo(3.5).Within(0.0000001));\n        Assert.That(stats.SampleVariance, Is.EqualTo(4.6666667).Within(0.0000001));\n    }\n\n    [Test]\n    public void WelfordVariance_Example5()\n    {\n        var stats = new WelfordsVariance([2, 2, 5, 7]);\n        Assert.That(stats.Count, Is.EqualTo(4));\n        Assert.That(stats.Mean, Is.EqualTo(4).Within(0.0000001));\n        Assert.That(stats.Variance, Is.EqualTo(4.5).Within(0.0000001));\n        Assert.That(stats.SampleVariance, Is.EqualTo(6).Within(0.0000001));\n    }\n\n    [Test]\n    public void WelfordVariance_Example6()\n    {\n        var stats = new WelfordsVariance();\n        stats.AddRange([2, 4, 4, 4, 5, 5, 7, 9]);\n        Assert.That(stats.Count, Is.EqualTo(8));\n        Assert.That(stats.Mean, Is.EqualTo(5).Within(0.0000001));\n        Assert.That(stats.Variance, Is.EqualTo(4).Within(0.0000001));\n        Assert.That(stats.SampleVariance, Is.EqualTo(4.5714286).Within(0.0000001));\n    }\n\n    [Test]\n    public void WelfordVariance_Example7()\n    {\n        var stats = new WelfordsVariance();\n        stats.AddRange([9, 2, 5, 4, 12, 7, 8, 11, 9, 3, 7, 4, 12, 5, 4, 10, 9, 6, 9, 4]);\n        Assert.That(stats.Count, Is.EqualTo(20));\n        Assert.That(stats.Mean, Is.EqualTo(7).Within(0.0000001));\n        Assert.That(stats.Variance, Is.EqualTo(8.9).Within(0.0000001));\n        Assert.That(stats.SampleVariance, Is.EqualTo(9.3684211).Within(0.0000001));\n    }\n\n    [Test]\n    public void WelfordVariance_Example8()\n    {\n        var stats = new WelfordsVariance();\n        stats.AddRange([51.3, 55.6, 49.9, 52.0]);\n        Assert.That(stats.Count, Is.EqualTo(4));\n        Assert.That(stats.Mean, Is.EqualTo(52.2).Within(0.0000001));\n        Assert.That(stats.Variance, Is.EqualTo(4.4250000).Within(0.0000001));\n        Assert.That(stats.SampleVariance, Is.EqualTo(5.9000000).Within(0.0000001));\n    }\n\n    [Test]\n    public void WelfordVariance_Example9()\n    {\n        var stats = new WelfordsVariance();\n        stats.AddRange([-5, -3, -1, 1, 3]);\n        Assert.That(stats.Count, Is.EqualTo(5));\n        Assert.That(stats.Mean, Is.EqualTo(-1).Within(0.0000001));\n        Assert.That(stats.Variance, Is.EqualTo(8).Within(0.0000001));\n        Assert.That(stats.SampleVariance, Is.EqualTo(10).Within(0.0000001));\n    }\n\n    [Test]\n    public void WelfordVariance_Example10()\n    {\n        var stats = new WelfordsVariance();\n        stats.AddRange([-1, 0, 1]);\n        Assert.That(stats.Count, Is.EqualTo(3));\n        Assert.That(stats.Mean, Is.EqualTo(0).Within(0.0000001));\n        Assert.That(stats.Variance, Is.EqualTo(0.6666667).Within(0.0000001));\n        Assert.That(stats.SampleVariance, Is.EqualTo(1).Within(0.0000001));\n    }\n\n    [Test]\n    public void WelfordVariance_NoValue()\n    {\n        var stats = new WelfordsVariance();\n        Assert.That(stats.Count, Is.EqualTo(0));\n        Assert.That(stats.Mean, Is.EqualTo(double.NaN));\n        Assert.That(stats.Variance, Is.EqualTo(double.NaN));\n        Assert.That(stats.SampleVariance, Is.EqualTo(double.NaN));\n    }\n\n    [Test]\n    public void WelfordVariance_OneValue()\n    {\n        var stats = new WelfordsVariance();\n        stats.AddValue(1);\n        Assert.That(stats.Count, Is.EqualTo(1));\n        Assert.That(stats.Mean, Is.EqualTo(double.NaN));\n        Assert.That(stats.Variance, Is.EqualTo(double.NaN));\n        Assert.That(stats.SampleVariance, Is.EqualTo(double.NaN));\n    }\n\n    [Test]\n    public void WelfordVariance_TwoValues()\n    {\n        var stats = new WelfordsVariance();\n        stats.AddValue(1);\n        stats.AddValue(2);\n        Assert.That(stats.Count, Is.EqualTo(2));\n        Assert.That(stats.Mean, Is.EqualTo(1.5).Within(0.0000001));\n        Assert.That(stats.Variance, Is.EqualTo(0.25).Within(0.0000001));\n        Assert.That(stats.SampleVariance, Is.EqualTo(0.5).Within(0.0000001));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateChangesDictionaryTests.cs",
    "content": "using Algorithms.Problems.DynamicProgramming.CoinChange;\n\nnamespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange;\n\n[TestFixture]\npublic class GenerateChangesDictionaryTests\n{\n    [Test]\n    public void GenerateChangesDictionaryTest_Success()\n    {\n        const int coin = 6;\n        var coins = new[] { 1, 3, 4 };\n        var changeDictionary = DynamicCoinChangeSolver.GenerateChangesDictionary(coin, coins);\n\n        changeDictionary[1].SequenceEqual(new[] { 0 }).Should().BeTrue();\n        changeDictionary[2].SequenceEqual(new[] { 1 }).Should().BeTrue();\n        changeDictionary[3].SequenceEqual(new[] { 0, 2 }).Should().BeTrue();\n        changeDictionary[4].SequenceEqual(new[] { 0, 1, 3 }).Should().BeTrue();\n        changeDictionary[5].SequenceEqual(new[] { 1, 2, 4 }).Should().BeTrue();\n        changeDictionary[6].SequenceEqual(new[] { 2, 3, 5 }).Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GenerateSingleCoinChangesTests.cs",
    "content": "using Algorithms.Problems.DynamicProgramming.CoinChange;\n\nnamespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange;\n\n[TestFixture]\npublic class GenerateSingleCoinChangesTests\n{\n    [Test]\n    public void GenerateSingleCoinChangesTests_Success()\n    {\n        DynamicCoinChangeSolver\n            .GenerateSingleCoinChanges(6, [1, 2, 3])\n            .SequenceEqual(new[] { 3, 4, 5 })\n            .Should().BeTrue();\n\n        DynamicCoinChangeSolver\n            .GenerateSingleCoinChanges(10, [1, 2, 3, 7, 12, 15, 14])\n            .SequenceEqual(new[] { 3, 7, 8, 9 })\n            .Should().BeTrue();\n\n        DynamicCoinChangeSolver\n            .GenerateSingleCoinChanges(1, [1, 2, 3, 7, 12, 15, 14])\n            .SequenceEqual(new[] { 0 })\n            .Should().BeTrue();\n\n        DynamicCoinChangeSolver\n            .GenerateSingleCoinChanges(2, [1, 2, 3, 7, 12, 15, 14])\n            .SequenceEqual(new[] { 0, 1 })\n            .Should().BeTrue();\n    }\n\n    [Test]\n    public void GenerateSingleCoinChangesTests_ShouldThrow_CoinCannotBeLesserOrEqualZero()\n    {\n        const int coin = 0;\n        var arr = new[] { 1, 2, 3 };\n\n        Func<int[]> act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, arr);\n\n        act.Should().Throw<InvalidOperationException>()\n            .WithMessage($\"The coin cannot be lesser or equal to zero {nameof(coin)}.\");\n    }\n\n    [Test]\n    public void GenerateSingleCoinChangesTests_ShouldThrow_CoinsArrayCannotBeEmpty()\n    {\n        const int coin = 10;\n        var coinsAsArray = Array.Empty<int>();\n\n        Func<int[]> act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, coinsAsArray);\n\n        act.Should().Throw<InvalidOperationException>()\n            .WithMessage($\"Coins array cannot be empty {nameof(coinsAsArray)}.\");\n    }\n\n    [Test]\n    public void GenerateSingleCoinChangesTests_ShouldThrow_CoinsArrayMustContainOne()\n    {\n        const int coin = 10;\n        var coinsAsArray = new[] { 2, 3, 4 };\n\n        Func<int[]> act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, coinsAsArray);\n\n        act.Should().Throw<InvalidOperationException>()\n            .WithMessage($\"Coins array must contain coin 1 {nameof(coinsAsArray)}.\");\n    }\n\n    [Test]\n    public void GenerateSingleCoinChangesTests_ShouldThrow_CoinsArrayCannotContainNegativeValues()\n    {\n        const int coin = 10;\n        var coinsAsArray = new[] { 1, 2, -3, 4 };\n\n        Func<int[]> act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, coinsAsArray);\n\n        act.Should().Throw<InvalidOperationException>()\n            .WithMessage($\"{nameof(coinsAsArray)} cannot contain numbers less than or equal to zero\");\n    }\n\n    [Test]\n    public void GenerateSingleCoinChangesTests_ShouldThrow_CoinsArrayCannotContainDuplicates()\n    {\n        const int coin = 10;\n        var coinsAsArray = new[] { 1, 2, 3, 3, 4 };\n\n        Func<int[]> act = () => DynamicCoinChangeSolver.GenerateSingleCoinChanges(coin, coinsAsArray);\n\n        act.Should().Throw<InvalidOperationException>()\n            .WithMessage($\"Coins array cannot contain duplicates {nameof(coinsAsArray)}.\");\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Problems/DynamicProgramming/CoinChange/GetMinimalNextCoinTests.cs",
    "content": "using Algorithms.Problems.DynamicProgramming.CoinChange;\n\nnamespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange;\n\npublic class GetMinimalNextCoinTests\n{\n    [Test]\n    public void GetMinimalNextCoinTest_Success()\n    {\n        const int coin = 6;\n        var coins = new[] { 1, 3, 4 };\n        var exchangeDict = DynamicCoinChangeSolver.GenerateChangesDictionary(coin, coins);\n        var nextCoin = DynamicCoinChangeSolver.GetMinimalNextCoin(6, exchangeDict);\n\n        nextCoin.Should().Be(3);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Problems/DynamicProgramming/CoinChange/MakeCoinChangeDynamicTests.cs",
    "content": "using Algorithms.Problems.DynamicProgramming.CoinChange;\n\nnamespace Algorithms.Tests.Problems.DynamicProgramming.CoinChange;\n\n[TestFixture]\npublic class MakeCoinChangeDynamicTests\n{\n    [Test]\n    public void MakeCoinChangeDynamicTest_Success()\n    {\n        DynamicCoinChangeSolver\n            .MakeCoinChangeDynamic(6, [1, 3, 4])\n            .SequenceEqual(new[] { 3, 3 })\n            .Should().BeTrue();\n\n        DynamicCoinChangeSolver\n            .MakeCoinChangeDynamic(8, [1, 3, 4])\n            .SequenceEqual(new[] { 4, 4 })\n            .Should().BeTrue();\n\n        DynamicCoinChangeSolver\n            .MakeCoinChangeDynamic(25, [1, 3, 4, 12, 13, 14])\n            .SequenceEqual(new[] { 13, 12 })\n            .Should().BeTrue();\n\n        DynamicCoinChangeSolver\n            .MakeCoinChangeDynamic(26, [1, 3, 4, 12, 13, 14])\n            .SequenceEqual(new[] { 14, 12 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistanceTests.cs",
    "content": "using Algorithms.Problems.DynamicProgramming;\n\nnamespace Algorithms.Tests.DynamicProgramming;\n\npublic class LevenshteinDistanceTests\n{\n    [TestCase(\"kitten\", \"sitting\", 3)]\n    [TestCase(\"bob\", \"bond\", 2)]\n    [TestCase(\"algorithm\", \"logarithm\", 3)]\n    [TestCase(\"star\", \"\", 4)]\n    [TestCase(\"\", \"star\", 4)]\n    [TestCase(\"abcde\", \"12345\", 5)]\n    public void Calculate_ReturnsCorrectLevenshteinDistance(string source, string destination, int expectedDistance)\n    {\n        var result = LevenshteinDistance.Calculate(source, destination);\n        Assert.That(result, Is.EqualTo(expectedDistance));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Problems/GraphColoring/GraphColoringSolverTests.cs",
    "content": "using Algorithms.Problems.GraphColoring;\n\nnamespace Algorithms.Tests.Problems.GraphColoring;\n\n[TestFixture]\npublic sealed class GraphColoringSolverTests\n{\n    /// <summary>\n    /// Helper method to validate that a coloring is valid for a given graph.\n    /// </summary>\n    /// <param name=\"adjacencyMatrix\">The graph adjacency matrix.</param>\n    /// <param name=\"colors\">The color assignment to validate.</param>\n    /// <remarks>\n    /// A valid coloring must satisfy:\n    /// 1. All vertices are colored (no -1 values).\n    /// 2. No two adjacent vertices have the same color.\n    /// </remarks>\n    private static void AssertValidColoring(bool[,] adjacencyMatrix, int[] colors)\n    {\n        var numVertices = adjacencyMatrix.GetLength(0);\n\n        Assert.That(colors, Has.Length.EqualTo(numVertices), \n            \"Color array length must match number of vertices.\");\n\n        // Check all vertices are colored\n        for (var i = 0; i < numVertices; i++)\n        {\n            Assert.That(colors[i], Is.GreaterThanOrEqualTo(0),\n                $\"Vertex {i} is not colored (has value -1).\");\n        }\n\n        // Check no adjacent vertices have the same color\n        for (var i = 0; i < numVertices; i++)\n        {\n            for (var j = i + 1; j < numVertices; j++)\n            {\n                if (adjacencyMatrix[i, j])\n                {\n                    Assert.That(colors[i], Is.Not.EqualTo(colors[j]),\n                        $\"Adjacent vertices {i} and {j} have the same color {colors[i]}.\");\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Helper method to create an empty graph (no edges).\n    /// </summary>\n    private static bool[,] CreateEmptyGraph(int vertices)\n    {\n        return new bool[vertices, vertices];\n    }\n\n    /// <summary>\n    /// Helper method to create a complete graph where all vertices are connected.\n    /// </summary>\n    private static bool[,] CreateCompleteGraph(int vertices)\n    {\n        var graph = new bool[vertices, vertices];\n        for (var i = 0; i < vertices; i++)\n        {\n            for (var j = 0; j < vertices; j++)\n            {\n                if (i != j)\n                {\n                    graph[i, j] = true;\n                }\n            }\n        }\n        return graph;\n    }\n\n    /// <summary>\n    /// Helper method to create a bipartite graph (two sets with edges only between sets).\n    /// </summary>\n    private static bool[,] CreateBipartiteGraph(int setASize, int setBSize)\n    {\n        var total = setASize + setBSize;\n        var graph = new bool[total, total];\n        \n        // Connect all vertices in set A to all vertices in set B\n        for (var i = 0; i < setASize; i++)\n        {\n            for (var j = setASize; j < total; j++)\n            {\n                graph[i, j] = true;\n                graph[j, i] = true;\n            }\n        }\n        return graph;\n    }\n\n    /// <summary>\n    /// Helper method to create a cycle graph.\n    /// </summary>\n    private static bool[,] CreateCycleGraph(int vertices)\n    {\n        var graph = new bool[vertices, vertices];\n        for (var i = 0; i < vertices; i++)\n        {\n            var next = (i + 1) % vertices;\n            graph[i, next] = true;\n            graph[next, i] = true;\n        }\n        return graph;\n    }\n\n    /// <summary>\n    /// Helper method to create a path graph (linear chain).\n    /// </summary>\n    private static bool[,] CreatePathGraph(int vertices)\n    {\n        var graph = new bool[vertices, vertices];\n        for (var i = 0; i < vertices - 1; i++)\n        {\n            graph[i, i + 1] = true;\n            graph[i + 1, i] = true;\n        }\n        return graph;\n    }\n\n    [Test]\n    public void ColorGraph_ThrowsArgumentNullException_WhenAdjacencyMatrixIsNull()\n    {\n        var solver = new GraphColoringSolver();\n\n        Assert.Throws<ArgumentNullException>(() => solver.ColorGraph(null!, 3));\n    }\n\n    [Test]\n    public void ColorGraph_ThrowsArgumentException_WhenAdjacencyMatrixIsNotSquare()\n    {\n        var solver = new GraphColoringSolver();\n        var nonSquareMatrix = new bool[3, 4];\n\n        Assert.Throws<ArgumentException>(() => solver.ColorGraph(nonSquareMatrix, 3));\n    }\n\n    [TestCase(0)]\n    [TestCase(-1)]\n    [TestCase(-5)]\n    public void ColorGraph_ThrowsArgumentException_WhenNumColorsIsNonPositive(int numColors)\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateEmptyGraph(3);\n\n        Assert.Throws<ArgumentException>(() => solver.ColorGraph(graph, numColors));\n    }\n\n    [Test]\n    public void ColorGraph_ReturnsEmptyArray_ForEmptyGraph()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = new bool[0, 0];\n\n        var result = solver.ColorGraph(graph, 1);\n\n        Assert.That(result, Is.Empty);\n    }\n\n    [Test]\n    public void ColorGraph_ColorsSingleVertex_WithOneColor()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateEmptyGraph(1);\n\n        var result = solver.ColorGraph(graph, 1);\n\n        Assert.That(result, Has.Length.EqualTo(1));\n        Assert.That(result[0], Is.EqualTo(0));\n        AssertValidColoring(graph, result);\n    }\n\n    [Test]\n    public void ColorGraph_ColorsDisconnectedVertices_WithOneColor()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateEmptyGraph(5); // No edges\n\n        var result = solver.ColorGraph(graph, 1);\n\n        Assert.That(result, Has.Length.EqualTo(5));\n        AssertValidColoring(graph, result);\n        \n        // All vertices should have the same color since there are no edges\n        Assert.That(result.Distinct().Count(), Is.EqualTo(1));\n    }\n\n    [Test]\n    public void ColorGraph_ColorsBipartiteGraph_WithTwoColors()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateBipartiteGraph(3, 3);\n\n        var result = solver.ColorGraph(graph, 2);\n\n        Assert.That(result, Has.Length.EqualTo(6));\n        AssertValidColoring(graph, result);\n        \n        // Bipartite graph should use exactly 2 colors\n        Assert.That(result.Distinct().Count(), Is.LessThanOrEqualTo(2));\n    }\n\n    [Test]\n    public void ColorGraph_ThrowsArgumentException_ForBipartiteGraphWithOneColor()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateBipartiteGraph(2, 2);\n\n        // Bipartite graph with edges requires at least 2 colors\n        Assert.Throws<ArgumentException>(() => solver.ColorGraph(graph, 1));\n    }\n\n    [Test]\n    public void ColorGraph_ColorsPathGraph_WithTwoColors()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreatePathGraph(5);\n\n        var result = solver.ColorGraph(graph, 2);\n\n        Assert.That(result, Has.Length.EqualTo(5));\n        AssertValidColoring(graph, result);\n        \n        // Path graph can be colored with 2 colors\n        Assert.That(result.Distinct().Count(), Is.LessThanOrEqualTo(2));\n    }\n\n    [Test]\n    public void ColorGraph_ColorsEvenCycle_WithTwoColors()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateCycleGraph(6); // Even cycle\n\n        var result = solver.ColorGraph(graph, 2);\n\n        Assert.That(result, Has.Length.EqualTo(6));\n        AssertValidColoring(graph, result);\n        \n        // Even cycle can be colored with 2 colors\n        Assert.That(result.Distinct().Count(), Is.LessThanOrEqualTo(2));\n    }\n\n    [Test]\n    public void ColorGraph_ThrowsArgumentException_ForOddCycleWithTwoColors()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateCycleGraph(5); // Odd cycle\n\n        // Odd cycle requires at least 3 colors\n        Assert.Throws<ArgumentException>(() => solver.ColorGraph(graph, 2));\n    }\n\n    [Test]\n    public void ColorGraph_ColorsOddCycle_WithThreeColors()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateCycleGraph(5); // Odd cycle\n\n        var result = solver.ColorGraph(graph, 3);\n\n        Assert.That(result, Has.Length.EqualTo(5));\n        AssertValidColoring(graph, result);\n    }\n\n    [Test]\n    public void ColorGraph_ColorsTriangle_WithThreeColors()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateCompleteGraph(3); // Triangle (K3)\n\n        var result = solver.ColorGraph(graph, 3);\n\n        Assert.That(result, Has.Length.EqualTo(3));\n        AssertValidColoring(graph, result);\n        \n        // Complete graph K3 requires exactly 3 colors\n        Assert.That(result.Distinct().Count(), Is.EqualTo(3));\n    }\n\n    [Test]\n    public void ColorGraph_ThrowsArgumentException_ForTriangleWithTwoColors()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateCompleteGraph(3); // Triangle (K3)\n\n        // Triangle requires 3 colors\n        Assert.Throws<ArgumentException>(() => solver.ColorGraph(graph, 2));\n    }\n\n    [Test]\n    public void ColorGraph_ColorsCompleteGraphK4_WithFourColors()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateCompleteGraph(4); // K4\n\n        var result = solver.ColorGraph(graph, 4);\n\n        Assert.That(result, Has.Length.EqualTo(4));\n        AssertValidColoring(graph, result);\n        \n        // Complete graph K4 requires exactly 4 colors\n        Assert.That(result.Distinct().Count(), Is.EqualTo(4));\n    }\n\n    [Test]\n    public void ColorGraph_ThrowsArgumentException_ForCompleteGraphK4WithThreeColors()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateCompleteGraph(4); // K4\n\n        // K4 requires 4 colors\n        Assert.Throws<ArgumentException>(() => solver.ColorGraph(graph, 3));\n    }\n\n    [Test]\n    public void ColorGraph_ColorsStarGraph_WithTwoColors()\n    {\n        var solver = new GraphColoringSolver();\n        \n        // Star graph: one central vertex connected to all others\n        var graph = new bool[5, 5];\n        for (var i = 1; i < 5; i++)\n        {\n            graph[0, i] = true;\n            graph[i, 0] = true;\n        }\n\n        var result = solver.ColorGraph(graph, 2);\n\n        Assert.That(result, Has.Length.EqualTo(5));\n        AssertValidColoring(graph, result);\n        \n        // Star graph requires only 2 colors\n        Assert.That(result.Distinct().Count(), Is.LessThanOrEqualTo(2));\n    }\n\n    [Test]\n    public void ColorGraph_HandlesPetersenGraph_WithThreeColors()\n    {\n        var solver = new GraphColoringSolver();\n        \n        // Simplified version: a graph that requires 3 colors\n        // Creating a graph with a triangle and additional connections\n        var graph = new bool[5, 5];\n        \n        // Triangle: vertices 0, 1, 2\n        graph[0, 1] = graph[1, 0] = true;\n        graph[1, 2] = graph[2, 1] = true;\n        graph[2, 0] = graph[0, 2] = true;\n        \n        // Additional edges to vertex 3\n        graph[0, 3] = graph[3, 0] = true;\n        graph[1, 3] = graph[3, 1] = true;\n        \n        // Additional edges to vertex 4\n        graph[2, 4] = graph[4, 2] = true;\n        graph[3, 4] = graph[4, 3] = true;\n\n        var result = solver.ColorGraph(graph, 3);\n\n        Assert.That(result, Has.Length.EqualTo(5));\n        AssertValidColoring(graph, result);\n    }\n\n    [Test]\n    public void ColorGraph_AllColorsWithinRange()\n    {\n        var solver = new GraphColoringSolver();\n        var graph = CreateCompleteGraph(4);\n        var numColors = 4;\n\n        var result = solver.ColorGraph(graph, numColors);\n\n        // Verify all colors are in range [0, numColors)\n        foreach (var color in result)\n        {\n            Assert.That(color, Is.InRange(0, numColors - 1));\n        }\n    }\n\n    [Test]\n    public void ColorGraph_SymmetricMatrix_ProducesSameResult()\n    {\n        var solver = new GraphColoringSolver();\n        \n        // Create a symmetric graph\n        var graph = new bool[4, 4];\n        graph[0, 1] = graph[1, 0] = true;\n        graph[1, 2] = graph[2, 1] = true;\n        graph[2, 3] = graph[3, 2] = true;\n\n        var result = solver.ColorGraph(graph, 3);\n\n        Assert.That(result, Has.Length.EqualTo(4));\n        AssertValidColoring(graph, result);\n    }\n\n    [Test]\n    public void ColorGraph_LargerGraph_ProducesValidColoring()\n    {\n        var solver = new GraphColoringSolver();\n        \n        // Create a larger graph (10 vertices, random edges)\n        var graph = new bool[10, 10];\n        \n        // Create edges forming a more complex structure\n        for (var i = 0; i < 9; i++)\n        {\n            graph[i, i + 1] = graph[i + 1, i] = true;\n        }\n        \n        // Add some cross edges\n        graph[0, 5] = graph[5, 0] = true;\n        graph[2, 7] = graph[7, 2] = true;\n        graph[3, 8] = graph[8, 3] = true;\n\n        var result = solver.ColorGraph(graph, 3);\n\n        Assert.That(result, Has.Length.EqualTo(10));\n        AssertValidColoring(graph, result);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Problems/JobScheduling/IntervalSchedulingSolverTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Algorithms.Problems.JobScheduling;\n\nnamespace Algorithms.Tests.Problems.JobScheduling;\n\npublic class IntervalSchedulingSolverTests\n{\n    [Test]\n    public void Schedule_ReturnsEmpty_WhenNoJobs()\n    {\n        var result = IntervalSchedulingSolver.Schedule(new List<Job>());\n        Assert.That(result, Is.Empty);\n    }\n\n    [Test]\n    public void Schedule_ReturnsSingleJob_WhenOnlyOneJob()\n    {\n        var jobs = new List<Job> { new Job(1, 3) };\n        var result = IntervalSchedulingSolver.Schedule(jobs);\n        Assert.That(result, Has.Count.EqualTo(1));\n        Assert.That(result[0], Is.EqualTo(jobs[0]));\n    }\n\n    [Test]\n    public void Schedule_ThrowsArgumentNullException_WhenJobsIsNull()\n    {\n        Assert.Throws<ArgumentNullException>(() => IntervalSchedulingSolver.Schedule(jobs: null!));\n    }\n\n    [Test]\n    public void Schedule_SelectsJobsWithEqualEndTime()\n    {\n        var jobs = new List<Job>\n        {\n            new Job(1, 4),\n            new Job(2, 4),\n            new Job(4, 6)\n        };\n        var result = IntervalSchedulingSolver.Schedule(jobs);\n        Assert.That(result, Has.Count.EqualTo(2));\n        Assert.That(result, Does.Contain(new Job(1, 4)));\n        Assert.That(result, Does.Contain(new Job(4, 6)));\n    }\n\n    [Test]\n    public void Schedule_SelectsJobStartingAtLastEnd()\n    {\n        var jobs = new List<Job>\n        {\n            new Job(1, 3),\n            new Job(3, 5),\n            new Job(5, 7)\n        };\n        var result = IntervalSchedulingSolver.Schedule(jobs);\n        Assert.That(result, Has.Count.EqualTo(3));\n        Assert.That(result[0], Is.EqualTo(jobs[0]));\n        Assert.That(result[1], Is.EqualTo(jobs[1]));\n        Assert.That(result[2], Is.EqualTo(jobs[2]));\n    }\n\n    [Test]\n    public void Schedule_HandlesJobsWithNegativeTimes()\n    {\n        var jobs = new List<Job>\n        {\n            new Job(-5, -3),\n            new Job(-2, 1),\n            new Job(0, 2)\n        };\n        var result = IntervalSchedulingSolver.Schedule(jobs);\n        Assert.That(result, Has.Count.EqualTo(2));\n        Assert.That(result, Does.Contain(new Job(-5, -3)));\n        Assert.That(result, Does.Contain(new Job(-2, 1)));\n    }\n\n    [Test]\n    public void Schedule_SelectsNonOverlappingJobs()\n    {\n        var jobs = new List<Job>\n        {\n            new Job(1, 4),\n            new Job(3, 5),\n            new Job(0, 6),\n            new Job(5, 7),\n            new Job(8, 9),\n            new Job(5, 9)\n        };\n        var result = IntervalSchedulingSolver.Schedule(jobs);\n        // Expected: (1,4), (5,7), (8,9)\n        Assert.That(result, Has.Count.EqualTo(3));\n        Assert.That(result, Does.Contain(new Job(1, 4)));\n        Assert.That(result, Does.Contain(new Job(5, 7)));\n        Assert.That(result, Does.Contain(new Job(8, 9)));\n    }\n\n    [Test]\n    public void Schedule_HandlesFullyOverlappingJobs()\n    {\n        var jobs = new List<Job>\n        {\n            new Job(1, 5),\n            new Job(2, 6),\n            new Job(3, 7)\n        };\n        var result = IntervalSchedulingSolver.Schedule(jobs);\n        // Only one job can be selected\n        Assert.That(result, Has.Count.EqualTo(1));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Problems/KnightTour/OpenKnightTourTests.cs",
    "content": "using Algorithms.Problems.KnightTour;\n\nnamespace Algorithms.Tests.Problems.KnightTour\n{\n    [TestFixture]\n    public sealed class OpenKnightTourTests\n    {\n        private static bool IsKnightMove((int r, int c) a, (int r, int c) b)\n        {\n            var dr = Math.Abs(a.r - b.r);\n            var dc = Math.Abs(a.c - b.c);\n            return (dr == 1 && dc == 2) || (dr == 2 && dc == 1);\n        }\n\n        private static Dictionary<int, (int r, int c)> MapVisitOrder(int[,] board)\n        {\n            var n = board.GetLength(0);\n            var map = new Dictionary<int, (int r, int c)>(n * n);\n            for (var r = 0; r < n; r++)\n            {\n                for (var c = 0; c < n; c++)\n                {\n                    var v = board[r, c];\n                    if (v <= 0)\n                    {\n                        continue;\n                    }\n                    // ignore zeros in partial/invalid boards\n                    if (!map.TryAdd(v, (r, c)))\n                    {\n                        throw new AssertionException($\"Duplicate visit number detected: {v}.\");\n                    }\n                }\n            }\n            return map;\n        }\n\n        private static void AssertIsValidTour(int[,] board)\n        {\n            var n = board.GetLength(0);\n            Assert.That(board.GetLength(1), Is.EqualTo(n), \"Board must be square.\");\n\n            // 1) All cells visited and within [1..n*n]\n            int min = int.MaxValue;\n            int max = int.MinValue;\n            \n            var seen = new bool[n * n + 1]; // 1..n*n\n            for (var r = 0; r < n; r++)\n            {\n                for (var c = 0; c < n; c++)\n                {\n                    var v = board[r, c];\n                    Assert.That(v, Is.InRange(1, n * n),\n                        $\"Cell [{r},{c}] has out-of-range value {v}.\");\n                    Assert.That(seen[v], Is.False, $\"Duplicate value {v} found.\");\n                    seen[v] = true;\n                    if (v < min)\n                    {\n                        min = v;\n                    }\n\n                    if (v > max)\n                    {\n                        max = v;\n                    }\n                }\n            }\n            Assert.That(min, Is.EqualTo(1), \"Tour must start at 1.\");\n            Assert.That(max, Is.EqualTo(n * n), \"Tour must end at n*n.\");\n\n            // 2) Each successive step is a legal knight move\n            var pos = MapVisitOrder(board); // throws if duplicates\n            for (var step = 1; step < n * n; step++)\n            {\n                var a = pos[step];\n                var b = pos[step + 1];\n                Assert.That(IsKnightMove(a, b),\n                    $\"Step {step}->{step + 1} is not a legal knight move: {a} -> {b}.\");\n            }\n        }\n\n        [Test]\n        public void Tour_Throws_On_NonPositiveN()\n        {\n            var solver = new OpenKnightTour();\n\n            Assert.Throws<ArgumentException>(() => solver.Tour(0));\n            Assert.Throws<ArgumentException>(() => solver.Tour(-1));\n            Assert.Throws<ArgumentException>(() => solver.Tour(-5));\n        }\n\n        [TestCase(2)]\n        [TestCase(3)]\n        [TestCase(4)]\n        public void Tour_Throws_On_Unsolvable_N_2_3_4(int n)\n        {\n            var solver = new OpenKnightTour();\n            Assert.Throws<ArgumentException>(() => solver.Tour(n));\n        }\n\n        [Test]\n        public void Tour_Returns_Valid_1x1()\n        {\n            var solver = new OpenKnightTour();\n            var board = solver.Tour(1);\n\n            Assert.That(board.GetLength(0), Is.EqualTo(1));\n            Assert.That(board.GetLength(1), Is.EqualTo(1));\n            Assert.That(board[0, 0], Is.EqualTo(1));\n            AssertIsValidTour(board);\n        }\n\n        /// <summary>\n        /// The plain backtracking search can take some time on 5x5 depending on move ordering,\n        /// but should still be manageable. We mark it as \"Slow\" and add a generous timeout.\n        /// </summary>\n        [Test, Category(\"Slow\"), CancelAfterAttribute(30000)]\n        public void Tour_Returns_Valid_5x5()\n        {\n            var solver = new OpenKnightTour();\n            var board = solver.Tour(5);\n\n            // Shape checks\n            Assert.That(board.GetLength(0), Is.EqualTo(5));\n            Assert.That(board.GetLength(1), Is.EqualTo(5));\n\n            // Structural validity checks\n            AssertIsValidTour(board);\n        }\n\n        [Test]\n        public void Tour_Fills_All_Cells_No_Zeros_On_Successful_Boards()\n        {\n            var solver = new OpenKnightTour();\n            var board = solver.Tour(5);\n\n            for (var r = 0; r < board.GetLength(0); r++)\n            {\n                for (var c = 0; c < board.GetLength(1); c++)\n                {\n                    Assert.That(board[r, c], Is.Not.EqualTo(0),\n                        $\"Found unvisited cell at [{r},{c}].\");\n                }\n            }\n        }\n\n        [Test]\n        public void Tour_Produces_Values_In_Valid_Range_And_Unique()\n        {\n            var solver = new OpenKnightTour();\n            var n = 5;\n            var board = solver.Tour(n);\n\n            var values = new List<int>(n * n);\n            for (var r = 0; r < n; r++)\n            {\n                for (var c = 0; c < n; c++)\n                {\n                    values.Add(board[r, c]);\n                }\n            }\n\n            values.Sort();\n            // Expect [1..n*n]\n            var expected = Enumerable.Range(1, n * n).ToArray();\n            Assert.That(values, Is.EqualTo(expected),\n                \"Board must contain each number exactly once from 1 to n*n.\");\n        }\n\n        [Test]\n        public void Tour_Returns_Square_Array()\n        {\n            var solver = new OpenKnightTour();\n            var board = solver.Tour(5);\n\n            Assert.That(board.GetLength(0), Is.EqualTo(board.GetLength(1)));\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Problems/NQueens/BacktrackingNQueensSolverTests.cs",
    "content": "using Algorithms.Problems.NQueens;\n\nnamespace Algorithms.Tests.Problems.NQueens;\n\npublic static class BacktrackingNQueensSolverTests\n{\n    [TestCase(0, 0)]\n    [TestCase(1, 1)]\n    [TestCase(2, 0)]\n    [TestCase(3, 0)]\n    [TestCase(4, 2)]\n    [TestCase(5, 10)]\n    [TestCase(6, 4)]\n    [TestCase(7, 40)]\n    [TestCase(8, 92)]\n    [TestCase(8, 92)]\n    [TestCase(9, 352)]\n    [TestCase(10, 724)]\n    [TestCase(11, 2680)]\n    public static void SolvesCorrectly(int n, int expectedNumberOfSolutions)\n    {\n        // Arrange\n        // Act\n        var result = new BacktrackingNQueensSolver().BacktrackSolve(n).ToList();\n\n        // Assert\n        result.Should().HaveCount(expectedNumberOfSolutions);\n        foreach (var solution in result)\n        {\n            ValidateOneQueenPerRow(solution);\n            ValidateOneQueenPerColumn(solution);\n            ValidateOneQueenPerTopLeftBottomRightDiagonalLine(solution);\n            ValidateOneQueenPerBottomLeftTopRightDiagonalLine(solution);\n        }\n    }\n\n    [Test]\n    public static void NCannotBeNegative()\n    {\n        var n = -1;\n\n        Action act = () => new BacktrackingNQueensSolver().BacktrackSolve(n);\n\n        act.Should().Throw<ArgumentException>();\n    }\n\n    private static void ValidateOneQueenPerRow(bool[,] solution)\n    {\n        for (var i = 0; i < solution.GetLength(1); i++)\n        {\n            var foundQueen = false;\n            for (var j = 0; j < solution.GetLength(0); j++)\n            {\n                foundQueen = ValidateCell(foundQueen, solution[j, i]);\n            }\n        }\n    }\n\n    private static void ValidateOneQueenPerColumn(bool[,] solution)\n    {\n        for (var i = 0; i < solution.GetLength(0); i++)\n        {\n            var foundQueen = false;\n            for (var j = 0; j < solution.GetLength(1); j++)\n            {\n                foundQueen = ValidateCell(foundQueen, solution[i, j]);\n            }\n        }\n    }\n\n    private static void ValidateOneQueenPerTopLeftBottomRightDiagonalLine(bool[,] solution)\n    {\n        for (var i = 0; i < solution.GetLength(0); i++)\n        {\n            var foundQueen = false;\n            for (var j = 0; i + j < solution.GetLength(1); j++)\n            {\n                foundQueen = ValidateCell(foundQueen, solution[i + j, i]);\n            }\n        }\n\n        for (var i = 0; i < solution.GetLength(1); i++)\n        {\n            var foundQueen = false;\n            for (var j = 0; i + j < solution.GetLength(0); j++)\n            {\n                foundQueen = ValidateCell(foundQueen, solution[j, i + j]);\n            }\n        }\n    }\n\n    private static void ValidateOneQueenPerBottomLeftTopRightDiagonalLine(bool[,] solution)\n    {\n        for (var i = 0; i < solution.GetLength(0); i++)\n        {\n            var foundQueen = false;\n            for (var j = 0; i - j >= 0; j++)\n            {\n                foundQueen = ValidateCell(foundQueen, solution[i - j, i]);\n            }\n        }\n\n        for (var i = 0; i < solution.GetLength(1); i++)\n        {\n            var foundQueen = false;\n            for (var j = 0; i - j >= 0 && solution.GetLength(0) - j > 0; j++)\n            {\n                foundQueen = ValidateCell(foundQueen, solution[solution.GetLength(0) - j - 1, i - j]);\n            }\n        }\n    }\n\n    private static bool ValidateCell(bool foundQueen, bool currentCell)\n    {\n        if (foundQueen)\n        {\n            currentCell.Should().BeFalse();\n        }\n\n        return foundQueen || currentCell;\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Problems/StableMarriage/GaleShapleyTests.cs",
    "content": "using Algorithms.Problems.StableMarriage;\n\nnamespace Algorithms.Tests.Problems.StableMarriage;\n\n/// <summary>\n///     The stable marriage problem (also stable matching problem or SMP)\n///     is the problem of finding a stable matching between two equally sized sets of elements given an ordering of\n///     preferences for each element.\n/// </summary>\npublic static class GaleShapleyTests\n{\n    /// <summary>\n    ///     Checks that all parties are engaged and stable.\n    /// </summary>\n    [Test]\n    public static void MatchingIsSuccessful()\n    {\n        var random = new Random(7);\n        var proposers = Enumerable.Range(1, 10).Select(_ => new Proposer()).ToArray();\n        var acceptors = Enumerable.Range(1, 10).Select(_ => new Accepter()).ToArray();\n\n        foreach (var proposer in proposers)\n        {\n            proposer.PreferenceOrder = new LinkedList<Accepter>(acceptors.OrderBy(_ => random.Next()));\n        }\n\n        foreach (var acceptor in acceptors)\n        {\n            acceptor.PreferenceOrder = proposers.OrderBy(_ => random.Next()).ToList();\n        }\n\n        GaleShapley.Match(proposers, acceptors);\n\n        Assert.That(acceptors.ToList().TrueForAll(x => x.EngagedTo is not null));\n        Assert.That(proposers.ToList().TrueForAll(x => x.EngagedTo is not null));\n        Assert.That(AreMatchesStable(proposers, acceptors), Is.True);\n    }\n\n    private static bool AreMatchesStable(Proposer[] proposers, Accepter[] accepters) =>\n        proposers.ToList().TrueForAll(p =>\n            p.EngagedTo is not null\n            && Score(p, p.EngagedTo) <= accepters\n                .Where(a => a.PrefersOverCurrent(p))\n                .Min(a => Score(p, a)));\n\n    private static int Score(Proposer proposer, Accepter accepter) =>\n        proposer.PreferenceOrder.ToList().IndexOf(accepter);\n}\n"
  },
  {
    "path": "Algorithms.Tests/Problems/TravelingSalesman/TravelingSalesmanSolverTests.cs",
    "content": "using Algorithms.Problems.TravelingSalesman;\nusing NUnit.Framework;\n\nnamespace Algorithms.Tests.Problems.TravelingSalesman;\n\n/// <summary>\n/// Unit tests for TravelingSalesmanSolver. Covers brute-force and nearest neighbor methods, including edge cases and invalid input.\n/// </summary>\n[TestFixture]\npublic class TravelingSalesmanSolverTests\n{\n    /// <summary>\n    /// Tests brute-force TSP solver on a 4-city symmetric distance matrix with known optimal route.\n    /// </summary>\n    [Test]\n    public void SolveBruteForce_KnownOptimalRoute_ReturnsCorrectResult()\n    {\n        // Distance matrix for 4 cities (symmetric, triangle inequality holds)\n        double[,] matrix =\n        {\n            { 0, 10, 15, 20 },\n            { 10, 0, 35, 25 },\n            { 15, 35, 0, 30 },\n            { 20, 25, 30, 0 }\n        };\n        var (route, distance) = TravelingSalesmanSolver.SolveBruteForce(matrix);\n        // Optimal route: 0 -> 1 -> 3 -> 2 -> 0, total distance = 80\n        Assert.That(distance, Is.EqualTo(80));\n        Assert.That(route, Is.EquivalentTo(new[] { 0, 1, 3, 2, 0 }));\n    }\n\n    /// <summary>\n    /// Tests nearest neighbor heuristic on the same matrix. May not be optimal.\n    /// </summary>\n    [Test]\n    public void SolveNearestNeighbor_Heuristic_ReturnsFeasibleRoute()\n    {\n        double[,] matrix =\n        {\n            { 0, 10, 15, 20 },\n            { 10, 0, 35, 25 },\n            { 15, 35, 0, 30 },\n            { 20, 25, 30, 0 }\n        };\n        var (route, distance) = TravelingSalesmanSolver.SolveNearestNeighbor(matrix, 0);\n        // Route: 0 -> 1 -> 3 -> 2 -> 0, total distance = 80\n        Assert.That(route.Length, Is.EqualTo(5));\n        Assert.That(route.First(), Is.EqualTo(0));\n        Assert.That(route.Last(), Is.EqualTo(0));\n        Assert.That(distance, Is.GreaterThanOrEqualTo(80)); // Heuristic may be optimal or suboptimal\n    }\n\n    /// <summary>\n    /// Tests nearest neighbor with invalid start index.\n    /// </summary>\n    [Test]\n    public void SolveNearestNeighbor_InvalidStart_ThrowsException()\n    {\n        double[,] matrix =\n        {\n            { 0, 1 },\n            { 1, 0 }\n        };\n        Assert.Throws<ArgumentOutOfRangeException>(() => TravelingSalesmanSolver.SolveNearestNeighbor(matrix, -1));\n        Assert.Throws<ArgumentOutOfRangeException>(() => TravelingSalesmanSolver.SolveNearestNeighbor(matrix, 2));\n    }\n    \n    /// <summary>\n    /// Tests nearest neighbor when no unvisited cities remain (should throw InvalidOperationException).\n    /// </summary>\n    [Test]\n    public void SolveNearestNeighbor_NoUnvisitedCities_ThrowsException()\n    {\n        // Construct a matrix where one city cannot be reached (simulate unreachable city)\n        double[,] matrix =\n        {\n            { 0, double.MaxValue, 1 },\n            { double.MaxValue, 0, double.MaxValue },\n            { 1, double.MaxValue, 0 }\n        };\n        // Start at city 0, city 1 is unreachable from both 0 and 2\n        Assert.Throws<InvalidOperationException>(() => TravelingSalesmanSolver.SolveNearestNeighbor(matrix, 0));\n    }\n\n    /// <summary>\n    /// Tests brute-force and nearest neighbor with non-square matrix.\n    /// </summary>\n    [Test]\n    public void NonSquareMatrix_ThrowsException()\n    {\n        double[,] matrix = new double[2, 3];\n        Assert.Throws<ArgumentException>(() => TravelingSalesmanSolver.SolveBruteForce(matrix));\n        Assert.Throws<ArgumentException>(() => TravelingSalesmanSolver.SolveNearestNeighbor(matrix, 0));\n    }\n\n    /// <summary>\n    /// Tests brute-force with less than two cities (invalid case).\n    /// </summary>\n    [Test]\n    public void SolveBruteForce_TooFewCities_ThrowsException()\n    {\n        double[,] matrix = { { 0 } };\n        Assert.Throws<ArgumentException>(() => TravelingSalesmanSolver.SolveBruteForce(matrix));\n    }\n\n    /// <summary>\n    /// Tests nearest neighbor with only two cities (trivial case).\n    /// </summary>\n    [Test]\n    public void SolveNearestNeighbor_TwoCities_ReturnsCorrectRoute()\n    {\n        double[,] matrix =\n        {\n            { 0, 5 },\n            { 5, 0 }\n        };\n        var (route, distance) = TravelingSalesmanSolver.SolveNearestNeighbor(matrix, 0);\n        Assert.That(route, Is.EquivalentTo(new[] { 0, 1, 0 }));\n        Assert.That(distance, Is.EqualTo(10));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/RecommenderSystem/CollaborativeFilteringTests.cs",
    "content": "using Algorithms.RecommenderSystem;\nusing Moq;\n\nnamespace Algorithms.Tests.RecommenderSystem;\n\n[TestFixture]\npublic class CollaborativeFilteringTests\n{\n    private Mock<ISimilarityCalculator>? mockSimilarityCalculator;\n    private CollaborativeFiltering? recommender;\n    private Dictionary<string, Dictionary<string, double>> testRatings = null!;\n\n    [SetUp]\n    public void Setup()\n    {\n        mockSimilarityCalculator = new Mock<ISimilarityCalculator>();\n        recommender = new CollaborativeFiltering(mockSimilarityCalculator.Object);\n\n        testRatings = new Dictionary<string, Dictionary<string, double>>\n        {\n            [\"user1\"] = new()\n            {\n                [\"item1\"] = 5.0,\n                [\"item2\"] = 3.0,\n                [\"item3\"] = 4.0\n            },\n            [\"user2\"] = new()\n            {\n                [\"item1\"] = 4.0,\n                [\"item2\"] = 2.0,\n                [\"item3\"] = 5.0\n            },\n            [\"user3\"] = new()\n            {\n                [\"item1\"] = 3.0,\n                [\"item2\"] = 4.0,\n                [\"item4\"] = 3.0\n            }\n        };\n    }\n\n    [Test]\n    [TestCase(\"item1\", 4.0, 5.0)]\n    [TestCase(\"item2\", 2.0, 4.0)]\n    public void CalculateSimilarity_WithValidInputs_ReturnsExpectedResults(\n        string commonItem,\n        double rating1,\n        double rating2)\n    {\n        var user1Ratings = new Dictionary<string, double> { [commonItem] = rating1 };\n        var user2Ratings = new Dictionary<string, double> { [commonItem] = rating2 };\n\n        var similarity = recommender?.CalculateSimilarity(user1Ratings, user2Ratings);\n\n        Assert.That(similarity, Is.InRange(-1.0, 1.0));\n    }\n\n    [Test]\n    public void CalculateSimilarity_WithNoCommonItems_ReturnsZero()\n    {\n        var user1Ratings = new Dictionary<string, double> { [\"item1\"] = 5.0 };\n        var user2Ratings = new Dictionary<string, double> { [\"item2\"] = 4.0 };\n\n        var similarity = recommender?.CalculateSimilarity(user1Ratings, user2Ratings);\n\n        Assert.That(similarity, Is.EqualTo(0));\n    }\n\n    [Test]\n    public void PredictRating_WithNonexistentItem_ReturnsZero()\n    {\n        var predictedRating = recommender?.PredictRating(\"nonexistentItem\", \"user1\", testRatings);\n\n        Assert.That(predictedRating, Is.EqualTo(0));\n    }\n\n    [NonParallelizable]\n    [Test]\n    public void PredictRating_WithOtherUserHavingRatedTargetItem_ShouldCalculateSimilarityAndWeightedSum()\n    {\n        var targetItem = \"item1\";\n        var targetUser = \"user1\";\n\n        mockSimilarityCalculator?\n            .Setup(s => s.CalculateSimilarity(It.IsAny<Dictionary<string, double>>(), It.IsAny<Dictionary<string, double>>()))\n            .Returns(0.8);\n\n        var predictedRating = recommender?.PredictRating(targetItem, targetUser, testRatings);\n\n        Assert.That(predictedRating, Is.Not.EqualTo(0.0d));\n        Assert.That(predictedRating, Is.EqualTo(3.5d).Within(0.01));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Search/AStarTests.cs",
    "content": "\nusing System.Reflection;\n\nusing Algorithms.Search.AStar;\n\nnamespace Algorithms.Tests.Search;\n\npublic static class AStarTests\n{\n    [Test]\n    public static void ResetNodes_ResetsAllNodeProperties()\n    {\n        var node = new Node(new VecN(0, 0), true, 1.0)\n        {\n            CurrentCost = 5,\n            EstimatedCost = 10,\n            Parent = new Node(new VecN(1, 1), true, 1.0),\n            State = NodeState.Closed\n        };\n        var nodes = new List<Node> { node };\n\n        AStar.ResetNodes(nodes);\n\n        node.CurrentCost.Should().Be(0);\n        node.EstimatedCost.Should().Be(0);\n        node.Parent.Should().BeNull();\n        node.State.Should().Be(NodeState.Unconsidered);\n    }\n\n    [Test]\n    public static void GeneratePath_ReturnsPathFromTargetToRoot()\n    {\n        var start = new Node(new VecN(0, 0), true, 1.0);\n        var mid = new Node(new VecN(1, 0), true, 1.0) { Parent = start };\n        var end = new Node(new VecN(2, 0), true, 1.0) { Parent = mid };\n\n        var path = AStar.GeneratePath(end);\n\n        path.Should().HaveCount(3);\n        path[0].Should().BeSameAs(start);\n        path[1].Should().BeSameAs(mid);\n        path[2].Should().BeSameAs(end);\n    }\n\n    [Test]\n    public static void Compute_ReturnsEmptyList_WhenNoPathExists()\n    {\n        var start = new Node(new VecN(0, 0), true, 1.0);\n        var end = new Node(new VecN(1, 0), true, 1.0);\n        start.ConnectedNodes = [];\n        end.ConnectedNodes = [];\n\n        var path = AStar.Compute(start, end);\n\n        path.Should().BeEmpty();\n    }\n\n    [Test]\n    public static void Compute_ReturnsPath_WhenPathExists()\n    {\n        var start = new Node(new VecN(0, 0), true, 1.0);\n        var mid = new Node(new VecN(1, 0), true, 1.0);\n        var end = new Node(new VecN(2, 0), true, 1.0);\n\n        start.ConnectedNodes = [mid];\n        mid.ConnectedNodes = [end];\n        end.ConnectedNodes = [];\n\n        var path = AStar.Compute(start, end);\n\n        path.Should().NotBeEmpty();\n        path[0].Should().Be(start);\n        path[^1].Should().Be(end);\n    }\n\n    [Test]\n    public static void VecN_Equality_WorksAsExpected()\n    {\n        var a = new VecN(1, 2);\n        var b = new VecN(1, 2);\n        var c = new VecN(2, 1);\n\n        a.Equals(b).Should().BeTrue();\n        a.Equals(c).Should().BeFalse();\n    }\n\n    [Test]\n    public static void AddOrUpdateConnected_ThrowsPathfindingException_OnSelfReference()\n    {\n        var node = new Node(new VecN(0, 0), true, 1.0);\n        node.ConnectedNodes = [node];\n        node.State = NodeState.Open;\n\n        var queue = new PriorityQueue<Node>();\n\n        Action act = () => {\n            // Directly call the private method using reflection, otherwise we can't test this case\n            var method = typeof(AStar).GetMethod(\"AddOrUpdateConnected\", BindingFlags.NonPublic | BindingFlags.Static);\n            method!.Invoke(null, [node, node, queue]);\n        };\n\n        act.Should().Throw<TargetInvocationException>()\n            .WithInnerException<PathfindingException>()\n            .WithMessage(\"*same node twice*\");\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Search/BinarySearcherTests.cs",
    "content": "using Algorithms.Search;\n\nnamespace Algorithms.Tests.Search;\n\npublic static class BinarySearcherTests\n{\n    [Test]\n    public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int n)\n    {\n        // Arrange\n        var searcher = new BinarySearcher<int>();\n        var random = Randomizer.CreateRandomizer();\n        var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).OrderBy(x => x).ToArray();\n        var selectedIndex = random.Next(0, n);\n\n        // Act\n        var actualIndex = searcher.FindIndex(arrayToSearch, arrayToSearch[selectedIndex]);\n\n        // Assert\n        Assert.That(arrayToSearch[actualIndex], Is.EqualTo(arrayToSearch[selectedIndex]));\n    }\n\n    [Test]\n    public static void FindIndex_ItemMissing_MinusOneReturned(\n        [Random(0, 1000, 10)] int n,\n        [Random(-100, 1100, 10)] int missingItem)\n    {\n        // Arrange\n        var searcher = new BinarySearcher<int>();\n        var random = Randomizer.CreateRandomizer();\n        var arrayToSearch = Enumerable.Range(0, n)\n            .Select(_ => random.Next(0, 1000))\n            .Where(x => x != missingItem)\n            .OrderBy(x => x).ToArray();\n\n        // Act\n        var actualIndex = searcher.FindIndex(arrayToSearch, missingItem);\n\n        // Assert\n        Assert.That(actualIndex, Is.EqualTo(-1));\n    }\n\n    [Test]\n    public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemToSearch)\n    {\n        // Arrange\n        var searcher = new BinarySearcher<int>();\n        var arrayToSearch = new int[0];\n\n        // Act\n        var actualIndex = searcher.FindIndex(arrayToSearch, itemToSearch);\n\n        // Assert\n        Assert.That(actualIndex, Is.EqualTo(-1));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Search/BoyerMooreTests.cs",
    "content": "using Algorithms.Search;\r\n\r\nnamespace Algorithms.Tests.Search;\r\n\r\npublic class BoyerMoore_Tests\r\n{\r\n    [Test]\r\n    public void BoyerMoore_Majority_Finder_Test()\r\n    {\r\n        var elementCount = 1000;\r\n\r\n        var rnd = new Random();\r\n        var randomNumbers = new List<int>();\r\n\r\n        while (randomNumbers.Count < elementCount / 2)\r\n        {\r\n            randomNumbers.Add(rnd.Next(0, elementCount));\r\n        }\r\n\r\n        var majorityElement = rnd.Next(0, elementCount);\r\n\r\n        randomNumbers.AddRange(Enumerable.Repeat(majorityElement, elementCount / 2 + 1));\r\n        randomNumbers = randomNumbers.OrderBy(x => rnd.Next()).ToList();\r\n\r\n        var expected = majorityElement;\r\n        var actual = BoyerMoore<int>.FindMajority(randomNumbers);\r\n\r\n        Assert.That(expected, Is.EqualTo(actual));\r\n    }\r\n}\r\n"
  },
  {
    "path": "Algorithms.Tests/Search/FastSearcherTests.cs",
    "content": "using Algorithms.Search;\nusing Utilities.Exceptions;\n\nnamespace Algorithms.Tests.Search;\n\npublic static class FastSearcherTests\n{\n    [Test]\n    public static void FindIndex_ItemPresent_IndexCorrect()\n    {\n        // Arrange\n        var searcher = new FastSearcher();\n        var arr = Helper.GetSortedArray(1000);\n        var present = Helper.GetItemIn(arr);\n\n        // Act\n        var index = searcher.FindIndex(arr, present);\n\n        // Assert\n        arr[index].Should().Be(present);\n    }\n\n    [TestCase(new[] { 1, 2 }, 1)]\n    [TestCase(new[] { 1, 2 }, 2)]\n    [TestCase(new[] { 1, 2, 3, 3, 3 }, 2)]\n    public static void FindIndex_ItemPresentInSpecificCase_IndexCorrect(int[] arr, int present)\n    {\n        // Arrange\n        var searcher = new FastSearcher();\n\n        // Act\n        var index = searcher.FindIndex(arr, present);\n\n        // Assert\n        arr[index].Should().Be(present);\n    }\n\n    [TestCase(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 3)] // Item in left segment (< indexBinary)\n    [TestCase(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 5)] // Item at binary index\n    [TestCase(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 8)] // Item in right segment (> indexBinary)\n    [TestCase(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 1)] // Item at start\n    [TestCase(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 10)] // Item at end\n    [TestCase(new[] { 1, 10, 20, 30, 40, 50, 60, 70, 80, 90 }, 20)] // Non-uniform distribution, interpolation < binary\n    [TestCase(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 100 }, 100)] // Non-uniform distribution, interpolation > binary\n    [TestCase(new[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }, 50)] // Uniform spacing\n    [TestCase(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }, 7)] // Larger array\n    [TestCase(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }, 15)] // Larger array, right side\n    public static void FindIndex_ItemPresentDeterministic_IndexCorrect(int[] arr, int present)\n    {\n        // Arrange\n        var searcher = new FastSearcher();\n\n        // Act\n        var index = searcher.FindIndex(arr, present);\n\n        // Assert\n        arr[index].Should().Be(present);\n    }\n\n    [Test]\n    public static void FindIndex_ItemPresentInArrayOfDuplicates_IndexCorrect()\n    {\n        // Arrange\n        var searcher = new FastSearcher();\n        var arr = CreateArrayOfDuplicates(1000, 0); // Helper for large duplicate arrays\n        var present = 0;\n\n        // Act\n        var index = searcher.FindIndex(arr, present);\n\n        // Assert\n        arr[index].Should().Be(0);\n    }\n\n    [TestCase(new int[0], 2)] // Empty array\n    [TestCase(new[] { 1, 2, 3 }, 4)] // Item missing in array\n    public static void FindIndex_ItemMissing_ItemNotFoundExceptionThrown(int[] arr, int missing)\n    {\n        // Arrange\n        var searcher = new FastSearcher();\n\n        // Act\n        Action act = () => searcher.FindIndex(arr, missing);\n\n        // Assert\n        act.Should().Throw<ItemNotFoundException>();\n    }\n\n    [Test]\n    public static void FindIndex_ItemMissingInArrayOfDuplicates_ItemNotFoundExceptionThrown()\n    {\n        // Arrange\n        var searcher = new FastSearcher();\n        var arr = CreateArrayOfDuplicates(1000, 0); // Helper for large duplicate arrays\n        var missing = 1;\n\n        // Act\n        Action act = () => searcher.FindIndex(arr, missing);\n\n        // Assert\n        act.Should().Throw<ItemNotFoundException>();\n    }\n\n    [Test]\n    public static void FindIndex_ItemOutOfRange_ItemNotFoundExceptionThrown()\n    {\n        // Arrange\n        var searcher = new FastSearcher();\n        var arr = Helper.GetSortedArray(1000);\n        var smaller = Helper.GetItemSmallerThanAllIn(arr);\n        var bigger = Helper.GetItemBiggerThanAllIn(arr);\n\n        // Act & Assert\n        Action act1 = () => searcher.FindIndex(arr, smaller);\n        Action act2 = () => searcher.FindIndex(arr, bigger);\n\n        act1.Should().Throw<ItemNotFoundException>();\n        act2.Should().Throw<ItemNotFoundException>();\n    }\n\n    private static int[] CreateArrayOfDuplicates(int length, int value)\n    {\n        var arr = new int[length];\n        Array.Fill(arr, value);\n        return arr;\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Search/FibonacciSearcherTests.cs",
    "content": "using Algorithms.Search;\n\nnamespace Algorithms.Tests.Search;\n\npublic static class FibonacciSearcherTests\n{\n    [Test]\n    public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 10)] int n)\n    {\n        // Arranges\n        var searcher = new FibonacciSearcher<int>();\n        var arrayToSearch = Helper.GetSortedArray(n);\n        var present = Helper.GetItemIn(arrayToSearch);\n\n        // Act\n        var actualIndex = searcher.FindIndex(arrayToSearch, present);\n\n        // Assert\n        arrayToSearch[actualIndex].Should().Be(present);\n    }\n\n    [Test]\n    public static void FindIndex_ItemMissing_MinusOneReturned([Random(1, 1000, 10)] int n)\n    {\n        // Arranges\n        var searcher = new FibonacciSearcher<int>();\n        var arrayToSearch = Helper.GetSortedArray(n);\n        var present = Helper.GetItemNotIn(arrayToSearch);\n        var expectedIndex = -1;\n\n        // Act\n        var actualIndex = searcher.FindIndex(arrayToSearch, present);\n\n        // Assert\n        actualIndex.Should().Be(expectedIndex);\n    }\n\n    [Test]\n    public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(1, 1000, 10)] int missingItem)\n    {\n        // Arrange\n        var searcher = new FibonacciSearcher<int>();\n        var sortedArray = Array.Empty<int>();\n        var expectedIndex = -1;\n\n        // Act\n        var actualIndex = searcher.FindIndex(sortedArray, missingItem);\n\n        // Assert\n        actualIndex.Should().Be(expectedIndex);\n    }\n\n    [TestCase(null, \"a\")]\n    [TestCase(new[] { \"a\", \"b\", \"c\" }, null)]\n    [TestCase(null, null)]\n    public static void FindIndex_ArrayNull_ItemNull_ArgumentNullExceptionThrown(string[] sortedArray, string searchItem)\n    {\n        // Arranges\n        var searcher = new FibonacciSearcher<string>();\n\n        // Act\n        Action action = () => searcher.FindIndex(sortedArray, searchItem);\n\n        // Assert\n        action.Should().Throw<ArgumentNullException>();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Search/Helper.cs",
    "content": "namespace Algorithms.Tests.Search;\n\npublic static class Helper\n{\n    public static int[] GetSortedArray(int length) =>\n        Enumerable.Range(0, length)\n            .Select(_ => TestContext.CurrentContext.Random.Next(1_000_000))\n            .OrderBy(x => x)\n            .ToArray();\n\n    public static int GetItemIn(int[] arr) => arr[TestContext.CurrentContext.Random.Next(arr.Length)];\n\n    public static int GetItemNotIn(int[] arr)\n    {\n        int item;\n        do\n        {\n            item = TestContext.CurrentContext.Random.Next(arr.Min(), arr.Max() + 1);\n        }\n        while (arr.Contains(item));\n\n        return item;\n    }\n\n    public static int GetItemSmallerThanAllIn(int[] arr) => arr.Min() - 1;\n\n    public static int GetItemBiggerThanAllIn(int[] arr) => arr.Max() + 1;\n}\n"
  },
  {
    "path": "Algorithms.Tests/Search/InterpolationSearchTests.cs",
    "content": "using Algorithms.Search;\n\nnamespace Algorithms.Tests.Search;\n\npublic static class InterpolationSearchTests\n{\n    [Test]\n    public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int n)\n    {\n        // Arrange\n        var random = Randomizer.CreateRandomizer();\n        var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).OrderBy(x => x).ToArray();\n        var selectedIndex = random.Next(0, n);\n\n        // Act\n        var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, arrayToSearch[selectedIndex]);\n\n        // Assert\n        Assert.That(arrayToSearch[actualIndex], Is.EqualTo(arrayToSearch[selectedIndex]));\n    }\n\n    [Test]\n    public static void FindIndex_ItemMissing_MinusOneReturned(\n        [Random(0, 1000, 10)] int n,\n        [Random(-100, 1100, 10)] int missingItem)\n    {\n        // Arrange\n        var random = Randomizer.CreateRandomizer();\n        var arrayToSearch = Enumerable.Range(0, n)\n            .Select(_ => random.Next(0, 1000))\n            .Where(x => x != missingItem)\n            .OrderBy(x => x).ToArray();\n\n        // Act\n        var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, missingItem);\n\n        // Assert\n        Assert.That(actualIndex, Is.EqualTo(-1));\n    }\n\n    [Test]\n    public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemToSearch)\n    {\n        // Arrange\n        var arrayToSearch = new int[0];\n\n        // Act\n        var actualIndex = InterpolationSearch.FindIndex(arrayToSearch, itemToSearch);\n\n        // Assert\n        Assert.That(actualIndex, Is.EqualTo(-1));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Search/JumpSearcherTests.cs",
    "content": "using Algorithms.Search;\n\nnamespace Algorithms.Tests.Search;\n\npublic class JumpSearcherTests\n{\n    [Test]\n    public void FindIndex_ItemPresent_ItemCorrect([Random(1, 1000, 100)] int n)\n    {\n        // Arrange\n        var searcher = new JumpSearcher<int>();\n        var sortedArray = Enumerable.Range(0, n).Select(_ => TestContext.CurrentContext.Random.Next(1_000_000)).OrderBy(x => x).ToArray();\n        var expectedIndex = TestContext.CurrentContext.Random.Next(sortedArray.Length);\n\n        // Act\n        var actualIndex = searcher.FindIndex(sortedArray, sortedArray[expectedIndex]);\n\n        // Assert\n        sortedArray[actualIndex].Should().Be(sortedArray[expectedIndex]);\n    }\n\n    [Test]\n    public void FindIndex_ItemMissing_MinusOneReturned([Random(1, 1000, 10)] int n, [Random(-100, 1100, 10)] int missingItem)\n    {\n        // Arrange\n        var searcher = new JumpSearcher<int>();\n        var sortedArray = Enumerable.Range(0, n).Select(_ => TestContext.CurrentContext.Random.Next(1_000_000)).Where(x => x != missingItem).OrderBy(x => x).ToArray();\n        var expectedIndex = -1;\n\n        // Act\n        var actualIndex = searcher.FindIndex(sortedArray, missingItem);\n\n        // Assert\n        Assert.That(actualIndex, Is.EqualTo(expectedIndex));\n    }\n\n    [Test]\n    public void FindIndex_ArrayEmpty_MinusOneReturned([Random(-100, 1100, 10)] int missingItem)\n    {\n        // Arrange\n        var searcher = new JumpSearcher<int>();\n        var sortedArray = Array.Empty<int>();\n        var expectedIndex = -1;\n\n        // Act\n        var actualIndex = searcher.FindIndex(sortedArray, missingItem);\n\n        // Assert\n        Assert.That(actualIndex, Is.EqualTo(expectedIndex));\n    }\n\n    [TestCase(null, \"abc\")]\n    [TestCase(new[] { \"abc\", \"def\", \"ghi\" }, null)]\n    [TestCase(null, null)]\n    public void FindIndex_ArrayNull_ItemNull_ArgumentNullExceptionThrown(string[] sortedArray, string searchItem)\n    {\n        // Arrange\n        var searcher = new JumpSearcher<string>();\n\n        // Act, Assert\n        _ = Assert.Throws<ArgumentNullException>(() => searcher.FindIndex(sortedArray, searchItem));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Search/LinearSearcherTests.cs",
    "content": "using Algorithms.Search;\nusing Utilities.Exceptions;\n\nnamespace Algorithms.Tests.Search;\n\npublic static class LinearSearcherTests\n{\n    [Test]\n    public static void Find_ItemPresent_ItemCorrect([Random(0, 1_000_000, 100)] int n)\n    {\n        // Arrange\n        var searcher = new LinearSearcher<int>();\n        var random = Randomizer.CreateRandomizer();\n        var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).ToArray();\n\n        // Act\n        var expectedItem = Array.Find(arrayToSearch, x => x == arrayToSearch[n / 2]);\n        var actualItem = searcher.Find(arrayToSearch, x => x == arrayToSearch[n / 2]);\n\n        // Assert\n        Assert.That(actualItem, Is.EqualTo(expectedItem));\n    }\n\n    [Test]\n    public static void FindIndex_ItemPresent_IndexCorrect([Random(0, 1_000_000, 100)] int n)\n    {\n        // Arrange\n        var searcher = new LinearSearcher<int>();\n        var random = Randomizer.CreateRandomizer();\n        var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).ToArray();\n\n        // Act\n        var expectedIndex = Array.FindIndex(arrayToSearch, x => x == arrayToSearch[n / 2]);\n        var actualIndex = searcher.FindIndex(arrayToSearch, x => x == arrayToSearch[n / 2]);\n\n        // Assert\n        Assert.That(actualIndex, Is.EqualTo(expectedIndex));\n    }\n\n    [Test]\n    public static void Find_ItemMissing_ItemNotFoundExceptionThrown([Random(0, 1_000_000, 100)] int n)\n    {\n        // Arrange\n        var searcher = new LinearSearcher<int>();\n        var random = Randomizer.CreateRandomizer();\n        var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).ToArray();\n\n        // Act\n        // Assert\n        _ = Assert.Throws<ItemNotFoundException>(() => searcher.Find(arrayToSearch, _ => false));\n    }\n\n    [Test]\n    public static void FindIndex_ItemMissing_MinusOneReturned([Random(0, 1_000_000, 100)] int n)\n    {\n        // Arrange\n        var searcher = new LinearSearcher<int>();\n        var random = Randomizer.CreateRandomizer();\n        var arrayToSearch = Enumerable.Range(0, n).Select(_ => random.Next(0, 1000)).ToArray();\n\n        // Act\n        var actualIndex = searcher.FindIndex(arrayToSearch, _ => false);\n\n        // Assert\n        Assert.That(actualIndex, Is.EqualTo(-1));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Search/RecursiveBinarySearcherTests.cs",
    "content": "using Algorithms.Search;\n\nnamespace Algorithms.Tests.Search;\n\npublic static class RecursiveBinarySearcherTests\n{\n    [Test]\n    public static void FindIndex_ItemPresent_IndexCorrect([Random(1, 1000, 100)] int n)\n    {\n        // Arrange\n        var subject = new RecursiveBinarySearcher<int>();\n        var randomizer = Randomizer.CreateRandomizer();\n        var selectedIndex = randomizer.Next(0, n);\n        var collection = Enumerable.Range(0, n).Select(_ => randomizer.Next(0, 1000)).OrderBy(x => x).ToList();\n\n        // Act\n        var actualIndex = subject.FindIndex(collection, collection[selectedIndex]);\n\n        // Assert\n        Assert.That(collection[actualIndex], Is.EqualTo(collection[selectedIndex]));\n    }\n\n    [Test]\n    public static void FindIndex_ItemMissing_MinusOneReturned(\n        [Random(0, 1000, 10)] int n,\n        [Random(-100, 1100, 10)] int missingItem)\n    {\n        // Arrange\n        var subject = new RecursiveBinarySearcher<int>();\n        var random = Randomizer.CreateRandomizer();\n        var collection = Enumerable.Range(0, n)\n            .Select(_ => random.Next(0, 1000))\n            .Where(x => x != missingItem)\n            .OrderBy(x => x).ToList();\n\n        // Act\n        var actualIndex = subject.FindIndex(collection, missingItem);\n\n        // Assert\n        Assert.That(actualIndex, Is.EqualTo(-1));\n    }\n\n    [Test]\n    public static void FindIndex_ArrayEmpty_MinusOneReturned([Random(100)] int itemToSearch)\n    {\n        // Arrange\n        var subject = new RecursiveBinarySearcher<int>();\n        var collection = new int[0];\n\n        // Act\n        var actualIndex = subject.FindIndex(collection, itemToSearch);\n\n        // Assert\n        Assert.That(actualIndex, Is.EqualTo(-1));\n    }\n\n    [Test]\n    public static void FindIndex_NullCollection_Throws()\n    {\n        // Arrange\n        var subject = new RecursiveBinarySearcher<int>();\n        var collection = (IList<int>?)null;\n\n        // Act\n        Action act = () => subject.FindIndex(collection, 42);\n\n        // Assert\n        act.Should().Throw<ArgumentNullException>();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/AllOnesSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class AllOnesSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new AllOnesSequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/AllThreesSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class AllThreesSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new AllThreesSequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[] { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/AllTwosSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class AllTwosSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new AllTwosSequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[] { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/BinaryPrimeConstantSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class BinaryPrimeConstantSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new BinaryPrimeConstantSequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[] { 0, 1, 1, 0, 1, 0, 1, 0, 0, 0 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/BinomialSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class BinomialSequenceTests\n{\n    [Test]\n    public void First4RowsCorrect()\n    {\n        var sequence = new BinomialSequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[] { 1, 1, 1, 1, 2, 1, 1, 3, 3, 1 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/CakeNumbersSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class CakeNumbersSequenceTests\n{\n    [Test]\n    public void First46ElementsCorrect()\n    {\n        var sequence = new CakeNumbersSequence().Sequence.Take(46);\n        sequence.SequenceEqual(new BigInteger[]\n            {\n                1, 2, 4, 8, 15, 26, 42, 64, 93, 130,\n                176, 232, 299, 378, 470, 576, 697, 834, 988, 1160,\n                1351, 1562, 1794, 2048, 2325, 2626, 2952, 3304, 3683, 4090,\n                4526, 4992, 5489, 6018, 6580, 7176, 7807, 8474, 9178, 9920,\n                10701, 11522, 12384, 13288, 14235, 15226\n            })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/CatalanSequenceTest.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class CatalanSequenceTest\n{\n    [Test]\n    public void First30ItemsCorrect()\n    {\n        var sequence = new CatalanSequence().Sequence.Take(30);\n        sequence.SequenceEqual(new BigInteger[]     { 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440,\n                                                    9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020,\n                                                    91482563640, 343059613650, 1289904147324, 4861946401452, 18367353072152,\n                                                    69533550916004, 263747951750360, 1002242216651368})\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/CentralPolygonalNumbersSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class CentralPolygonalNumbersSequenceTests\n{\n    [Test]\n    public void First53ElementsCorrect()\n    {\n        var sequence = new CentralPolygonalNumbersSequence().Sequence.Take(53);\n        sequence.SequenceEqual(new BigInteger[]\n            {\n                1, 2, 4, 7, 11, 16, 22, 29, 37, 46, 56, 67, 79, 92, 106, 121, 137, 154, 172, 191, 211, 232, 254,\n                277, 301, 326, 352, 379, 407, 436, 466, 497, 529, 562, 596, 631, 667, 704, 742, 781, 821, 862, 904,\n                947, 991, 1036, 1082, 1129, 1177, 1226, 1276, 1327, 1379,\n            })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/CubesSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class CubesSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new CubesSequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[] { 0, 1, 8, 27, 64, 125, 216, 343, 512, 729 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/DivisorsCountSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class DivisorsCountSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        // These values are taken from https://oeis.org/A000005 for comparison.\n        BigInteger[] oeisSource =\n        [\n            1,  2, 2, 3,  2,  4,  2,  4,  3, 4, 2,  6, 2,\n            4,  4, 5, 2,  6,  2,  6,  4,  4, 2, 8,  3, 4,\n            4,  6, 2, 8,  2,  6,  4,  4,  4, 9, 2,  4, 4,\n            8,  2, 8, 2,  6,  6,  4,  2, 10, 3, 6,  4, 6,\n            2,  8, 4, 8,  4,  4,  2, 12,  2, 4, 6,  7, 4,\n            8,  2, 6, 4,  8,  2, 12,  2,  4, 6, 6,  4, 8,\n            2, 10, 5, 4,  2, 12,  4,  4,  4, 8, 2, 12, 4,\n            6,  4, 4, 4, 12,  2,  6,  6,  9, 2, 8,  2, 8,\n        ];\n\n        var sequence = new DivisorsCountSequence().Sequence.Take(oeisSource.Length);\n        sequence.SequenceEqual(oeisSource).Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/EuclidNumbersSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class EuclidNumbersSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new EuclidNumbersSequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[]\n            { 2, 3, 7, 31, 211, 2311, 30031, 510511, 9699691, 223092871 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/EulerTotientSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class EulerTotientSequenceTests\n{\n    [Test]\n    public void FirstElementsCorrect()\n    {\n        //  Let's be thorough.  500 phi values!\n        //  Initial test of 69 number from table at https://oeis.org/A000010/list and passed test.\n        //  Extended out to 500 values from https://primefan.tripod.com/Phi500.html and passed initial 69\n        // along with remaining values.\n        BigInteger[] check =\n        [\n                        1,     1,   2,   2,   4,   2,   6,   4,   6,   4,  10,   4,  12,   6,   8,   8,  16,   6,  18,   8,\n                        12,   10,  22,   8,  20,  12,  18,  12,  28,   8,  30,  16,  20,  16,  24,  12,  36,  18,  24,  16,\n                        40,   12,  42,  20,  24,  22,  46,  16,  42,  20,  32,  24,  52,  18,  40,  24,  36,  28,  58,  16,\n                        60,   30,  36,  32,  48,  20,  66,  32,  44,  24,  70,  24,  72,  36,  40,  36,  60,  24,  78,  32,\n                        54,   40,  82,  24,  64,  42,  56,  40,  88,  24,  72,  44,  60,  46,  72,  32,  96,  42,  60,  40,\n                        100,  32, 102,  48,  48,  52, 106,  36, 108,  40,  72,  48, 112,  36,  88,  56,  72,  58,  96,  32,\n                        110,  60,  80,  60, 100,  36, 126,  64,  84,  48, 130,  40, 108,  66,  72,  64, 136,  44, 138,  48,\n                        92,   70, 120,  48, 112,  72,  84,  72, 148,  40, 150,  72,  96,  60, 120,  48, 156,  78, 104,  64,\n                        132,  54, 162,  80,  80,  82, 166,  48, 156,  64, 108,  84, 172,  56, 120,  80, 116,  88, 178,  48,\n                        180,  72, 120,  88, 144,  60, 160,  92, 108,  72, 190,  64, 192,  96,  96,  84, 196,  60, 198,  80,\n                        132, 100, 168,  64, 160, 102, 132,  96, 180,  48, 210, 104, 140, 106, 168,  72, 180, 108, 144,  80,\n                        192,  72, 222,  96, 120, 112, 226,  72, 228,  88, 120, 112, 232,  72, 184, 116, 156,  96, 238,  64,\n                        240, 110, 162, 120, 168,  80, 216, 120, 164, 100, 250,  72, 220, 126, 128, 128, 256,  84, 216,  96,\n                        168, 130, 262,  80, 208, 108, 176, 132, 268,  72, 270, 128, 144, 136, 200,  88, 276, 138, 180,  96,\n                        280,  92, 282, 140, 144, 120, 240,  96, 272, 112, 192, 144, 292,  84, 232, 144, 180, 148, 264,  80,\n                        252, 150, 200, 144, 240,  96, 306, 120, 204, 120, 310,  96, 312, 156, 144, 156, 316, 104, 280, 128,\n                        212, 132, 288, 108, 240, 162, 216, 160, 276,  80, 330, 164, 216, 166, 264,  96, 336, 156, 224, 128,\n                        300, 108, 294, 168, 176, 172, 346, 112, 348, 120, 216, 160, 352, 116, 280, 176, 192, 178, 358,  96,\n                        342, 180, 220, 144, 288, 120, 366, 176, 240, 144, 312, 120, 372, 160, 200, 184, 336, 108, 378, 144,\n                        252, 190, 382, 128, 240, 192, 252, 192, 388,  96, 352, 168, 260, 196, 312, 120, 396, 198, 216, 160,\n                        400, 132, 360, 200, 216, 168, 360, 128, 408, 160, 272, 204, 348, 132, 328, 192, 276, 180, 418,  96,\n                        420, 210, 276, 208, 320, 140, 360, 212, 240, 168, 430, 144, 432, 180, 224, 216, 396, 144, 438, 160,\n                        252, 192, 442, 144, 352, 222, 296, 192, 448, 120, 400, 224, 300, 226, 288, 144, 456, 228, 288, 176,\n                        460, 120, 462, 224, 240, 232, 466, 144, 396, 184, 312, 232, 420, 156, 360, 192, 312, 238, 478, 128,\n                        432, 240, 264, 220, 384, 162, 486, 240, 324, 168, 490, 160, 448, 216, 240, 240, 420, 164, 498, 200,\n        ];\n\n        var sequence = new EulerTotientSequence().Sequence.Take(check.Length);\n        sequence.SequenceEqual(check).Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/FactorialSequenceTest.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class FactorialSequenceTest\n{\n    [Test]\n    public void First10ItemsCorrect()\n    {\n        var sequence = new FactorialSequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[] { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/FermatNumbersSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class FermatNumbersSequenceTests\n{\n    [Test]\n    public void First5ElementsCorrect()\n    {\n        var sequence = new FermatNumbersSequence().Sequence.Take(5);\n        sequence.SequenceEqual(new BigInteger[] { 3, 5, 17, 257, 65537 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/FermatPrimesSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class FermatPrimesSequenceTests\n{\n    [Test]\n    public void All5ElementsCorrect()\n    {\n        var sequence = new FermatPrimesSequence().Sequence.Take(5);\n        sequence.SequenceEqual(new BigInteger[] { 3, 5, 17, 257, 65537 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/FibonacciSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class FibonacciSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new FibonacciSequence().Sequence.Take(10);\n        BigInteger[] expected = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34];\n        sequence.SequenceEqual(expected)\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/GolombsSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class GolombsSequenceTests\n{\n    [Test]\n    public void First50ElementsCorrect()\n    {\n        // Taken from https://oeis.org/A001462\n        var expected = new BigInteger[] {\n            1, 2, 2, 3, 3, 4, 4, 4, 5, 5,\n            5, 6, 6, 6, 6, 7, 7, 7, 7, 8,\n            8, 8, 8, 9, 9, 9, 9, 9, 10, 10,\n            10, 10, 10, 11, 11, 11, 11, 11, 12, 12,\n            12, 12, 12, 12, 13, 13, 13, 13, 13, 13};\n\n        var sequence = new GolombsSequence().Sequence.Take(50);\n\n        sequence.SequenceEqual(expected).Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/KolakoskiSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class KolakoskiSequenceTests\n{\n    [Test]\n    public void First100ElementsCorrect()\n    {\n        // Taken from https://oeis.org/A000002\n        BigInteger[] expected =\n        [\n            1, 2, 2, 1, 1, 2, 1, 2, 2, 1,\n            2, 2, 1, 1, 2, 1, 1, 2, 2, 1,\n            2, 1, 1, 2, 1, 2, 2, 1, 1, 2,\n            1, 1, 2, 1, 2, 2, 1, 2, 2, 1,\n            1, 2, 1, 2, 2, 1, 2, 1, 1, 2,\n            1, 1, 2, 2, 1, 2, 2, 1, 1, 2,\n            1, 2, 2, 1, 2, 2, 1, 1, 2, 1,\n            1, 2, 1, 2, 2, 1, 2, 1, 1, 2,\n            2, 1, 2, 2, 1, 1, 2, 1, 2, 2,\n            1, 2, 2, 1, 1, 2, 1, 1, 2, 2,\n        ];\n\n        var sequence = new KolakoskiSequence().Sequence.Take(100);\n        var sequence2 = new KolakoskiSequence2().Sequence.Take(100);\n\n        sequence.Should().Equal(expected);\n        sequence2.Should().Equal(expected);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/KummerNumbersSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class KummerNumbersSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new KummerNumbersSequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[]\n            { 1, 5, 29, 209, 2309, 30029, 510509, 9699689, 223092869, 6469693229 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/LucasNumbersBeginningAt2SequenceTests.cs",
    "content": "﻿using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class LucasNumbersBeginningAt2SequenceTests\n{\n    [Test]\n    public void FirstElementsCorrect()\n    {\n        //  Initial test of 38 values from http://oeis.org/A000032/list which passed.\n        //  Testing 200 Lucas numbers, with values from https://r-knott.surrey.ac.uk/Fibonacci/lucas200.html and\n        //  compared to initial 38, which passed.\n        //  Assigning numeric values to BigInteger types performed by string parsing dues to length of value.\n        var bigNumbers = new[] {\n                                   \"2\", \"1\", \"3\", \"4\", \"7\", \"11\", \"18\", \"29\", \"47\", \"76\", \"123\", \"199\", \"322\",\n                                   \"521\", \"843\", \"1364\", \"2207\", \"3571\", \"5778\", \"9349\", \"15127\", \"24476\",\n                                   \"39603\", \"64079\", \"103682\", \"167761\", \"271443\", \"439204\", \"710647\", \"1149851\",\n                                   \"1860498\", \"3010349\", \"4870847\", \"7881196\", \"12752043\", \"20633239\", \"33385282\",\n                                   \"54018521\", \"87403803\", \"141422324\", \"228826127\", \"370248451\", \"599074578\",\n                                   \"969323029\", \"1568397607\", \"2537720636\", \"4106118243\", \"6643838879\",\n                                   \"10749957122\", \"17393796001\", \"28143753123\", \"45537549124\", \"73681302247\",\n                                   \"119218851371\", \"192900153618\", \"312119004989\", \"505019158607\", \"817138163596\",\n                                   \"1322157322203\", \"2139295485799\", \"3461452808002\", \"5600748293801\",\n                                   \"9062201101803\", \"14662949395604\", \"23725150497407\", \"38388099893011\",\n                                   \"62113250390418\", \"100501350283429\", \"162614600673847\", \"263115950957276\",\n                                   \"425730551631123\", \"688846502588399\", \"1114577054219522\", \"1803423556807921\",\n                                   \"2918000611027443\", \"4721424167835364\", \"7639424778862807\",\n                                   \"12360848946698171\", \"20000273725560978\", \"32361122672259149\",\n                                   \"52361396397820127\", \"84722519070079276\", \"137083915467899403\",\n                                   \"221806434537978679\", \"358890350005878082\", \"580696784543856761\",\n                                   \"939587134549734843\", \"1520283919093591604\", \"2459871053643326447\",\n                                   \"3980154972736918051\", \"6440026026380244498\", \"10420180999117162549\",\n                                   \"16860207025497407047\", \"27280388024614569596\", \"44140595050111976643\",\n                                   \"71420983074726546239\", \"115561578124838522882\", \"186982561199565069121\",\n                                   \"302544139324403592003\", \"489526700523968661124\", \"792070839848372253127\",\n                                   \"1281597540372340914251\", \"2073668380220713167378\", \"3355265920593054081629\",\n                                   \"5428934300813767249007\", \"8784200221406821330636\", \"14213134522220588579643\",\n                                   \"22997334743627409910279\", \"37210469265847998489922\",\n                                   \"60207804009475408400201\", \"97418273275323406890123\",\n                                   \"157626077284798815290324\", \"255044350560122222180447\",\n                                   \"412670427844921037470771\", \"667714778405043259651218\",\n                                   \"1080385206249964297121989\", \"1748099984655007556773207\",\n                                   \"2828485190904971853895196\", \"4576585175559979410668403\",\n                                   \"7405070366464951264563599\", \"11981655542024930675232002\",\n                                   \"19386725908489881939795601\", \"31368381450514812615027603\",\n                                   \"50755107359004694554823204\", \"82123488809519507169850807\",\n                                   \"132878596168524201724674011\", \"215002084978043708894524818\"\n                                 , \"347880681146567910619198829\", \"562882766124611619513723647\",\n                                   \"910763447271179530132922476\", \"1473646213395791149646646123\",\n                                   \"2384409660666970679779568599\", \"3858055874062761829426214722\",\n                                   \"6242465534729732509205783321\", \"10100521408792494338631998043\",\n                                   \"16342986943522226847837781364\", \"26443508352314721186469779407\",\n                                   \"42786495295836948034307560771\", \"69230003648151669220777340178\",\n                                   \"112016498943988617255084900949\", \"181246502592140286475862241127\",\n                                   \"293263001536128903730947142076\", \"474509504128269190206809383203\",\n                                   \"767772505664398093937756525279\", \"1242282009792667284144565908482\",\n                                   \"2010054515457065378082322433761\", \"3252336525249732662226888342243\",\n                                   \"5262391040706798040309210776004\", \"8514727565956530702536099118247\",\n                                   \"13777118606663328742845309894251\", \"22291846172619859445381409012498\",\n                                   \"36068964779283188188226718906749\", \"58360810951903047633608127919247\",\n                                   \"94429775731186235821834846825996\", \"152790586683089283455442974745243\",\n                                   \"247220362414275519277277821571239\", \"400010949097364802732720796316482\",\n                                   \"647231311511640322009998617887721\", \"1047242260609005124742719414204203\",\n                                   \"1694473572120645446752718032091924\", \"2741715832729650571495437446296127\",\n                                   \"4436189404850296018248155478388051\", \"7177905237579946589743592924684178\",\n                                   \"11614094642430242607991748403072229\", \"18791999880010189197735341327756407\",\n                                   \"30406094522440431805727089730828636\", \"49198094402450621003462431058585043\",\n                                   \"79604188924891052809189520789413679\", \"128802283327341673812651951847998722\",\n                                   \"208406472252232726621841472637412401\", \"337208755579574400434493424485411123\",\n                                   \"545615227831807127056334897122823524\", \"882823983411381527490828321608234647\",\n                                   \"1428439211243188654547163218731058171\",\n                                   \"2311263194654570182037991540339292818\",\n                                   \"3739702405897758836585154759070350989\",\n                                   \"6050965600552329018623146299409643807\",\n                                   \"9790668006450087855208301058479994796\",\n                                   \"15841633607002416873831447357889638603\",\n                                   \"25632301613452504729039748416369633399\",\n                                   \"41473935220454921602871195774259272002\",\n                                   \"67106236833907426331910944190628905401\",\n                                   \"108580172054362347934782139964888177403\",\n                                   \"175686408888269774266693084155517082804\",\n                                   \"284266580942632122201475224120405260207\",\n                                   \"459952989830901896468168308275922343011\",\n                                   \"744219570773534018669643532396327603218\",\n                                   \"1204172560604435915137811840672249946229\",\n                                   \"1948392131377969933807455373068577549447\",\n                                   \"3152564691982405848945267213740827495676\",\n                                   \"5100956823360375782752722586809405045123\",\n                                   \"8253521515342781631697989800550232540799\",\n                                   \"13354478338703157414450712387359637585922\",\n                                   \"21607999854045939046148702187909870126721\",\n                                   \"34962478192749096460599414575269507712643\",\n                                   \"56570478046795035506748116763179377839364\",\n                                   \"91532956239544131967347531338448885552007\",\n                                   \"148103434286339167474095648101628263391371\",\n                                   \"239636390525883299441443179440077148943378\",\n                                   \"387739824812222466915538827541705412334749\",\n                                   \"627376215338105766356982006981782561278127\",\n                               };\n\n        var check = bigNumbers.Select(BigInteger.Parse).ToArray();\n        var sequence = new LucasNumbersBeginningAt2Sequence().Sequence.Take(check.Length);\n        sequence.SequenceEqual(check).Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/MakeChangeSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class MakeChangeSequenceTests\n{\n    [Test]\n    public void First100ElementsCorrect()\n    {\n        // Values from https://oeis.org/A000008/b000008.txt\n        var test = new BigInteger[]\n                   {\n                       1,       1,    2,    2,    3,    4,    5,    6,    7,    8,\n                       11,     12,   15,   16,   19,   22,   25,   28,   31,   34,\n                       40,     43,   49,   52,   58,   64,   70,   76,   82,   88,\n                       98,    104,  114,  120,  130,  140,  150,  160,  170,  180,\n                       195,   205,  220,  230,  245,  260,  275,  290,  305,  320,\n                       341,   356,  377,  392,  413,  434,  455,  476,  497,  518,\n                       546,   567,  595,  616,  644,  672,  700,  728,  756,  784,\n                       820,   848,  884,  912,  948,  984, 1020, 1056, 1092, 1128,\n                       1173, 1209, 1254, 1290, 1335, 1380, 1425, 1470, 1515, 1560,\n                       1615, 1660, 1715, 1760, 1815, 1870, 1925, 1980, 2035, 2090,\n                   };\n\n        var sequence = new MakeChangeSequence().Sequence.Take(test.Length);\n        sequence.SequenceEqual(test).Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/MatchstickTriangleSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\n[TestFixture]\npublic static class MatchstickTriangleSequenceTests\n{\n    private static BigInteger[] _testList = [\n                                               0, 1, 5, 13, 27, 48, 78, 118, 170, 235, 315, 411, 525, 658,\n                                               812, 988, 1188, 1413, 1665, 1945, 2255, 2596, 2970, 3378,\n                                               3822, 4303, 4823, 5383, 5985, 6630, 7320, 8056, 8840, 9673,\n                                               10557, 11493, 12483, 13528, 14630, 15790, 17010, 18291,\n                                               19635, 21043, 22517,\n                                           ];\n    /// <summary>\n    ///     This test uses the list values provided from http://oeis.org/A002717/list.\n    /// </summary>\n    [Test]\n    public static void TestOeisList()\n    {\n        var sequence = new MatchstickTriangleSequence().Sequence.Take(_testList.Length);\n        sequence.SequenceEqual(_testList).Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/NaturalSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class NaturalSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new NaturalSequence().Sequence.Take(10);\n        BigInteger[] expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n        sequence.SequenceEqual(expected)\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/NegativeIntegersSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class NegativeIntegersSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new NegativeIntegersSequence().Sequence.Take(10);\n        BigInteger[] expected = [-1, -2, -3, -4, -5, -6, -7, -8, -9, -10];\n        sequence.SequenceEqual(expected)\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/NumberOfBooleanFunctionsSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class NumberOfBooleanFunctionsSequenceTests\n{\n    [Test]\n    public void First5ElementsCorrect()\n    {\n        var sequence = new NumberOfBooleanFunctionsSequence().Sequence.Take(5);\n        sequence.SequenceEqual(new BigInteger[] { 2, 4, 16, 256, 65536 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/NumberOfPrimesByNumberOfDigitsSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class NumberOfPrimesByNumberOfDigitsSequenceTests\n{\n    [Test]\n    public void First5ElementsCorrect()\n    {\n        var sequence = new NumberOfPrimesByNumberOfDigitsSequence().Sequence.Take(5);\n        sequence.SequenceEqual(new BigInteger[] { 0, 4, 21, 143, 1061 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/NumberOfPrimesByPowersOf10SequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class NumberOfPrimesByPowersOf10SequenceTests\n{\n    [Test]\n    public void First5ElementsCorrect()\n    {\n        var sequence = new NumberOfPrimesByPowersOf10Sequence().Sequence.Take(5);\n        sequence.SequenceEqual(new BigInteger[] { 0, 4, 25, 168, 1229 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/OnesCountingSequenceTest.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\n[TestFixture]\npublic class OnesCountingSequenceTest\n{\n    /// <summary>\n    ///     <para>\n    ///         Values taken from http://oeis.org/A000120/b000120.txt.\n    ///     </para>\n    ///     <para>\n    ///         While the file contains 10,000 values, this only tests 1000.\n    ///     </para>\n    /// </summary>\n    private readonly BigInteger[] oeisValues = [\n                                                   0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2,\n                                                   3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3,\n                                                   3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3,\n                                                   4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,\n                                                   3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,\n                                                   6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4,\n                                                   4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5,\n                                                   6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,\n                                                   3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3,\n                                                   4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6,\n                                                   6, 7, 6, 7, 7, 8, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3,\n                                                   4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,\n                                                   4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3,\n                                                   4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6,\n                                                   6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,\n                                                   7, 5, 6, 6, 7, 6, 7, 7, 8, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,\n                                                   3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4,\n                                                   5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 3, 4,\n                                                   4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6,\n                                                   7, 6, 7, 7, 8, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7,\n                                                   6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3,\n                                                   4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4,\n                                                   4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6,\n                                                   7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,\n                                                   4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4,\n                                                   5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4,\n                                                   4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4,\n                                                   5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7,\n                                                   6, 7, 7, 8, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5,\n                                                   6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7,\n                                                   7, 8, 5, 6, 6, 7, 6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9, 2, 3, 3, 4, 3, 4, 4,\n                                                   5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,\n                                                   3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5,\n                                                   6, 6, 7, 6, 7, 7, 8, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5,\n                                                   5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6,\n                                                   7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9, 3, 4, 4, 5,\n                                                   4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6,\n                                                   7, 7, 8, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7,\n                                                   7, 8, 6, 7, 7, 8, 7, 8, 8, 9, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7,\n                                                   8, 5, 6, 6, 7, 6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9, 5, 6, 6, 7, 6, 7, 7, 8,\n                                               ];\n\n    /// <summary>\n    ///     <para>\n    ///         Performs number of ones in the binary representation of a BigInteger.\n    ///     </para>\n    ///     <para>\n    ///         This is used as a check to compare the provided values from OEIS.\n    ///     </para>\n    /// </summary>\n    /// <param name=\"i\">BigInteger value to count 1s in</param>\n    /// <returns>Number of 1s in binary representation of number.</returns>\n    private int CountOnes(BigInteger i)\n    {\n        var temp = i;\n        BigInteger remainder = 0;\n        var result = 0;\n\n        while (temp != BigInteger.Zero)\n        {\n            temp = BigInteger.DivRem(temp, 2, out remainder);\n            result += remainder.IsOne ? 1 : 0;\n        }\n\n        return result;\n    }\n\n\n    [Test]\n    public void Count1000()\n    {\n        //  Compare generated sequence against provided data\n        var sequence = new OnesCountingSequence().Sequence.Take(oeisValues.Length);\n        sequence.SequenceEqual(oeisValues).Should().BeTrue();\n    }\n\n    [Test]\n    public void CompareAgainstCalculated()\n    {\n        //  Calculate 1s in binary value the old fashioned way.\n        var calculated = new List<BigInteger>();\n        for (var i = 0; i < oeisValues.Length; i++)\n        {\n            calculated.Add(CountOnes(new BigInteger(i)));\n        }\n\n        calculated.SequenceEqual(oeisValues).Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/PowersOf10SequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class PowersOf10SequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new PowersOf10Sequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[]\n            { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/PowersOf2SequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class PowersOf2SequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new PowersOf2Sequence().Sequence.Take(10);\n        BigInteger[] expected = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512];\n        sequence.SequenceEqual(expected)\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/PrimePiSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class PrimePiSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new PrimePiSequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[] { 0, 1, 2, 2, 3, 3, 4, 4, 4, 4 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/PrimesSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class PrimesSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new PrimesSequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/PrimorialNumbersSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class PrimorialNumbersSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new PrimorialNumbersSequence().Sequence.Take(10);\n        sequence.SequenceEqual(new BigInteger[]\n            { 1, 2, 6, 30, 210, 2310, 30030, 510510, 9699690, 223092870 })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/RecamansSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class RecamansSequenceTests\n{\n    [Test]\n    public void First50ElementsCorrect()\n    {\n        // Taken from http://oeis.org/A005132\n        var expected = new BigInteger[]\n        {\n            0, 1, 3, 6, 2, 7, 13, 20, 12, 21,\n            11, 22, 10, 23, 9, 24, 8, 25, 43, 62,\n            42, 63, 41, 18, 42, 17, 43, 16, 44, 15,\n            45, 14, 46, 79, 113, 78, 114, 77, 39, 78,\n            38, 79, 37, 80, 36, 81, 35, 82, 34, 83,\n        };\n\n        var sequence = new RecamansSequence().Sequence.Take(50);\n\n        sequence.Should().Equal(expected);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/SquaresSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class SquaresSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new SquaresSequence().Sequence.Take(10);\n        BigInteger[] expected = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81];\n        sequence.SequenceEqual(expected)\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/TetrahedralSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\n[TestFixture]\npublic class TetrahedralSequenceTests\n{\n    private static readonly BigInteger[] TestList = [\n                                                        0, 1, 4, 10, 20, 35, 56, 84, 120, 165, 220, 286, 364, 455,\n                                                        560, 680, 816, 969, 1140, 1330, 1540, 1771, 2024, 2300,\n                                                        2600, 2925, 3276, 3654, 4060, 4495, 4960, 5456, 5984, 6545,\n                                                        7140, 7770, 8436, 9139, 9880, 10660, 11480, 12341, 13244,\n                                                        14190, 15180,\n                                                    ];\n\n    /// <summary>\n    ///     This test uses the list values provided from http://oeis.org/A000292/list.\n    /// </summary>\n    [Test]\n    public void TestOeisList()\n    {\n        var sequence = new TetrahedralSequence().Sequence.Take(TestList.Length);\n        sequence.SequenceEqual(TestList).Should().BeTrue();\n\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/TetranacciNumbersSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class TetranacciNumbersSequenceTests\n{\n    [Test]\n    public void First35ElementsCorrect()\n    {\n        var sequence = new TetranacciNumbersSequence().Sequence.Take(35);\n        BigInteger[] expected =\n        [\n            1, 1, 1, 1, 4, 7, 13, 25, 49, 94, 181, 349, 673, 1297, 2500, 4819, 9289, 17905, 34513, 66526, 128233,\n            247177, 476449, 918385, 1770244, 3412255, 6577333, 12678217, 24438049, 47105854, 90799453, 175021573,\n            337364929, 650291809, 1253477764,\n        ];\n        sequence.SequenceEqual(expected)\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/ThreeNPlusOneStepsSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class ThreeNPlusOneStepsSequenceTests\n{\n    [Test]\n    public void First50ElementsCorrect()\n    {\n        var sequence = new ThreeNPlusOneStepsSequence().Sequence.Take(50);\n        var first50 = new BigInteger[] {\n            0, 1, 7, 2, 5, 8, 16, 3, 19, 6,\n            14, 9, 9, 17, 17, 4, 12, 20, 20, 7,\n            7, 15, 15, 10, 23, 10, 111, 18, 18, 18,\n            106, 5, 26, 13, 13, 21, 21, 21, 34, 8,\n            109, 8, 29, 16, 16, 16, 104, 11, 24, 24\n        };\n        sequence.SequenceEqual(first50).Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/TribonacciNumbersSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class TribonacciNumbersSequenceTests\n{\n    [Test]\n    public void First37ElementsCorrect()\n    {\n        var sequence = new TribonacciNumbersSequence().Sequence.Take(37);\n        sequence.SequenceEqual(new BigInteger[]\n            {\n                1, 1, 1, 3, 5, 9, 17, 31, 57, 105, 193, 355, 653, 1201, 2209, 4063, 7473, 13745, 25281, 46499, 85525,\n                157305, 289329, 532159, 978793, 1800281, 3311233, 6090307, 11201821, 20603361, 37895489, 69700671,\n                128199521, 235795681, 433695873, 797691075, 1467182629,\n            })\n            .Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/VanEcksSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class VanEcksSequenceTests\n{\n    [Test]\n    public void First50ElementsCorrect()\n    {\n        // Taken from http://oeis.org/A181391\n        BigInteger[] expected =\n        [\n            0, 0, 1, 0, 2, 0, 2, 2, 1, 6,\n            0, 5, 0, 2, 6, 5, 4, 0, 5, 3,\n            0, 3, 2, 9, 0, 4, 9, 3, 6, 14,\n            0, 6, 3, 5, 15, 0, 5, 3, 5, 2,\n            17, 0, 6, 11, 0, 3, 8, 0, 3, 3,\n        ];\n\n        var sequence = new VanEcksSequence().Sequence.Take(50);\n\n        sequence.Should().Equal(expected);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sequences/ZeroSequenceTests.cs",
    "content": "using Algorithms.Sequences;\n\nnamespace Algorithms.Tests.Sequences;\n\npublic class ZeroSequenceTests\n{\n    [Test]\n    public void First10ElementsCorrect()\n    {\n        var sequence = new ZeroSequence().Sequence.Take(10);\n        sequence.SequenceEqual(Enumerable.Repeat(BigInteger.Zero, 10))\n                .Should().BeTrue();\n    }\n\n}\n"
  },
  {
    "path": "Algorithms.Tests/Shufflers/FisherYatesShufflerTests.cs",
    "content": "using Algorithms.Shufflers;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Shufflers;\n\npublic static class FisherYatesShufflerTests\n{\n    [Test]\n    public static void ArrayShuffled_NewArrayHasSameSize(\n        [Random(10, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var shuffler = new FisherYatesShuffler<int>();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        shuffler.Shuffle(testArray);\n\n        // Assert\n        testArray.Length.Should().Be(correctArray.Length);\n    }\n\n    [Test]\n    public static void ArrayShuffled_NewArrayHasSameValues(\n        [Random(0, 100, 10, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var shuffler = new FisherYatesShuffler<int>();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        shuffler.Shuffle(testArray);\n\n        // Assert\n        testArray.Should().BeEquivalentTo(correctArray);\n    }\n\n    [Test]\n    public static void ArrayShuffled_SameShuffle(\n       [Random(0, 1000, 2, Distinct = true)] int n,\n       [Random(1000, 10000, 5, Distinct = true)] int seed)\n    {\n        // Arrange\n        var shuffler = new FisherYatesShuffler<int>();\n        var (array1, array2) = RandomHelper.GetArrays(n);\n\n        // Act\n        shuffler.Shuffle(array1, seed);\n        shuffler.Shuffle(array2, seed);\n\n        // Assert\n        array1.Should().BeEquivalentTo(array2, options => options.WithStrictOrdering());\n    }\n\n    [Test]\n    public static void ArrayShuffled_DifferentSeedDifferentShuffle(\n      [Random(10, 100, 2, Distinct = true)] int n,\n      [Random(1000, 10000, 5, Distinct = true)] int seed)\n    {\n        // Arrange\n        var shuffler = new FisherYatesShuffler<int>();\n        var (array1, array2) = RandomHelper.GetArrays(n);\n\n        // Act\n        shuffler.Shuffle(array1, seed);\n        shuffler.Shuffle(array2, seed + 13);\n\n        // It seems the actual version of FluentAssertion has no options in NotBeEquivalentTo.\n        // With default options, it does not check for order, but for the same elements in the collection.\n        // So until the library is updated check that not all the items have the same order.\n        int hits = 0;\n        for (int i = 0; i < n; i++)\n        {\n            if (array1[i] == array2[i])\n            {\n                hits++;\n            }\n        }\n        hits.Should().BeLessThan(array2.Length);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Shufflers/LINQShufflerTests.cs",
    "content": "using Algorithms.Shufflers;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Shufflers\n{\n    public static class LinqShufflerTests\n    {\n        [Test]\n        public static void ArrayShuffled_NewArraySameSize(\n            [Random(10, 1000, 100, Distinct = true)]\n            int n)\n        {\n            // Arrange\n            var shuffler = new LinqShuffler<int>();\n            var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n            // Act\n            shuffler.Shuffle(testArray);\n\n            // Assert\n            testArray.Length.Should().Be(correctArray.Length);\n        }\n\n        [Test]\n        public static void ArrayShuffled_NewArraySameValues(\n            [Random(10, 1000, 100, Distinct = true)]\n            int n)\n        {\n            // Arrange\n            var shuffler = new LinqShuffler<int>();\n            var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n            // Act\n            shuffler.Shuffle(testArray);\n\n            // Assert\n            testArray.Should().BeEquivalentTo(correctArray);\n        }\n\n        [Test]\n        public static void ArrayShuffled_NewArraySameShuffle(\n            [Random(0, 1000, 2, Distinct = true)] int n,\n            [Random(1000, 10000, 5, Distinct = true)] int seed)\n        {\n            // Arrange\n            var shuffle = new LinqShuffler<int>();\n            var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n            // Act\n            shuffle.Shuffle(testArray, seed);\n            shuffle.Shuffle(correctArray, seed);\n\n            // Assert\n            correctArray.Should().BeEquivalentTo(testArray, options => options.WithStrictOrdering());\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Shufflers/NaiveShufflerTests.cs",
    "content": "using Algorithms.Shufflers;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Shufflers\n{\n    public static class NaiveShufflerTests\n    {\n        [Test]\n        public static void ArrayShuffled_NewArraySameSize(\n            [Random(10, 1000, 100, Distinct = true)]\n            int n)\n        {\n            // Arrange\n            var shuffler = new NaiveShuffler<int>();\n            var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n            // Act\n            shuffler.Shuffle(testArray);\n\n            // Assert\n            testArray.Length.Should().Be(correctArray.Length);\n        }\n\n        [Test]\n        public static void ArrayShuffled_NewArraySameValues(\n            [Random(10, 1000, 100, Distinct = true)]\n            int n)\n        {\n            // Arrange\n            var shuffler = new NaiveShuffler<int>();\n            var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n            // Act\n            shuffler.Shuffle(testArray);\n\n            // Assert\n            testArray.Should().BeEquivalentTo(correctArray);\n        }\n\n        [Test]\n        public static void ArrayShuffled_NewArraySameShuffle(\n            [Random(0, 1000, 2, Distinct = true)] int n,\n            [Random(1000, 10000, 5, Distinct = true)] int seed)\n        {\n            // Arrange\n            var shuffle = new NaiveShuffler<int>();\n            var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n            // Act\n            shuffle.Shuffle(testArray, seed);\n            shuffle.Shuffle(correctArray, seed);\n\n            // Assert\n            correctArray.Should().BeEquivalentTo(testArray, options => options.WithStrictOrdering());\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs",
    "content": "using Algorithms.Shufflers;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Shufflers\n{\n    public static class RecursiveShufflerTests\n    {\n        [Test]\n        public static void ArrayShuffled_NewArraySameSize(\n            [Random(10, 1000, 100, Distinct = true)]\n            int n)\n        {\n            // Arrange\n            var shuffler = new RecursiveShuffler<int>();\n            var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n            // Act\n            shuffler.Shuffle(testArray);\n\n            // Assert\n            testArray.Length.Should().Be(correctArray.Length);\n        }\n\n        [Test]\n        public static void ArrayShuffled_NewArraySameValues(\n            [Random(10, 1000, 100, Distinct = true)]\n            int n)\n        {\n            // Arrange\n            var shuffler = new RecursiveShuffler<int>();\n            var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n            // Act\n            shuffler.Shuffle(testArray);\n\n            // Assert\n            testArray.Should().BeEquivalentTo(correctArray);\n        }\n\n        [Test]\n        public static void ArrayShuffled_NewArraySameShuffle(\n            [Random(0, 1000, 2, Distinct = true)] int n,\n            [Random(1000, 10000, 5, Distinct = true)] int seed)\n        {\n            // Arrange\n            var shuffler = new RecursiveShuffler<int>();\n            var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n            // Act\n            shuffler.Shuffle(testArray, seed);\n            shuffler.Shuffle(correctArray, seed);\n\n            // Assert\n            correctArray.Should().BeEquivalentTo(testArray, options => options.WithStrictOrdering());\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/BasicTeamSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\n\nnamespace Algorithms.Tests.Sorters.Comparison\n{\n    [TestFixture]\n    public class BasicTimSorterTests\n    {\n        private readonly BasicTimSorter<int> sorter = new(Comparer<int>.Default);\n\n        [Test]\n        public void Sort_EmptyArray_DoesNotThrow()\n        {\n            var array = Array.Empty<int>();\n            Assert.DoesNotThrow(() => sorter.Sort(array));\n            Assert.That(array, Is.Empty);\n        }\n\n        [Test]\n        public void Sort_SingleElementArray_DoesNotChangeArray()\n        {\n            var array = new[] { 1 };\n            sorter.Sort(array);\n            Assert.That(array, Is.EqualTo(new[] { 1 }));\n        }\n\n        [Test]\n        public void Sort_AlreadySortedArray_DoesNotChangeArray()\n        {\n            var array = new[] { 1, 2, 3, 4, 5 };\n            sorter.Sort(array);\n            Assert.That(array, Is.EqualTo(new[] { 1, 2, 3, 4, 5 }));\n        }\n\n        [Test]\n        public void Sort_UnsortedArray_SortsCorrectly()\n        {\n            var array = new[] { 5, 3, 1, 4, 2 };\n            sorter.Sort(array);\n            Assert.That(array, Is.EqualTo(new[] { 1, 2, 3, 4, 5 }));\n        }\n\n        [Test]\n        public void Sort_ReverseSortedArray_SortsCorrectly()\n        {\n            var array = new[] { 5, 4, 3, 2, 1 };\n            sorter.Sort(array);\n            Assert.That(array, Is.EqualTo(new[] { 1, 2, 3, 4, 5 }));\n        }\n\n        [Test]\n        public void Sort_ArrayWithDuplicates_SortsCorrectly()\n        {\n            var array = new[] { 3, 1, 2, 3, 1, 2 };\n            sorter.Sort(array);\n            Assert.That(array, Is.EqualTo(new[] { 1, 1, 2, 2, 3, 3 }));\n        }\n\n        [Test]\n        public void Sort_LargeArray_SortsCorrectly()\n        {\n            var array = new int[1000];\n            for (var i = 0; i < 1000; i++)\n            {\n                array[i] = 1000 - i;\n            }\n            sorter.Sort(array);\n            array.Should().BeInAscendingOrder();\n        }\n\n        [Test]\n        public void Sort_LargeRandomArray_SortsCorrectly()\n        {\n            var array = new int[1000];\n            var random = new Random();\n            for (var i = 0; i < 1000; i++)\n            {\n                array[i] = random.Next(1, 1001);\n            }\n            sorter.Sort(array);\n            array.Should().BeInAscendingOrder();\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/BinaryInsertionSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class BinaryInsertionSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new BinaryInsertionSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/BogoSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class BogoSorterTests\n{\n    [Test]\n    public static void ArraySorted([Random(0, 10, 10, Distinct = true)] int n)\n    {\n        // Arrange\n        var sorter = new BogoSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/BubbleSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class BubbleSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new BubbleSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/CocktailSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class CocktailSorterTests\n{\n    [Test]\n    public static void SortsArray(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new CocktailSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray);\n\n        // Assert\n        Assert.That(testArray, Is.EqualTo(correctArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/CombSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class CombSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new CombSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n\n    [Test]\n    public static void ArraySorted_WithCustomShrinkFactor(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new CombSorter<int>(1.5);\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/CycleSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class CycleSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new CycleSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray);\n\n        // Assert\n        Assert.That(testArray, Is.EqualTo(correctArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/ExchangeSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class ExchangeSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new ExchangeSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/GnomeSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class GnomeSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new GnomeSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/HeapSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class HeapSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new HeapSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray);\n\n        // Assert\n        Assert.That(testArray, Is.EqualTo(correctArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/InsertionSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class InsertionSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new InsertionSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/MedianOfThreeQuickSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class MedianOfThreeQuickSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new MedianOfThreeQuickSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/MergeSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\n/// <summary>\n///     Class for testing merge sorter algorithm.\n/// </summary>\npublic static class MergeSorterTests\n{\n    [Test]\n    public static void TestOnMergeSorter(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new MergeSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray);\n\n        // Assert\n        Assert.That(testArray, Is.EqualTo(correctArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/MiddlePointQuickSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class MiddlePointQuickSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new MiddlePointQuickSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/PancakeSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class PancakeSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new PancakeSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/RandomPivotQuickSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class RandomPivotQuickSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new RandomPivotQuickSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/SelectionSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class SelectionSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new SelectionSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/ShellSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class ShellSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new ShellSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Comparison/TimSorterTests.cs",
    "content": "using Algorithms.Sorters.Comparison;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Comparison;\n\npublic static class TimSorterTests\n{\n    private static readonly IntComparer IntComparer = new();\n    private static readonly TimSorterSettings Settings = new();\n\n    [Test]\n    public static void Sort_ShouldBeEquivalentToSuccessfulBasicSort(\n        [Random(0, 10_000, 5000)] int n)\n    {\n        // Arrange\n        var sorter = new TimSorter<int>(Settings, IntComparer);\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray, IntComparer);\n        Array.Sort(correctArray, IntComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n\n    [Test]\n    public static void Sort_TinyArray_ShouldSortCorrectly()\n    {\n        // Arrange\n        var sorter = new TimSorter<int>(Settings, IntComparer);\n        var tinyArray = new[] { 1 };\n        var correctArray = new[] { 1 };\n\n        // Act\n        sorter.Sort(tinyArray, IntComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(tinyArray));\n    }\n\n    [Test]\n    public static void Sort_SmallChunks_ShouldSortCorrectly()\n    {\n        // Arrange\n        var sorter = new TimSorter<int>(Settings, IntComparer);\n        var (correctArray, testArray) = RandomHelper.GetArrays(800);\n        Array.Sort(correctArray, IntComparer);\n        Array.Sort(testArray, IntComparer);\n\n        var max = testArray.Max();\n        var min = testArray.Min();\n\n        correctArray[0] = max;\n        correctArray[800 - 1] = min;\n        testArray[0] = max;\n        testArray[800 - 1] = min;\n\n        // Act\n        sorter.Sort(testArray, IntComparer);\n        Array.Sort(correctArray, IntComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n\n    [Test]\n    public static void Sort_ThrowsArgumentNullException_WhenArrayIsNull()\n    {\n        // Arrange\n        var sorter = new TimSorter<int>(Settings, IntComparer);\n\n        // Act & Assert\n        Assert.Throws<ArgumentNullException>(() => sorter.Sort(null!, IntComparer));\n    }\n\n    [Test]\n    public static void Sort_UsesDefaultComparer_WhenComparerIsNull()\n    {\n        // Arrange\n        var sorter = new TimSorter<int>(Settings, null!);\n        var (correctArray, testArray) = RandomHelper.GetArrays(20);\n\n        // Act\n        sorter.Sort(testArray, IntComparer);\n        Array.Sort(correctArray, IntComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n\n    [Test]\n    public static void Sort_AlreadySortedArray_RemainsUnchanged()\n    {\n        // Arrange\n        var sorter = new TimSorter<int>(Settings, IntComparer);\n        var array = new[] { 1, 2, 3, 4, 5 };\n        var expected = new[] { 1, 2, 3, 4, 5 };\n\n        // Act\n        sorter.Sort(array, IntComparer);\n\n        // Assert\n        Assert.That(array, Is.EqualTo(expected));\n    }\n\n    [Test]\n    public static void MergeAt_ShouldReturnEarly_WhenLenAIsZero()\n    {\n        // Arrange: left run is all less than right run's first element\n        var array = Enumerable.Range(1, 25).Concat(Enumerable.Range(100, 25)).ToArray();\n        var sortedArray = Enumerable.Range(1, 25).Concat(Enumerable.Range(100, 25)).ToArray();\n        var sorter = new TimSorter<int>(new TimSorterSettings(), Comparer<int>.Default);\n\n        // Act\n        sorter.Sort(array, Comparer<int>.Default);\n\n        // Assert: Array order will not have changed, and the lenA <= 0 branch should be hit\n        Assert.That(sortedArray, Is.EqualTo(array));\n    }\n\n    [Test]\n    public static void MergeAt_ShouldReturnEarly_WhenLenBIsZero()\n    {\n        // Arrange: right run is all less than left run's last element\n        var array = Enumerable.Range(100, 25).Concat(Enumerable.Range(1, 25)).ToArray();\n        var sortedArray = Enumerable.Range(1, 25).Concat(Enumerable.Range(100, 25)).ToArray();\n        var sorter = new TimSorter<int>(new TimSorterSettings(), Comparer<int>.Default);\n\n        // Act\n        sorter.Sort(array, Comparer<int>.Default);\n\n        // Assert: The left and right sides of the array should have swapped places, and the lenB <= 0 branch should be hit\n        Assert.That(sortedArray, Is.EqualTo(array));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/External/ExternalMergeSorterTests.cs",
    "content": "using Algorithms.Sorters.External;\nusing Algorithms.Sorters.External.Storages;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.External;\n\npublic static class ExternalMergeSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new ExternalMergeSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n        var main = new IntInMemoryStorage(testArray);\n        var temp = new IntInMemoryStorage(new int[testArray.Length]);\n\n        // Act\n        sorter.Sort(main, temp, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n\n    [Test]\n    public static void ArraySorted_OnDisk(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new ExternalMergeSorter<int>();\n        var intComparer = new IntComparer();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n        var randomizer = Randomizer.CreateRandomizer();\n        var main = new IntFileStorage($\"sorted_{randomizer.GetString(100)}\", n);\n        var temp = new IntFileStorage($\"temp_{randomizer.GetString(100)}\", n);\n\n        var writer = main.GetWriter();\n        for (var i = 0; i < n; i++)\n        {\n            writer.Write(correctArray[i]);\n        }\n\n        writer.Dispose();\n\n        // Act\n        sorter.Sort(main, temp, intComparer);\n        Array.Sort(correctArray, intComparer);\n\n        // Assert\n        var reader = main.GetReader();\n        for (var i = 0; i < n; i++)\n        {\n            testArray[i] = reader.Read();\n        }\n\n        Assert.That(correctArray, Is.EqualTo(testArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Integer/BucketSorterTests.cs",
    "content": "using Algorithms.Sorters.Integer;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Integer;\n\npublic static class BucketSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(0, 1000, 1000, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new BucketSorter();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray);\n        Array.Sort(correctArray);\n\n        // Assert\n        Assert.That(testArray, Is.EqualTo(correctArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Integer/CountingSorterTests.cs",
    "content": "using Algorithms.Sorters.Integer;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Integer;\n\npublic static class CountingSorterTests\n{\n    [Test]\n    public static void SortsNonEmptyArray(\n        [Random(1, 10000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new CountingSorter();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray);\n        Array.Sort(correctArray);\n\n        // Assert\n        Assert.That(testArray, Is.EqualTo(correctArray));\n    }\n\n    [Test]\n    public static void SortsEmptyArray()\n    {\n        // Arrange\n        var sorter = new CountingSorter();\n        var (correctArray, testArray) = RandomHelper.GetArrays(0);\n\n        // Act\n        sorter.Sort(testArray);\n        Array.Sort(correctArray);\n\n        // Assert\n        Assert.That(testArray, Is.Empty);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Integer/RadixSorterTests.cs",
    "content": "using Algorithms.Sorters.Integer;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.Integer;\n\npublic static class RadixSorterTests\n{\n    [Test]\n    public static void SortsArray(\n        [Random(0, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new RadixSorter();\n        var (correctArray, testArray) = RandomHelper.GetArrays(n);\n\n        // Act\n        sorter.Sort(testArray);\n        Array.Sort(correctArray);\n\n        // Assert\n        Assert.That(testArray, Is.EqualTo(correctArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/String/MsdRadixStringSorterTests.cs",
    "content": "using Algorithms.Sorters.String;\nusing Algorithms.Tests.Helpers;\n\nnamespace Algorithms.Tests.Sorters.String;\n\n/// <summary>\n///     Class for testing MSD radix sorter algorithm.\n/// </summary>\npublic static class MsdRadixStringSorterTests\n{\n    [Test]\n    public static void ArraySorted(\n        [Random(2, 1000, 100, Distinct = true)]\n        int n)\n    {\n        // Arrange\n        var sorter = new MsdRadixStringSorter();\n        var (correctArray, testArray) = RandomHelper.GetStringArrays(n, 100, false);\n\n        // Act\n        sorter.Sort(testArray);\n        Array.Sort(correctArray);\n\n        // Assert\n        Assert.That(testArray, Is.EqualTo(correctArray));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Sorters/Utils/GallopingStrategyTests.cs",
    "content": "using Algorithms.Sorters.Utils;\n\nnamespace Algorithms.Tests.Sorters.Utils\n{\n    [TestFixture]\n    public class GallopingStrategyTests\n    {\n        private readonly IComparer<int> comparer = Comparer<int>.Default;\n\n        [Test]\n        public void GallopLeft_KeyPresent_ReturnsCorrectIndex()\n        {\n            var array = new[] { 1, 2, 3, 4, 5 };\n            var index = GallopingStrategy<int>.GallopLeft(array, 3, 0, array.Length, comparer);\n            Assert.That(index, Is.EqualTo(2));\n        }\n\n        [Test]\n        public void GallopLeft_KeyNotPresent_ReturnsCorrectIndex()\n        {\n            var array = new[] { 1, 2, 4, 5 };\n            var index = GallopingStrategy<int>.GallopLeft(array, 3, 0, array.Length, comparer);\n            Assert.That(index, Is.EqualTo(2));\n        }\n\n        [Test]\n        public void GallopLeft_KeyLessThanAll_ReturnsZero()\n        {\n            var array = new[] { 2, 3, 4, 5 };\n            var index = GallopingStrategy<int>.GallopLeft(array, 1, 0, array.Length, comparer);\n            Assert.That(index, Is.EqualTo(0));\n        }\n\n        [Test]\n        public void GallopLeft_KeyGreaterThanAll_ReturnsLength()\n        {\n            var array = new[] { 1, 2, 3, 4 };\n            var index = GallopingStrategy<int>.GallopLeft(array, 5, 0, array.Length, comparer);\n            Assert.That(index, Is.EqualTo(array.Length));\n        }\n\n        [Test]\n        public void GallopRight_KeyPresent_ReturnsCorrectIndex()\n        {\n            var array = new[] { 1, 2, 3, 4, 5 };\n            var index = GallopingStrategy<int>.GallopRight(array, 3, 0, array.Length, comparer);\n            Assert.That(index, Is.EqualTo(3));\n        }\n\n        [Test]\n        public void GallopRight_KeyNotPresent_ReturnsCorrectIndex()\n        {\n            var array = new[] { 1, 2, 4, 5 };\n            var index = GallopingStrategy<int>.GallopRight(array, 3, 0, array.Length, comparer);\n            Assert.That(index, Is.EqualTo(2));\n        }\n\n        [Test]\n        public void GallopRight_KeyLessThanAll_ReturnsZero()\n        {\n            var array = new[] { 2, 3, 4, 5 };\n            var index = GallopingStrategy<int>.GallopRight(array, 1, 0, array.Length, comparer);\n            Assert.That(index, Is.EqualTo(0));\n        }\n\n        [Test]\n        public void GallopRight_KeyGreaterThanAll_ReturnsLength()\n        {\n            var array = new[] { 1, 2, 3, 4 };\n            var index = GallopingStrategy<int>.GallopRight(array, 5, 0, array.Length, comparer);\n            Assert.That(index, Is.EqualTo(array.Length));\n        }\n\n        [Test]\n        public void GallopLeft_EmptyArray_ReturnsZero()\n        {\n            var array = new int[] { };\n            var index = GallopingStrategy<int>.GallopLeft(array, 1, 0, array.Length, comparer);\n            Assert.That(index, Is.EqualTo(0));\n        }\n\n        [Test]\n        public void GallopRight_EmptyArray_ReturnsZero()\n        {\n            var array = new int[] { };\n            var index = GallopingStrategy<int>.GallopRight(array, 1, 0, array.Length, comparer);\n            Assert.That(index, Is.EqualTo(0));\n        }\n\n        // Test when (shiftable << 1) < 0 is true\n        [Test]\n        public void TestBoundLeftShift_WhenShiftableCausesNegativeShift_ReturnsShiftedValuePlusOne()\n        {\n            // Arrange\n            int shiftable = int.MaxValue; // This should cause a negative result after left shift\n\n            // Act\n            int result = GallopingStrategy<int>.BoundLeftShift(shiftable);\n\n            // Assert\n            Assert.That((shiftable << 1) + 1, Is.EqualTo(result));  // True branch\n        }\n\n        // Test when (shiftable << 1) < 0 is false\n        [Test]\n        public void TestBoundLeftShift_WhenShiftableDoesNotCauseNegativeShift_ReturnsMaxValue()\n        {\n            // Arrange\n            int shiftable = 1;  // This will not cause a negative result after left shift\n\n            // Act\n            int result = GallopingStrategy<int>.BoundLeftShift(shiftable);\n\n            // Assert\n            Assert.That(int.MaxValue, Is.EqualTo(result));  // False branch\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Stack/BalancedParenthesesCheckerTests.cs",
    "content": "using Algorithms.Stack;\n\nnamespace Algorithms.Tests.Stack\n{\n    [TestFixture]\n    public class BalancedParenthesesCheckerTests\n    {\n        public static bool IsBalanced(string expression)\n        {\n            var checker = new BalancedParenthesesChecker();\n            return checker.IsBalanced(expression);\n        }\n\n        [Test]\n        public void IsBalanced_EmptyString_ThrowsArgumentException()\n        {\n            // Arrange\n            var expression = string.Empty;\n\n            // Act & Assert\n            var ex = Assert.Throws<ArgumentException>(() => IsBalanced(expression));\n\n            if (ex != null)\n            {\n                Assert.That(ex.Message, Is.EqualTo(\"The input expression cannot be null or empty.\"));\n            }\n\n        }\n\n        [Test]\n        public void IsBalanced_ValidBalancedExpression_ReturnsTrue()\n        {\n            // Arrange\n            var expression = \"{[()]}\";\n\n            // Act\n            var result = IsBalanced(expression);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(true));\n        }\n\n        [Test]\n        public void IsBalanced_ValidUnbalancedExpression_ReturnsFalse()\n        {\n            // Arrange\n            var expression = \"{[(])}\";\n\n            // Act\n            var result = IsBalanced(expression);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(false));\n        }\n\n        [Test]\n        public void IsBalanced_UnbalancedWithExtraClosingBracket_ReturnsFalse()\n        {\n            // Arrange\n            var expression = \"{[()]}]\";\n\n            // Act\n            var result = IsBalanced(expression);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(false));\n        }\n\n        [Test]\n        public void IsBalanced_ExpressionWithInvalidCharacters_ThrowsArgumentException()\n        {\n            // Arrange\n            var expression = \"{[a]}\";\n\n            // Act & Assert\n            var ex = Assert.Throws<ArgumentException>(() => IsBalanced(expression));\n            if (ex != null)\n            {\n                Assert.That(ex.Message, Is.EqualTo(\"Invalid character 'a' found in the expression.\"));\n            }\n        }\n\n        [Test]\n        public void IsBalanced_SingleOpeningBracket_ReturnsFalse()\n        {\n            // Arrange\n            var expression = \"(\";\n\n            // Act\n            var result = IsBalanced(expression);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(false));\n        }\n\n        [Test]\n        public void IsBalanced_SingleClosingBracket_ReturnsFalse()\n        {\n            // Arrange\n            var expression = \")\";\n\n            // Act\n            var result = IsBalanced(expression);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(false));\n        }\n\n        [Test]\n        public void IsBalanced_ExpressionWithMultipleBalancedBrackets_ReturnsTrue()\n        {\n            // Arrange\n            var expression = \"[{()}]()\";\n\n            // Act\n            var result = IsBalanced(expression);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(true));\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Stack/InfixToPostfixTests.cs",
    "content": "using System;\nusing NUnit.Framework;\nusing Algorithms.Stack;\n\nnamespace Algorithms.Tests.Stack\n{\n    [TestFixture]\n    public class InfixToPostfixTests\n    {\n        [Test]\n        public void InfixToPostfixConversion_SimpleAddition_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"A+B\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"AB+\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_SimpleSubtraction_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"A-B\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"AB-\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_MultiplicationAndDivision_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"A*B/C\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"AB*C/\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_ExponentiationOperator_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"A^B\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"AB^\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_MixedOperatorPrecedence_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"A+B*C\";\n       \n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"ABC*+\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_WithParentheses_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"(A+B)*C\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"AB+C*\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_NestedParentheses_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"((A+B)*C)\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"AB+C*\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_ComplexExpression_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"A+B*C-D/E\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"ABC*+DE/-\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_WithDigits_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"1+2*3\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"123*+\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_LowercaseLetters_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"a+b*c\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"abc*+\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_WithWhitespace_IgnoresWhitespace()\n        {\n            // Arrange\n            string infix = \"A + B * C\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"ABC*+\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_MultipleParentheses_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"(A+B)*(C-D)\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"AB+CD-*\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_AllOperators_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"A+B-C*D/E^F\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"AB+CD*EF^/-\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_NullExpression_ThrowsArgumentException()\n        {\n            // Arrange\n            string infix = null!;\n\n            // Act & Assert\n            var ex = Assert.Throws<ArgumentException>(() =>\n                InfixToPostfix.InfixToPostfixConversion(infix));\n            Assert.That(ex!.Message, Does.Contain(\"Infix cannot be null or empty\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_EmptyExpression_ThrowsArgumentException()\n        {\n            // Arrange\n            string infix = \"\";\n\n            // Act & Assert\n            var ex = Assert.Throws<ArgumentException>(() =>\n                InfixToPostfix.InfixToPostfixConversion(infix));\n            Assert.That(ex!.Message, Does.Contain(\"Infix cannot be null or empty\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_WhitespaceOnlyExpression_ThrowsArgumentException()\n        {\n            // Arrange\n            string infix = \"   \";\n\n            // Act & Assert\n            var ex = Assert.Throws<ArgumentException>(() =>\n                InfixToPostfix.InfixToPostfixConversion(infix));\n            Assert.That(ex!.Message, Does.Contain(\"Infix cannot be null or empty\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_InvalidCharacter_ThrowsArgumentException()\n        {\n            // Arrange\n            string infix = \"A+B$C\";\n\n            // Act & Assert\n            var ex = Assert.Throws<ArgumentException>(() =>\n                InfixToPostfix.InfixToPostfixConversion(infix));\n            Assert.That(ex!.Message, Does.Contain(\"Invalid character $\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_MismatchedParenthesesClosingExtra_ThrowsInvalidOperationException()\n        {\n            // Arrange\n            string infix = \"A+B)\";\n\n            // Act & Assert\n            var ex = Assert.Throws<InvalidOperationException>(() =>\n                InfixToPostfix.InfixToPostfixConversion(infix));\n            Assert.That(ex!.Message, Does.Contain(\"Mismatched parentheses\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_MismatchedParenthesesOpeningExtra_ThrowsInvalidOperationException()\n        {\n            // Arrange\n            string infix = \"(A+B\";\n\n            // Act & Assert\n            var ex = Assert.Throws<InvalidOperationException>(() =>\n                InfixToPostfix.InfixToPostfixConversion(infix));\n            Assert.That(ex!.Message, Does.Contain(\"Mismatched parentheses\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_OnlyOpeningParenthesis_ThrowsInvalidOperationException()\n        {\n            // Arrange\n            string infix = \"(\";\n\n            // Act & Assert\n            Assert.Throws<InvalidOperationException>(() =>\n                InfixToPostfix.InfixToPostfixConversion(infix));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_OnlyClosingParenthesis_ThrowsInvalidOperationException()\n        {\n            // Arrange\n            string infix = \")\";\n\n            // Act & Assert\n            Assert.Throws<InvalidOperationException>(() =>\n                InfixToPostfix.InfixToPostfixConversion(infix));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_ExponentiationWithOtherOperators_ReturnsCorrectPostfix()\n        {\n            // Arrange\n            string infix = \"A+B^C*D\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"ABC^D*+\"));\n        }\n\n        [Test]\n        public void InfixToPostfixConversion_SingleOperand_ReturnsOperand()\n        {\n            // Arrange\n            string infix = \"A\";\n\n            // Act\n            string result = InfixToPostfix.InfixToPostfixConversion(infix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(\"A\"));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_SimpleAddition_ReturnsCorrectResult()\n        {\n            // Arrange\n            string postfix = \"23+\";\n\n            // Act\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(5));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_SimpleSubtraction_ReturnsCorrectResult()\n        {\n            // Arrange\n            string postfix = \"53-\";\n\n            // Act\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(2));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_SimpleMultiplication_ReturnsCorrectResult()\n        {\n            // Arrange\n            string postfix = \"34*\";\n\n            // Act\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(12));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_SimpleDivision_ReturnsCorrectResult()\n        {\n            // Arrange\n            string postfix = \"82/\";\n\n            // Act\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(4));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_SimpleExponentiation_ReturnsCorrectResult()\n        {\n            // Arrange\n            string postfix = \"23^\";\n\n            // Act\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(8));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_ComplexExpression_ReturnsCorrectResult()\n        {\n            // Arrange\n            string postfix = \"23*4+\";\n\n            // Act\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(10));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_WithWhitespace_ReturnsCorrectResult()\n        {\n            // Arrange\n            string postfix = \"2 3 + 4 *\";\n\n            // Act\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(20));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_SingleDigit_ReturnsDigit()\n        {\n            // Arrange\n            string postfix = \"5\";\n\n            // Act\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(5));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_NullExpression_ThrowsArgumentException()\n        {\n            // Arrange\n            string postfix = null!;\n\n            // Act & Assert\n            var ex = Assert.Throws<ArgumentException>(() =>\n                InfixToPostfix.PostfixExpressionEvaluation(postfix));\n            Assert.That(ex!.Message, Does.Contain(\"Postfix cannot be null or empty\"));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_EmptyExpression_ThrowsArgumentException()\n        {\n            // Arrange\n            string postfix = \"\";\n\n            // Act & Assert\n            var ex = Assert.Throws<ArgumentException>(() =>\n                InfixToPostfix.PostfixExpressionEvaluation(postfix));\n            Assert.That(ex!.Message, Does.Contain(\"Postfix cannot be null or empty\"));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_WhitespaceOnlyExpression_ThrowsArgumentException()\n        {\n            // Arrange\n            string postfix = \"   \";\n\n            // Act & Assert\n            var ex = Assert.Throws<ArgumentException>(() =>\n                InfixToPostfix.PostfixExpressionEvaluation(postfix));\n            Assert.That(ex!.Message, Does.Contain(\"Postfix cannot be null or empty\"));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_InsufficientOperands_ThrowsInvalidOperationException()\n        {\n            // Arrange\n            string postfix = \"2+\";\n\n            // Act & Assert\n            var ex = Assert.Throws<InvalidOperationException>(() =>\n                InfixToPostfix.PostfixExpressionEvaluation(postfix));\n            Assert.That(ex!.Message, Does.Contain(\"Insufficient operands\"));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_DivisionByZero_ThrowsDivideByZeroException()\n        {\n            // Arrange\n            string postfix = \"20/\";\n\n            // Act & Assert\n            var ex = Assert.Throws<DivideByZeroException>(() =>\n                InfixToPostfix.PostfixExpressionEvaluation(postfix));\n            Assert.That(ex!.Message, Does.Contain(\"Cannot divide by zero\"));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_InvalidCharacter_ThrowsInvalidOperationException()\n        {\n            // Arrange\n            string postfix = \"23A+\";\n\n            // Act & Assert\n            var ex = Assert.Throws<InvalidOperationException>(() =>\n                InfixToPostfix.PostfixExpressionEvaluation(postfix));\n            Assert.That(ex!.Message, Does.Contain(\"Invalid character in expression\"));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_LeftoverOperands_ThrowsInvalidOperationException()\n        {\n            // Arrange\n            string postfix = \"234\";\n\n            // Act & Assert\n            var ex = Assert.Throws<InvalidOperationException>(() =>\n                InfixToPostfix.PostfixExpressionEvaluation(postfix));\n            Assert.That(ex!.Message, Does.Contain(\"Invalid postfix expression: Leftover operands\"));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_UnknownOperator_ThrowsInvalidOperationException()\n        {\n            // This test ensures the default case in the switch is covered\n            // Note: This is difficult to test directly as IsOperator filters valid operators\n            // But we can test by passing an operator character that somehow bypasses IsOperator\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_ComplexExpressionWithAllOperators_ReturnsCorrectResult()\n        {\n            // Arrange - (2+3)*4-6/2 = 5*4-3 = 20-3 = 17\n            string postfix = \"23+4*62/-\";\n\n            // Act\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(17));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_ExponentiationInExpression_ReturnsCorrectResult()\n        {\n            // Arrange - 2^3*2 = 8*2 = 16\n            string postfix = \"23^2*\";\n\n            // Act\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(16));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_ZeroOperands_ReturnsZero()\n        {\n            // Arrange\n            string postfix = \"0\";\n\n            // Act\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(0));\n        }\n\n        [Test]\n        public void PostfixExpressionEvaluation_LargerNumbers_ReturnsCorrectResult()\n        {\n            // Arrange - Uses single digits only: 9+8 = 17\n            string postfix = \"98+\";\n\n            // Act\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(17));\n        }\n\n        [Test]\n        public void IntegrationTest_ConvertAndEvaluate_SimpleExpression()\n        {\n            // Arrange\n            string infix = \"2+3\";\n\n            // Act\n            string postfix = InfixToPostfix.InfixToPostfixConversion(infix);\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(postfix, Is.EqualTo(\"23+\"));\n            Assert.That(result, Is.EqualTo(5));\n        }\n\n        [Test]\n        public void IntegrationTest_ConvertAndEvaluate_ComplexExpression()\n        {\n            // Arrange\n            string infix = \"(2+3)*4\";\n\n            // Act\n            string postfix = InfixToPostfix.InfixToPostfixConversion(infix);\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(postfix, Is.EqualTo(\"23+4*\"));\n            Assert.That(result, Is.EqualTo(20));\n        }\n\n        [Test]\n        public void IntegrationTest_ConvertAndEvaluate_WithAllOperators()\n        {\n            // Arrange - 2+3*4-6/2 = 2+12-3 = 11\n            string infix = \"2+3*4-6/2\";\n\n            // Act\n            string postfix = InfixToPostfix.InfixToPostfixConversion(infix);\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(postfix, Is.EqualTo(\"234*+62/-\"));\n            Assert.That(result, Is.EqualTo(11));\n        }\n\n        [Test]\n        public void IntegrationTest_ConvertAndEvaluate_WithExponentiation()\n        {\n            // Arrange - 2^3+1 = 8+1 = 9\n            string infix = \"2^3+1\";\n\n            // Act\n            string postfix = InfixToPostfix.InfixToPostfixConversion(infix);\n            int result = InfixToPostfix.PostfixExpressionEvaluation(postfix);\n\n            // Assert\n            Assert.That(postfix, Is.EqualTo(\"23^1+\"));\n            Assert.That(result, Is.EqualTo(9));\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Stack/NextGreaterElementTests.cs",
    "content": "using Algorithms.Stack;\n\nnamespace Algorithms.Tests.Stack\n{\n    [TestFixture]\n    public class NextGreaterElementTests\n    {\n        private static int[] FindNextGreaterElement(int[] input)\n        {\n            var obj = new NextGreaterElement();\n            return obj.FindNextGreaterElement(input);\n        }\n\n        [Test]\n        public void FindNextGreaterElement_InputIsEmpty_ReturnsEmptyArray()\n        {\n            // Arrange\n            int[] input = Array.Empty<int>();\n            int[] expected = Array.Empty<int>();\n\n            // Act\n            var result = FindNextGreaterElement(input);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(expected));\n        }\n\n        [Test]\n        public void FindNextGreaterElement_BasicScenario_ReturnsCorrectResult()\n        {\n            // Arrange\n            int[] input = [4, 5, 2, 25];\n            int[] expected = [5, 25, 25, -1];\n\n            // Act\n            var result = FindNextGreaterElement(input);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(expected));\n        }\n\n        [Test]\n        public void FindNextGreaterElement_NoNextGreaterElement_ReturnsCorrectResult()\n        {\n            // Arrange\n            int[] input = [13, 7, 6, 12];\n            int[] expected = [-1, 12, 12, -1];\n\n            // Act\n            var result = FindNextGreaterElement(input);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(expected));\n        }\n\n        [Test]\n        public void FindNextGreaterElement_AllElementsHaveNoGreaterElement_ReturnsAllNegativeOnes()\n        {\n            // Arrange\n            int[] input = [5, 4, 3, 2, 1];\n            int[] expected = [-1, -1, -1, -1, -1];\n\n            // Act\n            var result = FindNextGreaterElement(input);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(expected));\n        }\n\n        [Test]\n        public void FindNextGreaterElement_InputWithDuplicates_ReturnsCorrectResult()\n        {\n            // Arrange\n            int[] input = [4, 4, 3, 2, 4];\n            int[] expected = [-1, -1, 4, 4, -1];\n\n            // Act\n            var result = FindNextGreaterElement(input);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(expected));\n        }\n\n        [Test]\n        public void FindNextGreaterElement_SingleElementArray_ReturnsNegativeOne()\n        {\n            // Arrange\n            int[] input = [10];\n            int[] expected = [-1];\n\n            // Act\n            var result = FindNextGreaterElement(input);\n\n            // Assert\n            Assert.That(result, Is.EqualTo(expected));\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Stack/ReverseStackTests.cs",
    "content": "using Algorithms.Stack;\n\nnamespace Algorithms.Tests.Stack\n{\n    public class ReverseStackTests\n    {\n        public static void Reverse<T>(Stack<T> stack)\n        {\n            var obj = new ReverseStack();\n            obj.Reverse(stack);\n        }\n\n        [Test]\n        public void Reverse_EmptyStack_DoesNotChangeStack()\n        {\n            // Arrange\n            Stack<int> stack = new Stack<int>();\n\n            // Act\n            Reverse(stack);\n\n            // Assert\n            Assert.That(stack.Count, Is.EqualTo(0));\n        }\n\n        [Test]\n        public void Reverse_SingleElementStack_DoesNotChangeStack()\n        {\n            // Arrange\n            Stack<int> stack = new Stack<int>();\n            stack.Push(1);\n\n            // Act\n            Reverse(stack);\n\n            // Assert\n            Assert.That(stack.Count, Is.EqualTo(1));\n            Assert.That(stack.Peek(), Is.EqualTo(1));\n        }\n\n        [Test]\n        public void Reverse_MultipleElementStack_ReturnsCorrectOrder()\n        {\n            // Arrange\n            Stack<int> stack = new Stack<int>();\n            stack.Push(1);\n            stack.Push(2);\n            stack.Push(3);\n            // The stack is now [3, 2, 1] (top to bottom)\n\n            // Act\n            Reverse(stack);\n\n            // Assert\n            Assert.That(stack.Count, Is.EqualTo(3));\n            Assert.That(stack.Pop(), Is.EqualTo(1)); // Should return 1\n            Assert.That(stack.Pop(), Is.EqualTo(2)); // Should return 2\n            Assert.That(stack.Pop(), Is.EqualTo(3)); // Should return 3\n        }\n\n        [Test]\n        public void Reverse_StackWithDuplicates_ReturnsCorrectOrder()\n        {\n            // Arrange\n            Stack<int> stack = new Stack<int>();\n            stack.Push(1);\n            stack.Push(2);\n            stack.Push(1);\n            // The stack is now [1, 2, 1] (top to bottom)\n\n            // Act\n            Reverse(stack);\n\n            // Assert\n            Assert.That(stack.Count, Is.EqualTo(3));\n            Assert.That(stack.Pop(), Is.EqualTo(1)); // Should return 1\n            Assert.That(stack.Pop(), Is.EqualTo(2)); // Should return 2\n            Assert.That(stack.Pop(), Is.EqualTo(1)); // Should return 1\n        }\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/GeneralStringAlgorithmsTests.cs",
    "content": "using Algorithms.Strings;\n\nnamespace Algorithms.Tests.Strings;\n\npublic static class GeneralStringAlgorithmsTests\n{\n    [TestCase(\"Griffith\", 'f', 2)]\n    [TestCase(\"Randomwoooord\", 'o', 4)]\n    [TestCase(\"Control\", 'C', 1)]\n    public static void MaxCountCharIsObtained(string text, char expectedSymbol, int expectedCount)\n    {\n        // Arrange\n        // Act\n        var (symbol, count) = GeneralStringAlgorithms.FindLongestConsecutiveCharacters(text);\n\n        // Assert\n        Assert.That(symbol, Is.EqualTo(expectedSymbol));\n        Assert.That(count, Is.EqualTo(expectedCount));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/ManachersAlgorithmTests.cs",
    "content": "using Algorithms.Strings;\nusing NUnit.Framework;\nusing System;\n\nnamespace Algorithms.Tests.Strings;\n\n/// <summary>\n///     Comprehensive test suite for Manacher's Algorithm implementation.\n///     Tests cover various scenarios including:\n///     - Odd-length palindromes\n///     - Even-length palindromes\n///     - Single character strings\n///     - Empty strings\n///     - Strings with no palindromes longer than 1 character\n///     - Strings that are entirely palindromic\n///     - Multiple palindromes of the same length\n///     - Edge cases (null input, special characters)\n///     - Palindrome detection functionality\n///     - Detailed palindrome information retrieval.\n/// </summary>\npublic static class ManachersAlgorithmTests\n{\n    [Test]\n    public static void FindLongestPalindrome_WithOddLengthPalindrome_ReturnsCorrectPalindrome()\n    {\n        // Arrange: Classic example with odd-length palindrome \"bab\" or \"aba\"\n        string input = \"babad\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Either \"bab\" or \"aba\" is valid (both have length 3)\n        Assert.That(result.Length, Is.EqualTo(3));\n        Assert.That(result == \"bab\" || result == \"aba\", Is.True);\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithEvenLengthPalindrome_ReturnsCorrectPalindrome()\n    {\n        // Arrange: String with even-length palindrome \"abba\"\n        string input = \"cbbd\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should find \"bb\" (length 2)\n        Assert.That(result, Is.EqualTo(\"bb\"));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithSingleCharacter_ReturnsSingleCharacter()\n    {\n        // Arrange: Edge case with single character\n        string input = \"a\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Single character is a palindrome of itself\n        Assert.That(result, Is.EqualTo(\"a\"));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithEmptyString_ReturnsEmptyString()\n    {\n        // Arrange: Edge case with empty string\n        string input = string.Empty;\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Empty string should return empty string\n        Assert.That(result, Is.EqualTo(string.Empty));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithNullString_ThrowsArgumentException()\n    {\n        // Arrange: Test defensive programming - null input validation\n        string? input = null;\n\n        // Act & Assert: Should throw ArgumentException for null input\n        Assert.Throws<ArgumentException>(() => ManachersAlgorithm.FindLongestPalindrome(input!));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithEntirePalindrome_ReturnsEntireString()\n    {\n        // Arrange: String that is entirely a palindrome\n        string input = \"racecar\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should return the entire string\n        Assert.That(result, Is.EqualTo(\"racecar\"));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithNoPalindromes_ReturnsSingleCharacter()\n    {\n        // Arrange: String with no palindromes longer than 1 character\n        string input = \"abcdef\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should return a single character (any character is a palindrome)\n        Assert.That(result.Length, Is.EqualTo(1));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithLongPalindrome_ReturnsCorrectPalindrome()\n    {\n        // Arrange: String with a longer palindrome\n        string input = \"forgeeksskeegfor\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should find \"geeksskeeg\" (length 10)\n        Assert.That(result, Is.EqualTo(\"geeksskeeg\"));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithRepeatingCharacters_ReturnsCorrectPalindrome()\n    {\n        // Arrange: String with repeating characters\n        string input = \"aaaa\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Entire string is a palindrome\n        Assert.That(result, Is.EqualTo(\"aaaa\"));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithSpecialCharacters_ReturnsCorrectPalindrome()\n    {\n        // Arrange: String with special characters and spaces\n        string input = \"A man, a plan, a canal: Panama\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should find a palindrome (note: this includes spaces and punctuation)\n        // The longest palindrome considering all characters is \"anama\"\n        Assert.That(result.Length, Is.GreaterThan(0));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithTwoCharacters_ReturnsCorrectResult()\n    {\n        // Arrange: Edge case with two identical characters\n        string input = \"aa\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should return \"aa\"\n        Assert.That(result, Is.EqualTo(\"aa\"));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithTwoDifferentCharacters_ReturnsSingleCharacter()\n    {\n        // Arrange: Edge case with two different characters\n        string input = \"ab\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should return a single character\n        Assert.That(result.Length, Is.EqualTo(1));\n    }\n\n    [Test]\n    public static void FindLongestPalindromeWithDetails_ReturnsCorrectDetails()\n    {\n        // Arrange: Test the detailed version that returns index and length\n        string input = \"babad\";\n\n        // Act\n        var (palindrome, startIndex, length) = ManachersAlgorithm.FindLongestPalindromeWithDetails(input);\n\n        // Assert: Verify all components\n        Assert.That(length, Is.EqualTo(3));\n        Assert.That(palindrome.Length, Is.EqualTo(length));\n        Assert.That(input.Substring(startIndex, length), Is.EqualTo(palindrome));\n        Assert.That(palindrome == \"bab\" || palindrome == \"aba\", Is.True);\n    }\n\n    [Test]\n    public static void FindLongestPalindromeWithDetails_WithEmptyString_ReturnsZeroLength()\n    {\n        // Arrange\n        string input = string.Empty;\n\n        // Act\n        var (palindrome, startIndex, length) = ManachersAlgorithm.FindLongestPalindromeWithDetails(input);\n\n        // Assert\n        Assert.That(palindrome, Is.EqualTo(string.Empty));\n        Assert.That(startIndex, Is.EqualTo(0));\n        Assert.That(length, Is.EqualTo(0));\n    }\n\n    [Test]\n    public static void FindLongestPalindromeWithDetails_WithSingleCharacter_ReturnsCorrectDetails()\n    {\n        // Arrange\n        string input = \"x\";\n\n        // Act\n        var (palindrome, startIndex, length) = ManachersAlgorithm.FindLongestPalindromeWithDetails(input);\n\n        // Assert\n        Assert.That(palindrome, Is.EqualTo(\"x\"));\n        Assert.That(startIndex, Is.EqualTo(0));\n        Assert.That(length, Is.EqualTo(1));\n    }\n\n    [Test]\n    public static void FindLongestPalindromeWithDetails_WithNullString_ThrowsArgumentException()\n    {\n        // Arrange\n        string? input = null;\n\n        // Act & Assert\n        Assert.Throws<ArgumentException>(() => ManachersAlgorithm.FindLongestPalindromeWithDetails(input!));\n    }\n\n    [Test]\n    public static void IsPalindrome_WithPalindromeString_ReturnsTrue()\n    {\n        // Arrange: Test palindrome detection with a valid palindrome\n        string input = \"racecar\";\n\n        // Act\n        bool result = ManachersAlgorithm.IsPalindrome(input);\n\n        // Assert: Should return true\n        Assert.That(result, Is.True);\n    }\n\n    [Test]\n    public static void IsPalindrome_WithNonPalindromeString_ReturnsFalse()\n    {\n        // Arrange: Test palindrome detection with a non-palindrome\n        string input = \"hello\";\n\n        // Act\n        bool result = ManachersAlgorithm.IsPalindrome(input);\n\n        // Assert: Should return false\n        Assert.That(result, Is.False);\n    }\n\n    [Test]\n    public static void IsPalindrome_WithSingleCharacter_ReturnsTrue()\n    {\n        // Arrange: Single character is always a palindrome\n        string input = \"a\";\n\n        // Act\n        bool result = ManachersAlgorithm.IsPalindrome(input);\n\n        // Assert: Should return true\n        Assert.That(result, Is.True);\n    }\n\n    [Test]\n    public static void IsPalindrome_WithEmptyString_ReturnsTrue()\n    {\n        // Arrange: Empty string is considered a palindrome\n        string input = string.Empty;\n\n        // Act\n        bool result = ManachersAlgorithm.IsPalindrome(input);\n\n        // Assert: Should return true\n        Assert.That(result, Is.True);\n    }\n\n    [Test]\n    public static void IsPalindrome_WithNullString_ThrowsArgumentException()\n    {\n        // Arrange\n        string? input = null;\n\n        // Act & Assert\n        Assert.Throws<ArgumentException>(() => ManachersAlgorithm.IsPalindrome(input!));\n    }\n\n    [Test]\n    public static void IsPalindrome_WithEvenLengthPalindrome_ReturnsTrue()\n    {\n        // Arrange: Even-length palindrome\n        string input = \"abba\";\n\n        // Act\n        bool result = ManachersAlgorithm.IsPalindrome(input);\n\n        // Assert: Should return true\n        Assert.That(result, Is.True);\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithNumericString_ReturnsCorrectPalindrome()\n    {\n        // Arrange: String with numbers\n        string input = \"12321\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should return the entire string\n        Assert.That(result, Is.EqualTo(\"12321\"));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithMixedCase_ReturnsCorrectPalindrome()\n    {\n        // Arrange: Mixed case string (case-sensitive palindrome check)\n        string input = \"AbcbA\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should find \"AbcbA\" as it's case-sensitive\n        Assert.That(result, Is.EqualTo(\"AbcbA\"));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithPalindromeAtStart_ReturnsCorrectPalindrome()\n    {\n        // Arrange: Palindrome at the start of the string\n        string input = \"abaxyz\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should find \"aba\"\n        Assert.That(result, Is.EqualTo(\"aba\"));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithPalindromeAtEnd_ReturnsCorrectPalindrome()\n    {\n        // Arrange: Palindrome at the end of the string\n        string input = \"xyzaba\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should find \"aba\"\n        Assert.That(result, Is.EqualTo(\"aba\"));\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithMultiplePalindromesOfSameLength_ReturnsOne()\n    {\n        // Arrange: Multiple palindromes of the same length\n        // \"aba\" at index 0 and \"cdc\" at index 3\n        string input = \"abacdc\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should return one of them (the first one found)\n        Assert.That(result.Length, Is.EqualTo(3));\n        Assert.That(result == \"aba\" || result == \"cdc\", Is.True);\n    }\n\n    [Test]\n    public static void FindLongestPalindromeWithDetails_WithLongString_PerformsEfficiently()\n    {\n        // Arrange: Test with a longer string to verify O(n) performance\n        // Create a string with a palindrome in the middle\n        string input = new string('a', 1000) + \"racecar\" + new string('b', 1000);\n\n        // Act\n        var (_, _, length) = ManachersAlgorithm.FindLongestPalindromeWithDetails(input);\n\n        // Assert: Should find the longest palindrome (either the 'a's or 'b's or \"racecar\")\n        // The 1000 'a's form a palindrome\n        Assert.That(length, Is.GreaterThanOrEqualTo(7)); // At least \"racecar\"\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithVeryLongPalindrome_HandlesGracefully()\n    {\n        // Arrange: Test with a very long palindrome to verify O(n) performance\n        string input = new string('a', 10000);\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should correctly identify the entire string as a palindrome\n        Assert.That(result.Length, Is.EqualTo(10000));\n        Assert.That(result, Is.EqualTo(input));\n    }\n\n    [Test]\n    public static void IsPalindrome_WithVeryLongPalindrome_HandlesGracefully()\n    {\n        // Arrange: Test with a very long palindrome to verify performance\n        string input = new string('x', 5000);\n\n        // Act\n        bool result = ManachersAlgorithm.IsPalindrome(input);\n\n        // Assert: Should correctly identify as palindrome in O(n) time\n        Assert.That(result, Is.True);\n    }\n\n    [Test]\n    public static void FindLongestPalindrome_WithAlternatingCharacters_HandlesEdgeCases()\n    {\n        // Arrange: Test with alternating characters (minimal palindromes)\n        string input = \"abababababababababababababababab\";\n\n        // Act\n        string result = ManachersAlgorithm.FindLongestPalindrome(input);\n\n        // Assert: Should find at least a 3-character palindrome like \"aba\" or \"bab\"\n        Assert.That(result.Length, Is.GreaterThanOrEqualTo(3));\n    }\n\n    [Test]\n    public static void FindLongestPalindromeWithDetails_WithSpecialCharacters_HandlesCorrectly()\n    {\n        // Arrange: Test with special characters to ensure proper handling\n        string input = \"abc!@#@!xyz\";\n\n        // Act\n        var (palindrome, startIndex, length) = ManachersAlgorithm.FindLongestPalindromeWithDetails(input);\n\n        // Assert: Should find the palindrome with special characters\n        Assert.That(palindrome, Is.EqualTo(\"!@#@!\"));\n        Assert.That(length, Is.EqualTo(5));\n        Assert.That(startIndex, Is.EqualTo(3));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/PalindromeTests.cs",
    "content": "using Algorithms.Strings;\n\nnamespace Algorithms.Tests.Strings;\n\npublic static class PalindromeTests\n{\n    [TestCase(\"Anna\")]\n    [TestCase(\"A Santa at Nasa\")]\n    public static void TextIsPalindrome_TrueExpected(string text)\n    {\n        // Arrange\n        // Act\n        var isPalindrome = Palindrome.IsStringPalindrome(text);\n\n        // Assert\n        Assert.That(isPalindrome, Is.True);\n    }\n\n    [TestCase(\"hallo\")]\n    [TestCase(\"Once upon a time\")]\n    public static void TextNotPalindrome_FalseExpected(string text)\n    {\n        // Arrange\n        // Act\n        var isPalindrome = Palindrome.IsStringPalindrome(text);\n\n        // Assert\n        Assert.That(isPalindrome, Is.False);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/PatternMatching/BitapTests.cs",
    "content": "﻿using Algorithms.Strings.PatternMatching;\n\nnamespace Algorithms.Tests.Strings.PatternMatching;\n\n[TestFixture]\npublic class BitapTests\n{\n    [Test]\n    public void FindExactPattern_EmptyTextReturnsError()\n    {\n        Assert.That(Bitap.FindExactPattern(\"\", \"abc\"), Is.EqualTo(-1));\n    }\n\n    [Test]\n    public void FindExactPattern_EmptyPatternReturnsZero()\n    {\n        Assert.That(Bitap.FindExactPattern(\"abc\", \"\"), Is.EqualTo(0));\n    }\n\n    [Test]\n    public void FindExactPattern_PatternFoundAtBeginning()\n    {\n        Assert.That(Bitap.FindExactPattern(\"hello world\", \"hello\"), Is.EqualTo(0));\n    }\n\n    [Test]\n    public void FindExactPattern_PatternFoundInTheMiddle()\n    {\n        Assert.That(Bitap.FindExactPattern(\"abcabc\", \"cab\"), Is.EqualTo(2));\n    }\n\n    [Test]\n    public void FindExactPattern_PatternFoundAtEnd()\n    {\n        Assert.That(Bitap.FindExactPattern(\"the end\", \"end\"), Is.EqualTo(4));\n    }\n\n    [Test]\n    public void FindExactPattern_PatternNotFound()\n    {\n        Assert.That(Bitap.FindExactPattern(\"abcdefg\", \"xyz\"), Is.EqualTo(-1));\n    }\n\n    [Test]\n    public void FindExactPattern_PatternLongerThanText()\n    {\n        Assert.That(Bitap.FindExactPattern(\"short\", \"longerpattern\"), Is.EqualTo(-1));\n    }\n\n    [Test]\n    public void FindExactPattern_OverlappingPatterns()\n    {\n        Assert.That(Bitap.FindExactPattern(\"ababab\", \"abab\"), Is.EqualTo(0));\n    }\n\n    [Test]\n    public void FindExactPattern_PatternTooLongThrowsException()\n    {\n        var longPattern = new string('a', 32);\n        Assert.Throws<ArgumentException>(() => Bitap.FindExactPattern(\"some text\", longPattern));\n    }\n\n    [Test]\n    public void FindExactPattern_SpecialCharactersInPattern()\n    {\n        Assert.That(Bitap.FindExactPattern(\"hello, world!\", \", wo\"), Is.EqualTo(5));\n    }\n\n    [Test]\n    public void FindFuzzyPattern_EmptyTextReturnsZero()\n    {\n        Assert.That(Bitap.FindFuzzyPattern(\"\", \"abc\", 1), Is.EqualTo(0));\n    }\n\n    [Test]\n    public void FindFuzzyPattern_EmptyPatternReturnsZero()\n    {\n        Assert.That(Bitap.FindFuzzyPattern(\"def\", \"\", 1), Is.EqualTo(0));\n    }\n\n    [Test]\n    public void FindFuzzyPattern_ExactMatchFound()\n    {\n        Assert.That(Bitap.FindFuzzyPattern(\"hello world\", \"hello\", 0), Is.EqualTo(0));\n    }\n\n    [Test]\n    public void FindFuzzyPattern_FuzzyMatchWithOneMismatch()\n    {\n        Assert.That(Bitap.FindFuzzyPattern(\"hello world\", \"hellp\", 1), Is.EqualTo(0));\n    }\n\n    [Test]\n    public void FindFuzzyPattern_FuzzyMatchWithMultipleMismatches()\n    {\n        Assert.That(Bitap.FindFuzzyPattern(\"abcde\", \"xbcdz\", 2), Is.EqualTo(0));\n    }\n\n    [Test]\n    public void FindFuzzyPattern_FuzzyMatchAtEnd()\n    {\n        Assert.That(Bitap.FindFuzzyPattern(\"abcdefg\", \"efx\", 1), Is.EqualTo(4));\n    }\n\n    [Test]\n    public void FindFuzzyPattern_FuzzyMatchNotFound()\n    {\n        Assert.That(Bitap.FindFuzzyPattern(\"abcdefg\", \"xyz\", 2), Is.EqualTo(-1));\n    }\n\n    [Test]\n    public void FindFuzzyPattern_PatternTooLongReturnsNegativeOne()\n    {\n        var longPattern = new string('a', 32);\n        Assert.That(Bitap.FindFuzzyPattern(\"some text\", longPattern, 1), Is.EqualTo(-1));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/PatternMatching/BoyerMoreTests.cs",
    "content": "using Algorithms.Strings.PatternMatching;\n\nnamespace Algorithms.Tests.Strings;\n\npublic class BoyerMooreTests\n{\n    [TestCase(\"HelloImATestcaseAndIWillPass\", \"Testcase\", 8)]\n    [TestCase(\"HelloImATestcaseAndImCaseSensitive\", \"TestCase\", -1)]\n    [TestCase(\"Hello Im a testcase and I work with whitespaces\", \"testcase\", 11)]\n    [TestCase(\"Hello Im a testcase and I work with numbers like 1 2 3 4\", \"testcase\", 11)]\n    public void FindFirstOccurrence_IndexCheck(string t, string p, int expectedIndex)\n    {\n        var resultIndex = BoyerMoore.FindFirstOccurrence(t, p);\n        Assert.That(expectedIndex, Is.EqualTo(resultIndex));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/PatternMatching/KnuthMorrisPrattSearcherTests.cs",
    "content": "using Algorithms.Strings.PatternMatching;\n\nnamespace Algorithms.Tests.Strings;\n\npublic static class KnuthMorrisPrattSearcherTests\n{\n    [Test]\n    public static void FindIndexes_ItemsPresent_PassExpected()\n    {\n        // Arrange\n        var searcher = new KnuthMorrisPrattSearcher();\n        var str = \"ABABAcdeABA\";\n        var pat = \"ABA\";\n\n        // Act\n        var expectedItem = new[] { 0, 2, 8 };\n        var actualItem = searcher.FindIndexes(str, pat);\n\n        // Assert\n        Assert.That(actualItem, Is.EqualTo(expectedItem));\n    }\n\n    [Test]\n    public static void FindIndexes_ItemsMissing_NoIndexesReturned()\n    {\n        // Arrange\n        var searcher = new KnuthMorrisPrattSearcher();\n        var str = \"ABABA\";\n        var pat = \"ABB\";\n\n        // Act & Assert\n        var indexes = searcher.FindIndexes(str, pat);\n\n        // Assert\n        Assert.That(indexes, Is.Empty);\n    }\n\n    [Test]\n    public static void LongestPrefixSuffixArray_PrefixSuffixOfLength1_PassExpected()\n    {\n        // Arrange\n        var searcher = new KnuthMorrisPrattSearcher();\n        var s = \"ABA\";\n\n        // Act\n        var expectedItem = new[] { 0, 0, 1 };\n        var actualItem = searcher.FindLongestPrefixSuffixValues(s);\n\n        // Assert\n        Assert.That(actualItem, Is.EqualTo(expectedItem));\n    }\n\n    [Test]\n    public static void LongestPrefixSuffixArray_PrefixSuffixOfLength5_PassExpected()\n    {\n        // Arrange\n        var searcher = new KnuthMorrisPrattSearcher();\n        var s = \"AABAACAABAA\";\n\n        // Act\n        var expectedItem = new[] { 0, 1, 0, 1, 2, 0, 1, 2, 3, 4, 5 };\n        var actualItem = searcher.FindLongestPrefixSuffixValues(s);\n\n        // Assert\n        Assert.That(actualItem, Is.EqualTo(expectedItem));\n    }\n\n    [Test]\n    public static void LongestPrefixSuffixArray_PrefixSuffixOfLength0_PassExpected()\n    {\n        // Arrange\n        var searcher = new KnuthMorrisPrattSearcher();\n        var s = \"AB\";\n\n        // Act\n        var expectedItem = new[] { 0, 0 };\n        var actualItem = searcher.FindLongestPrefixSuffixValues(s);\n\n        // Assert\n        Assert.That(actualItem, Is.EqualTo(expectedItem));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/PatternMatching/NaiveStringSearchTests.cs",
    "content": "using Algorithms.Strings.PatternMatching;\n\nnamespace Algorithms.Tests.Strings;\n\npublic static class NaiveStringSearchTests\n{\n    [Test]\n    public static void ThreeMatchesFound_PassExpected()\n    {\n        // Arrange\n        var pattern = \"ABB\";\n        var content = \"ABBBAAABBAABBBBAB\";\n\n        // Act\n        var expectedOccurrences = new[] { 0, 6, 10 };\n        var actualOccurrences = NaiveStringSearch.NaiveSearch(content, pattern);\n        var sequencesAreEqual = expectedOccurrences.SequenceEqual(actualOccurrences);\n\n        // Assert\n        Assert.That(sequencesAreEqual, Is.True);\n    }\n\n    [Test]\n    public static void OneMatchFound_PassExpected()\n    {\n        // Arrange\n        var pattern = \"BAAB\";\n        var content = \"ABBBAAABBAABBBBAB\";\n\n        // Act\n        var expectedOccurrences = new[] { 8 };\n        var actualOccurrences = NaiveStringSearch.NaiveSearch(content, pattern);\n        var sequencesAreEqual = expectedOccurrences.SequenceEqual(actualOccurrences);\n\n        // Assert\n        Assert.That(sequencesAreEqual, Is.True);\n    }\n\n    [Test]\n    public static void NoMatchFound_PassExpected()\n    {\n        // Arrange\n        var pattern = \"XYZ\";\n        var content = \"ABBBAAABBAABBBBAB\";\n\n        // Act\n        var expectedOccurrences = new int[0];\n        var actualOccurrences = NaiveStringSearch.NaiveSearch(content, pattern);\n        var sequencesAreEqual = expectedOccurrences.SequenceEqual(actualOccurrences);\n\n        // Assert\n        Assert.That(sequencesAreEqual, Is.True);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/PatternMatching/RabinKarpTests.cs",
    "content": "using Algorithms.Strings.PatternMatching;\n\nnamespace Algorithms.Tests.Strings;\n\npublic class RabinKarpTest\n{\n    [TestCase(\"HelloImATestcaseAndIWillPass\", \"Testcase\", new[] { 8 })]\n    [TestCase(\"HelloImATestcaseAndImCaseSensitive\", \"TestCase\", new int[] { })]\n    [TestCase(\"Hello Im a testcase and you can use whitespaces\", \"testcase\", new[] { 11 })]\n    [TestCase(\"Hello Im a testcase and you can use numbers like 1, 2, 3, etcetera\", \"etcetera\", new[] { 58 })]\n    [TestCase(\"HelloImATestcaseAndIHaveTwoOccurrencesOfTestcase\", \"Testcase\", new[] { 8, 40 })]\n    public void FindAllOccurrences_IndexCheck(string t, string p, int[] expectedIndices)\n    {\n        List<int> result = RabinKarp.FindAllOccurrences(t, p);\n        Assert.That(result, Is.EqualTo(new List<int>(expectedIndices)));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/PatternMatching/WildCardMatcherTests.cs",
    "content": "using Algorithms.Strings.PatternMatching;\n\nnamespace Algorithms.Tests.Strings.PatternMatching;\n\npublic static class WildCardMatcherTests\n{\n    [TestCase(\"aab\", \"c*a*b\", true)]\n    [TestCase(\"aaa\", \"aa\", false)]\n    [TestCase(\"aaa\", \"a.a\", true)]\n    [TestCase(\"aaab\", \"aa*\", false)]\n    [TestCase(\"aaab\", \".*\", true)]\n    [TestCase(\"a\", \"bbbb\", false)]\n    [TestCase(\"\", \"bbbb\", false)]\n    [TestCase(\"a\", \"\", false)]\n    [TestCase(\"\", \"\", true)]\n    public static void MatchPattern(string inputString, string pattern, bool expected)\n    {\n        // Act\n        var result = WildCardMatcher.MatchPattern(inputString, pattern);\n\n        // Assert\n        Assert.That(result, Is.EqualTo(expected));\n    }\n\n    [Test]\n    public static void MatchPatternThrowsArgumentException()\n    {\n        // Arrange\n        var inputString = \"abc\";\n        var pattern = \"*abc\";\n\n        // Assert\n        Assert.Throws<System.ArgumentException>(() => WildCardMatcher.MatchPattern(inputString, pattern));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/PatternMatching/ZblockSubstringSearchTest.cs",
    "content": "using Algorithms.Strings.PatternMatching;\n\nnamespace Algorithms.Tests.Strings;\n\npublic class ZblockSubstringSearchTest\n{\n    [TestCase(\"abc\", \"abcdef\", 1)]\n    [TestCase(\"xxx\", \"abxxxcdexxxf\", 2)]\n    [TestCase(\"aa\", \"waapaaxcdaalaabb\", 4)]\n    [TestCase(\"ABC\", \"ABAAABCDBBABCDDEBCABC\", 3)]\n    [TestCase(\"xxx\", \"abcdefghij\", 0)]\n    [TestCase(\"aab\", \"caabxaaaz\", 1)]\n    [TestCase(\"abc\", \"xababaxbabcdabx\", 1)]\n    [TestCase(\"GEEK\", \"GEEKS FOR GEEKS\", 2)]\n    [TestCase(\"ground\", \"Hello, playground!\", 1)]\n    public void Test(string pattern, string text, int expectedOccurences)\n    {\n        var occurencesFound = ZblockSubstringSearch.FindSubstring(pattern, text);\n        Assert.That(occurencesFound, Is.EqualTo(expectedOccurences));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/PermutationTests.cs",
    "content": "using Algorithms.Numeric;\nusing Algorithms.Strings;\n\nnamespace Algorithms.Tests.Strings;\n\npublic class PermutationTests\n{\n    [TestCase(\"\")]\n    [TestCase(\"A\")]\n    [TestCase(\"abcd\")]\n    [TestCase(\"aabcd\")]\n    [TestCase(\"aabbbcd\")]\n    [TestCase(\"aabbccccd\")]\n    public void Test_GetEveryUniquePermutation(string word)\n    {\n        var permutations = Permutation.GetEveryUniquePermutation(word);\n\n        // We need to make sure that\n        // 1. We have the right number of permutations\n        // 2. Every string in permutations List is a permutation of word\n        // 3. There are no repetitions\n\n        // Start 1.\n        // The number of unique permutations is\n        // n!/(A1! * A2! * ... An!)\n        // where n is the length of word and Ai is the number of occurrences if ith char in the string\n        var charOccurrence = new Dictionary<char, int>();\n        foreach (var c in word)\n        {\n            if (charOccurrence.ContainsKey(c))\n            {\n                charOccurrence[c] += 1;\n            }\n            else\n            {\n                charOccurrence[c] = 1;\n            }\n        }\n        // now we know the values of A1, A2, ..., An\n        // evaluate the above formula\n        var expectedNumberOfAnagrams = Factorial.Calculate(word.Length);\n        expectedNumberOfAnagrams = charOccurrence.Aggregate(expectedNumberOfAnagrams, (current, keyValuePair) =>\n        {\n            return current / Factorial.Calculate(keyValuePair.Value);\n        });\n        Assert.That(new BigInteger(permutations.Count), Is.EqualTo(expectedNumberOfAnagrams));\n        // End 1.\n\n        // Start 2\n        // string A is a permutation of string B if and only if sorted(A) == sorted(b)\n        var wordSorted = SortString(word);\n        foreach (var permutation in permutations)\n        {\n            Assert.That(SortString(permutation), Is.EqualTo(wordSorted));\n        }\n        // End 2\n\n        // Start 3\n        Assert.That(new HashSet<string>(permutations).Count, Is.EqualTo(permutations.Count));\n        // End 3\n    }\n\n    private static string SortString(string word)\n    {\n        var asArray = word.ToArray();\n        Array.Sort(asArray);\n        return new string(asArray);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/Similarity/CosineSimilarityTests.cs",
    "content": "﻿using Algorithms.Strings.Similarity;\n\nnamespace Algorithms.Tests.Strings.Similarity;\n\n[TestFixture]\npublic class CosineSimilarityTests\n{\n    [Test]\n    public void Calculate_IdenticalStrings_ReturnsOne()\n    {\n        var str1 = \"test\";\n        var str2 = \"test\";\n        var result = CosineSimilarity.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(1.0).Within(1e-6), \"Identical strings should have a cosine similarity of 1.\");\n    }\n\n    [Test]\n    public void Calculate_CompletelyDifferentStrings_ReturnsZero()\n    {\n        var str1 = \"abc\";\n        var str2 = \"xyz\";\n        var result = CosineSimilarity.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(0.0).Within(1e-6), \"Completely different strings should have a cosine similarity of 0.\");\n    }\n\n    [Test]\n    public void Calculate_EmptyStrings_ReturnsZero()\n    {\n        var str1 = \"\";\n        var str2 = \"\";\n        var result = CosineSimilarity.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(0.0).Within(1e-6), \"Empty strings should have a cosine similarity of 0.\");\n    }\n\n    [Test]\n    public void Calculate_OneEmptyString_ReturnsZero()\n    {\n        var str1 = \"test\";\n        var str2 = \"\";\n        var result = CosineSimilarity.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(0.0).Within(1e-6), \"Empty string should have a cosine similarity of 0.\");\n    }\n\n    [Test]\n    public void Calculate_SameCharactersDifferentCases_ReturnsOne()\n    {\n        var str1 = \"Test\";\n        var str2 = \"test\";\n        var result = CosineSimilarity.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(1.0).Within(1e-6), \"The method should be case-insensitive.\");\n    }\n\n    [Test]\n    public void Calculate_SpecialCharacters_ReturnsCorrectValue()\n    {\n        var str1 = \"hello!\";\n        var str2 = \"hello!\";\n        var result = CosineSimilarity.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(1.0).Within(1e-6), \"Strings with special characters should have a cosine similarity of 1.\");\n    }\n\n    [Test]\n    public void Calculate_DifferentLengthWithCommonCharacters_ReturnsCorrectValue()\n    {\n        var str1 = \"hello\";\n        var str2 = \"hello world\";\n        var result = CosineSimilarity.Calculate(str1, str2);\n        var expected = 10 / (Math.Sqrt(7) * Math.Sqrt(19)); // calculated manually\n        Assert.That(result, Is.EqualTo(expected).Within(1e-6), \"Strings with different lengths but some common characters should have the correct cosine similarity.\");\n    }\n\n    [Test]\n    public void Calculate_PartiallyMatchingStrings_ReturnsCorrectValue()\n    {\n        var str1 = \"night\";\n        var str2 = \"nacht\";\n        var result = CosineSimilarity.Calculate(str1, str2);\n        // Assuming the correct calculation gives an expected value\n        var expected = 3.0 / 5.0;\n        Assert.That(result, Is.EqualTo(expected).Within(1e-6), \"Partially matching strings should have the correct cosine similarity.\");\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/Similarity/DamerauLevenshteinDistanceTests.cs",
    "content": "﻿using Algorithms.Strings.Similarity;\n\nnamespace Algorithms.Tests.Strings.Similarity;\n\n[TestFixture]\npublic class DamerauLevenshteinDistanceTests\n{\n    [Test]\n    public void Calculate_IdenticalStrings_ReturnsZero()\n    {\n        var str1 = \"test\";\n        var str2 = \"test\";\n        var result = DamerauLevenshteinDistance.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(0), \"Identical strings should have a Damerau-Levenshtein distance of 0.\");\n    }\n\n    [Test]\n    public void Calculate_CompletelyDifferentStrings_ReturnsLengthOfLongestString()\n    {\n        var str1 = \"abc\";\n        var str2 = \"xyz\";\n        var result = DamerauLevenshteinDistance.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(3), \"Completely different strings should have a Damerau-Levenshtein distance equal to the length of the longest string.\");\n    }\n\n    [Test]\n    public void Calculate_OneEmptyString_ReturnsLengthOfOtherString()\n    {\n        var str1 = \"test\";\n        var str2 = \"\";\n        var result = DamerauLevenshteinDistance.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(4), \"One empty string should have a Damerau-Levenshtein distance equal to the length of the other string.\");\n    }\n\n    [Test]\n    public void Calculate_BothEmptyStrings_ReturnsZero()\n    {\n        var str1 = \"\";\n        var str2 = \"\";\n        var result = DamerauLevenshteinDistance.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(0), \"Both empty strings should have a Damerau-Levenshtein distance of 0.\");\n    }\n\n    [Test]\n    public void Calculate_DifferentLengths_ReturnsCorrectValue()\n    {\n        var str1 = \"short\";\n        var str2 = \"longer\";\n        var result = DamerauLevenshteinDistance.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(6), \"Strings of different lengths should return the correct Damerau-Levenshtein distance.\");\n    }\n\n    [Test]\n    public void Calculate_SpecialCharacters_ReturnsCorrectValue()\n    {\n        var str1 = \"hello!\";\n        var str2 = \"hello?\";\n        var result = DamerauLevenshteinDistance.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(1), \"Strings with special characters should return the correct Damerau-Levenshtein distance.\");\n    }\n\n    [Test]\n    public void Calculate_DifferentCases_ReturnsCorrectValue()\n    {\n        var str1 = \"Hello\";\n        var str2 = \"hello\";\n        var result = DamerauLevenshteinDistance.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(1), \"Strings with different cases should return the correct Damerau-Levenshtein distance.\");\n    }\n\n    [Test]\n    public void Calculate_CommonPrefixes_ReturnsCorrectValue()\n    {\n        var str1 = \"prefix\";\n        var str2 = \"pre\";\n        var result = DamerauLevenshteinDistance.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(3), \"Strings with common prefixes should return the correct Damerau-Levenshtein distance.\");\n    }\n\n    [Test]\n    public void Calculate_CommonSuffixes_ReturnsCorrectValue()\n    {\n        var str1 = \"suffix\";\n        var str2 = \"fix\";\n        var result = DamerauLevenshteinDistance.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(3), \"Strings with common suffixes should return the correct Damerau-Levenshtein distance.\");\n    }\n\n    [Test]\n    public void Calculate_Transpositions_ReturnsCorrectValue()\n    {\n        var str1 = \"abcd\";\n        var str2 = \"acbd\";\n        var result = DamerauLevenshteinDistance.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(1), \"Strings with transpositions should return the correct Damerau-Levenshtein distance.\");\n    }\n\n    [Test]\n    public void Calculate_RepeatedCharacters_ReturnsCorrectValue()\n    {\n        var str1 = \"aaa\";\n        var str2 = \"aaaaa\";\n        var result = DamerauLevenshteinDistance.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(2), \"Strings with repeated characters should return the correct Damerau-Levenshtein distance.\");\n    }\n\n    [Test]\n    public void Calculate_UnicodeCharacters_ReturnsCorrectValue()\n    {\n        var str1 = \"こんにちは\";\n        var str2 = \"こんばんは\";\n        var result = DamerauLevenshteinDistance.Calculate(str1, str2);\n        Assert.That(result, Is.EqualTo(2), \"Strings with Unicode characters should return the correct Damerau-Levenshtein distance.\");\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/Similarity/HammingDistanceTests.cs",
    "content": "using Algorithms.Strings.Similarity;\n\nnamespace Algorithms.Tests.Strings;\n\npublic class HammingDistanceTests\n{\n    [TestCase(\"equal\", \"equal\", 0)]\n    [TestCase(\"dog\", \"dig\", 1)]\n    [TestCase(\"12345\", \"abcde\", 5)]\n    public void Calculate_ReturnsCorrectHammingDistance(string s1, string s2, int expectedDistance)\n    {\n        var result = HammingDistance.Calculate(s1, s2);\n        Assert.That(result, Is.EqualTo(expectedDistance));\n    }\n\n    [Test]\n    public void Calculate_ThrowsArgumentExceptionWhenStringLengthsDiffer()\n    {\n        Assert.Throws<ArgumentException>(() => HammingDistance.Calculate(\"123\", \"12345\"));\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/Similarity/JaccardDistanceTests.cs",
    "content": "﻿using Algorithms.Strings.Similarity;\n\nnamespace Algorithms.Tests.Strings.Similarity;\n\npublic class JaccardDistanceTests\n{\n    private readonly JaccardDistance jaccard = new JaccardDistance();\n    private readonly double precision = 0.0001;\n\n    [TestCase(\"left\", null)]\n    [TestCase(null, \"right\")]\n    [TestCase(null, null)]\n    public void Calculate_WhenStringsAreNull_ThrowsArgumentNullException(string left, string right)\n    {\n        Action action = () => jaccard.Calculate(left, right);\n        action.Should().Throw<ArgumentNullException>();\n    }\n\n\n    [TestCase(\"\", \"\", 0.0d)]\n    [TestCase(\"left\", \"\", 1.0d)]\n    [TestCase(\"\", \"right\", 1.0d)]\n    [TestCase(\"frog\", \"fog\", 0.25d)]\n    [TestCase(\"fly\", \"ant\", 1.0d)]\n    [TestCase(\"elephant\", \"hippo\", 0.777777d)]\n    [TestCase(\"ABC Corporation\", \"ABC Corp\", 0.36363d)]\n    public void Calculate_WhenProvidedWithStrings_CalculatesCorrectDistance(string left, string right, double expected)\n    {\n        var distance = jaccard.Calculate(left, right);\n\n        distance.Should().BeApproximately(expected, precision);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/Similarity/JaccardSimilarityTests.cs",
    "content": "﻿using Algorithms.Strings.Similarity;\n\nnamespace Algorithms.Tests.Strings.Similarity;\n\npublic class JaccardSimilarityTests\n{\n    private readonly JaccardSimilarity jaccard = new JaccardSimilarity();\n    private readonly double precision = 0.0001;\n\n    [TestCase(\"left\", null)]\n    [TestCase(null, \"right\")]\n    [TestCase(null, null)]\n    public void Calculate_WhenStringsAreNull_ThrowsArgumentNullException(string left, string right)\n    {\n        Action action = () => jaccard.Calculate(left, right);\n        action.Should().Throw<ArgumentNullException>();\n    }\n\n    [TestCase(\"\", \"\", 1.0d)]\n    [TestCase(\"left\", \"\", 0.0d)]\n    [TestCase(\"\", \"right\", 0.0d)]\n    [TestCase(\"frog\", \"fog\", 0.75d)]\n    [TestCase(\"fly\", \"ant\", 0.0d)]\n    [TestCase(\"elephant\", \"hippo\", 0.22222d)]\n    [TestCase(\"ABC Corporation\", \"ABC Corp\", 0.636363d)]\n    public void Calculate_WhenProvidedWithStrings_CalculatesTheCorrectDistance(string left, string right, double expected)\n    {\n        var similarity = jaccard.Calculate(left, right);\n\n        similarity.Should().BeApproximately(expected, precision);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/Similarity/JaroSimilarityTests.cs",
    "content": "using Algorithms.Strings.Similarity;\n\nnamespace Algorithms.Tests.Strings;\n\npublic class JaroSimilarityTests\n{\n    [TestCase(\"equal\", \"equal\", 1)]\n    [TestCase(\"abc\", \"123\", 0)]\n    [TestCase(\"FAREMVIEL\", \"FARMVILLE\", 0.88d)]\n    [TestCase(\"CRATE\", \"TRACE\", 0.73d)]\n    [TestCase(\"CRATE11111\", \"CRTAE11111\", 0.96d)]\n    [TestCase(\"a\", \"a\", 1)]\n    [TestCase(\"\", \"\", 1)]\n    public void Calculate_ReturnsCorrectJaroSimilarity(string s1, string s2, double expected)\n    {\n        JaroSimilarity.Calculate(s1, s2).Should().BeApproximately(expected, 0.01);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/Similarity/JaroWinklerDistanceTests.cs",
    "content": "using Algorithms.Strings.Similarity;\n\nnamespace Algorithms.Tests.Strings;\n\npublic class JaroWinklerDistanceTests\n{\n    [TestCase(\"equal\", \"equal\", 0)]\n    [TestCase(\"abc\", \"123\", 1)]\n    [TestCase(\"Winkler\", \"Welfare\", 0.33)]\n    [TestCase(\"faremviel\", \"farmville\", 0.08)]\n    [TestCase(\"\", \"\", 0)]\n    public void Calculate_ReturnsCorrectJaroWinklerDistance(string s1, string s2, double expected)\n    {\n        JaroWinklerDistance.Calculate(s1, s2).Should().BeApproximately(expected, 0.01);\n    }\n}\n"
  },
  {
    "path": "Algorithms.Tests/Strings/Similarity/OptimalStringAlignmentTests.cs",
    "content": "using Algorithms.Strings.Similarity;\n\nnamespace Algorithms.Tests.Strings.Similarity\n{\n    [TestFixture]\n    public class OptimalStringAlignmentTests\n    {\n        [Test]\n        public void Calculate_IdenticalStrings_ReturnsZero()\n        {\n            var result = OptimalStringAlignment.Calculate(\"example\", \"example\");\n            result.Should().Be(0.0);\n        }\n\n        [Test]\n        public void Calculate_FirstStringEmpty_ReturnsLengthOfSecondString()\n        {\n            var result = OptimalStringAlignment.Calculate(\"\", \"example\");\n            result.Should().Be(\"example\".Length);\n        }\n\n        [Test]\n        public void Calculate_SecondStringEmpty_ReturnsLengthOfFirstString()\n        {\n            var result = OptimalStringAlignment.Calculate(\"example\", \"\");\n            result.Should().Be(\"example\".Length);\n        }\n\n        [Test]\n        public void Calculate_BothStringsEmpty_ReturnsZero()\n        {\n            var result = OptimalStringAlignment.Calculate(\"\", \"\");\n            result.Should().Be(0.0);\n        }\n\n        [Test]\n        public void Calculate_OneInsertion_ReturnsOne()\n        {\n            var result = OptimalStringAlignment.Calculate(\"example\", \"examples\");\n            result.Should().Be(1.0);\n        }\n\n        [Test]\n        public void Calculate_OneDeletion_ReturnsOne()\n        {\n            var result = OptimalStringAlignment.Calculate(\"examples\", \"example\");\n            result.Should().Be(1.0);\n        }\n\n        [Test]\n        public void Calculate_OneSubstitution_ReturnsOne()\n        {\n            var result = OptimalStringAlignment.Calculate(\"example\", \"exbmple\");\n            result.Should().Be(1.0);\n        }\n\n        [Test]\n        public void Calculate_OneTransposition_ReturnsOne()\n        {\n            var result = OptimalStringAlignment.Calculate(\"example\", \"exmaple\");\n            result.Should().Be(1.0);\n        }\n\n        [Test]\n        public void Calculate_MultipleOperations_ReturnsCorrectDistance()\n        {\n            var result = OptimalStringAlignment.Calculate(\"kitten\", \"sitting\");\n            result.Should().Be(3.0);\n        }\n    }\n}\n"
  },
  {
    "path": "C-Sharp.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.28803.352\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Docs\", \"Docs\", \"{DAB16DEC-AF31-4B59-8DD5-5C76C1A23052}\"\n\tProjectSection(SolutionItems) = preProject\n\t\tCODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md\n\t\tCONTRIBUTING.md = CONTRIBUTING.md\n\t\tLICENSE = LICENSE\n\t\tREADME.md = README.md\n\tEndProjectSection\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Configs\", \"Configs\", \"{F3AC2246-318B-4EE4-BD9E-D751D3044901}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t.editorconfig = .editorconfig\n\t\t.gitignore = .gitignore\n\t\tstylecop.json = stylecop.json\n\t\tstylecop.ruleset = stylecop.ruleset\n\tEndProjectSection\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Algorithms\", \"Algorithms\\Algorithms.csproj\", \"{EC967159-73D8-4E44-8455-E2D16DB4CBBB}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Algorithms.Tests\", \"Algorithms.Tests\\Algorithms.Tests.csproj\", \"{56817595-1552-409B-93B8-F8082F8490A5}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DataStructures\", \"DataStructures\\DataStructures.csproj\", \"{E9C27C73-1F95-4C6E-9DB4-F8585426A850}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DataStructures.Tests\", \"DataStructures.Tests\\DataStructures.Tests.csproj\", \"{39174100-3A6E-45B2-9AA9-7C69764C0750}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Utilities\", \"Utilities\\Utilities.csproj\", \"{3A41157D-296D-4BFC-A34E-91B5ED7F0905}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Utilities.Tests\", \"Utilities.Tests\\Utilities.Tests.csproj\", \"{ED47E2E2-045C-41DD-B555-A64944D6C2F5}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{EC967159-73D8-4E44-8455-E2D16DB4CBBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{EC967159-73D8-4E44-8455-E2D16DB4CBBB}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{EC967159-73D8-4E44-8455-E2D16DB4CBBB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{EC967159-73D8-4E44-8455-E2D16DB4CBBB}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{56817595-1552-409B-93B8-F8082F8490A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{56817595-1552-409B-93B8-F8082F8490A5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{56817595-1552-409B-93B8-F8082F8490A5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{56817595-1552-409B-93B8-F8082F8490A5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{E9C27C73-1F95-4C6E-9DB4-F8585426A850}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E9C27C73-1F95-4C6E-9DB4-F8585426A850}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E9C27C73-1F95-4C6E-9DB4-F8585426A850}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E9C27C73-1F95-4C6E-9DB4-F8585426A850}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{39174100-3A6E-45B2-9AA9-7C69764C0750}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{39174100-3A6E-45B2-9AA9-7C69764C0750}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{39174100-3A6E-45B2-9AA9-7C69764C0750}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{39174100-3A6E-45B2-9AA9-7C69764C0750}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3A41157D-296D-4BFC-A34E-91B5ED7F0905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3A41157D-296D-4BFC-A34E-91B5ED7F0905}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3A41157D-296D-4BFC-A34E-91B5ED7F0905}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3A41157D-296D-4BFC-A34E-91B5ED7F0905}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{ED47E2E2-045C-41DD-B555-A64944D6C2F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{ED47E2E2-045C-41DD-B555-A64944D6C2F5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{ED47E2E2-045C-41DD-B555-A64944D6C2F5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{ED47E2E2-045C-41DD-B555-A64944D6C2F5}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {9D733AD8-7C69-4F40-ADBB-2DD8EA9F18FB}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at siryaka@gmail.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n## General notes\nWhen contributing to this repository, if your changes are subjective, controversial or people are likely to have\npolarized opinions on this matter, please first discuss the change you wish to make via issue with the owners of\nthis repository.\n\nWe welcome adding new algorithms and data structures that were mentioned in books or other reputable sources.\nWe also welcome fixing bugs in code, clarifying documentation and adding new test cases to check existing code.\nThe framework targeted by our code is **dotnet 8**. The corresponding SDK can be found [here](https://dotnet.microsoft.com/download/dotnet/8.0).\n\nPlease note that we have a code of conduct, please follow it in all your interactions with the project.\n\n## Files\nFor adding new algorithms, please ensure to name the cs-files corresponding to the classname, e.g. `Factorial.cs` for the class `Factorial` and add them to the most relevant pre-existing folder. Make sure to implement tests for all public methods. These tests should be added in a separate cs-file to the corresponding folder in `Algorithms.Tests` and have their classname ending in \"Test\", e.g. `FactorialTest`.\n\n## Tests\nWe use the [NUnit-library](https://nunit.org/) for testing. Instructions for the installation for local testing can be found [here](https://docs.nunit.org/articles/nunit/getting-started/installation.html). A basic test can be implemented by adding the attribute `[Test]` in front of the method performing the test and including an Assert-statement within the method, e.g. `Assert.AreEqual(result, 42)`. If possible, please use [FluentAssertions](https://fluentassertions.com/) since they are more eloquent and readable. Some of the basic assertions can be found [here](https://fluentassertions.com/basicassertions/). For getting familiar with the Nunit-tests, it might be helpful to have a look at some existing test-files. A tutorial explaining how to implement and run NUnit-tests can be found [here](https://www.c-sharpcorner.com/article/introduction-to-nunit-testing-framework/).\n\n## Automatic checks\nOne of the automatic checks we use is [codecov](https://about.codecov.io/). It checks whether each conditional branch is covered by a test. So if a method contains a conditional statement or operator (if-else, switch, ?: ) then there should be at least a test per branch (unless all the branches can be covered in one run).\n\nThe coding style follows the default code formatter of Visual Studio.\n\n## Comments\nPlease use the [XML documentation features](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc/how-to-use-the-xml-documentation-features) for comments. The comments should include a summary of the class/method and an explanation of the different parameters and of the return value. Including a link to Wikipedia or to another source of information on the algorithm is encouraged.\n"
  },
  {
    "path": "DataStructures/AATree/AATree.cs",
    "content": "namespace DataStructures.AATree;\n\n/// <summary>\n///     A simple self-balancing binary search tree.\n/// </summary>\n/// <remarks>\n///     AA Trees are a form of self-balancing binary search tree named after their inventor\n///     Arne Anderson. AA Trees are designed to be simple to understand and implement.\n///     This is accomplished by limiting how nodes can be added to the tree.\n///     This simplifies rebalancing operations.\n///     More information: https://en.wikipedia.org/wiki/AA_tree .\n/// </remarks>\n/// <typeparam name=\"TKey\">The type of key for the AA tree.</typeparam>\n/// <remarks>\n///     Initializes a new instance of the <see cref=\"AaTree{TKey}\" /> class with a custom comparer.\n/// </remarks>\n/// <param name=\"customComparer\">The custom comparer to use to compare keys.</param>\npublic class AaTree<TKey>(Comparer<TKey> customComparer)\n{\n    /// <summary>\n    ///     The comparer function to use to compare the keys.\n    /// </summary>\n    private readonly Comparer<TKey> comparer = customComparer;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"AaTree{TKey}\" /> class.\n    /// </summary>\n    public AaTree()\n        : this(Comparer<TKey>.Default)\n    {\n    }\n\n    /// <summary>\n    ///     Gets the root of the tree.\n    /// </summary>\n    public AaTreeNode<TKey>? Root { get; private set; }\n\n    /// <summary>\n    ///     Gets the number of elements in the tree.\n    /// </summary>\n    public int Count { get; private set; }\n\n    /// <summary>\n    ///     Add a single element to the tree.\n    /// </summary>\n    /// <param name=\"key\">The element to add to the tree.</param>\n    public void Add(TKey key)\n    {\n        Root = Add(key, Root);\n        Count++;\n    }\n\n    /// <summary>\n    ///     Add multiple elements to the tree.\n    /// </summary>\n    /// <param name=\"keys\">The elements to add to the tree.</param>\n    public void AddRange(IEnumerable<TKey> keys)\n    {\n        foreach (var key in keys)\n        {\n            Root = Add(key, Root);\n            Count++;\n        }\n    }\n\n    /// <summary>\n    ///     Remove a single element from the tree.\n    /// </summary>\n    /// <param name=\"key\">Element to remove.</param>\n    public void Remove(TKey key)\n    {\n        if (!Contains(key, Root))\n        {\n            throw new InvalidOperationException($\"{nameof(key)} is not in the tree\");\n        }\n\n        Root = Remove(key, Root);\n        Count--;\n    }\n\n    /// <summary>\n    ///     Checks if the specified element is in the tree.\n    /// </summary>\n    /// <param name=\"key\">The element to look for.</param>\n    /// <returns>true if the element is in the tree, false otherwise.</returns>\n    public bool Contains(TKey key) => Contains(key, Root);\n\n    /// <summary>\n    ///     Gets the largest element in the tree. (ie. the element in the right most node).\n    /// </summary>\n    /// <returns>The largest element in the tree according to the stored comparer.</returns>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the tree is empty.</exception>\n    public TKey GetMax()\n    {\n        if (Root is null)\n        {\n            throw new InvalidOperationException(\"Tree is empty!\");\n        }\n\n        return GetMax(Root).Key;\n    }\n\n    /// <summary>\n    ///     Gets the smallest element in the tree. (ie. the element in the left most node).\n    /// </summary>\n    /// <returns>The smallest element in the tree according to the stored comparer.</returns>\n    /// <throws>InvalidOperationException if the tree is empty.</throws>\n    public TKey GetMin()\n    {\n        if (Root is null)\n        {\n            throw new InvalidOperationException(\"Tree is empty!\");\n        }\n\n        return GetMin(Root).Key;\n    }\n\n    /// <summary>\n    ///     Gets all the elements in the tree in in-order order.\n    /// </summary>\n    /// <returns>Sequence of elements in in-order order.</returns>\n    public IEnumerable<TKey> GetKeysInOrder()\n    {\n        var result = new List<TKey>();\n        InOrderWalk(Root);\n        return result;\n\n        void InOrderWalk(AaTreeNode<TKey>? node)\n        {\n            if (node is null)\n            {\n                return;\n            }\n\n            InOrderWalk(node.Left);\n            result.Add(node.Key);\n            InOrderWalk(node.Right);\n        }\n    }\n\n    /// <summary>\n    ///     Gets all the elements in the tree in pre-order order.\n    /// </summary>\n    /// <returns>Sequence of elements in pre-order order.</returns>\n    public IEnumerable<TKey> GetKeysPreOrder()\n    {\n        var result = new List<TKey>();\n        PreOrderWalk(Root);\n        return result;\n\n        void PreOrderWalk(AaTreeNode<TKey>? node)\n        {\n            if (node is null)\n            {\n                return;\n            }\n\n            result.Add(node.Key);\n            PreOrderWalk(node.Left);\n            PreOrderWalk(node.Right);\n        }\n    }\n\n    /// <summary>\n    ///     Gets all the elements in the tree in post-order order.\n    /// </summary>\n    /// <returns>Sequence of elements in post-order order.</returns>\n    public IEnumerable<TKey> GetKeysPostOrder()\n    {\n        var result = new List<TKey>();\n        PostOrderWalk(Root);\n        return result;\n\n        void PostOrderWalk(AaTreeNode<TKey>? node)\n        {\n            if (node is null)\n            {\n                return;\n            }\n\n            PostOrderWalk(node.Left);\n            PostOrderWalk(node.Right);\n            result.Add(node.Key);\n        }\n    }\n\n    /// <summary>\n    ///     Recursive function to add an element to the tree.\n    /// </summary>\n    /// <param name=\"key\">The element to add.</param>\n    /// <param name=\"node\">The node to search for a empty spot.</param>\n    /// <returns>The node with the added element.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown if key is already in the tree.</exception>\n    private AaTreeNode<TKey> Add(TKey key, AaTreeNode<TKey>? node)\n    {\n        if (node is null)\n        {\n            return new AaTreeNode<TKey>(key, 1);\n        }\n\n        if (comparer.Compare(key, node.Key) < 0)\n        {\n            node.Left = Add(key, node.Left);\n        }\n        else if (comparer.Compare(key, node.Key) > 0)\n        {\n            node.Right = Add(key, node.Right);\n        }\n        else\n        {\n            throw new ArgumentException($\"\"\"Key \"{key}\" already in tree!\"\"\", nameof(key));\n        }\n\n        return Split(Skew(node))!;\n    }\n\n    /// <summary>\n    ///     Recursive function to remove an element from the tree.\n    /// </summary>\n    /// <param name=\"key\">The element to remove.</param>\n    /// <param name=\"node\">The node to search from.</param>\n    /// <returns>The node with the specified element removed.</returns>\n    private AaTreeNode<TKey>? Remove(TKey key, AaTreeNode<TKey>? node)\n    {\n        if (node is null)\n        {\n            return null;\n        }\n\n        if (comparer.Compare(key, node.Key) < 0)\n        {\n            node.Left = Remove(key, node.Left);\n        }\n        else if (comparer.Compare(key, node.Key) > 0)\n        {\n            node.Right = Remove(key, node.Right);\n        }\n        else\n        {\n            if (node.Left is null && node.Right is null)\n            {\n                return null;\n            }\n\n            if (node.Left is null)\n            {\n                var successor = GetMin(node.Right!);\n                node.Right = Remove(successor.Key, node.Right);\n                node.Key = successor.Key;\n            }\n            else\n            {\n                var predecessor = GetMax(node.Left);\n                node.Left = Remove(predecessor.Key, node.Left);\n                node.Key = predecessor.Key;\n            }\n        }\n\n        node = DecreaseLevel(node);\n        node = Skew(node);\n        node!.Right = Skew(node.Right);\n\n        if (node.Right is not null)\n        {\n            node.Right.Right = Skew(node.Right.Right);\n        }\n\n        node = Split(node);\n        node!.Right = Split(node.Right);\n        return node;\n    }\n\n    /// <summary>\n    ///     Recursive function to check if the element exists in the tree.\n    /// </summary>\n    /// <param name=\"key\">The element to check for.</param>\n    /// <param name=\"node\">The node to search from.</param>\n    /// <returns>true if the element exists in the tree, false otherwise.</returns>\n    private bool Contains(TKey key, AaTreeNode<TKey>? node) =>\n        node is { }\n        && comparer.Compare(key, node.Key) is { } v\n        && v switch\n        {\n            { } when v > 0 => Contains(key, node.Right),\n            { } when v < 0 => Contains(key, node.Left),\n            _ => true,\n        };\n\n    /// <summary>\n    ///     Recursive to find the maximum/right-most element.\n    /// </summary>\n    /// <param name=\"node\">The node to traverse from.</param>\n    /// <returns>The node with the maximum/right-most element.</returns>\n    private AaTreeNode<TKey> GetMax(AaTreeNode<TKey> node)\n    {\n        while (true)\n        {\n            if (node.Right is null)\n            {\n                return node;\n            }\n\n            node = node.Right;\n        }\n    }\n\n    /// <summary>\n    ///     Recursive to find the minimum/left-most element.\n    /// </summary>\n    /// <param name=\"node\">The node to traverse from.</param>\n    /// <returns>The node with the minimum/left-most element.</returns>\n    private AaTreeNode<TKey> GetMin(AaTreeNode<TKey> node)\n    {\n        while (true)\n        {\n            if (node.Left is null)\n            {\n                return node;\n            }\n\n            node = node.Left;\n        }\n    }\n\n    /// <summary>\n    ///     Remove right-horizontal links and replaces them with left-horizontal links.\n    ///     Accomplishes this by performing a right rotation.\n    /// </summary>\n    /// <param name=\"node\">The node to rebalance from.</param>\n    /// <returns>The rebalanced node.</returns>\n    private AaTreeNode<TKey>? Skew(AaTreeNode<TKey>? node)\n    {\n        if (node?.Left is null || node.Left.Level != node.Level)\n        {\n            return node;\n        }\n\n        var left = node.Left;\n        node.Left = left.Right;\n        left.Right = node;\n        return left;\n    }\n\n    /// <summary>\n    ///     Reduces the number of right-horizontal links.\n    ///     Accomplishes this by performing a left rotation, and incrementing level.\n    /// </summary>\n    /// <param name=\"node\">The node to rebalance from.</param>\n    /// <returns>The rebalanced node.</returns>\n    private AaTreeNode<TKey>? Split(AaTreeNode<TKey>? node)\n    {\n        if (node?.Right?.Right is null || node.Level != node.Right.Right.Level)\n        {\n            return node;\n        }\n\n        var right = node.Right;\n        node.Right = right.Left;\n        right.Left = node;\n        right.Level++;\n        return right;\n    }\n\n    /// <summary>\n    ///     Decreases the level of node if necessary.\n    /// </summary>\n    /// <param name=\"node\">The node to decrease level from.</param>\n    /// <returns>The node with modified level.</returns>\n    private AaTreeNode<TKey> DecreaseLevel(AaTreeNode<TKey> node)\n    {\n        var newLevel = Math.Min(GetLevel(node.Left), GetLevel(node.Right)) + 1;\n        if (newLevel >= node.Level)\n        {\n            return node;\n        }\n\n        node.Level = newLevel;\n        if (node.Right is { } && newLevel < node.Right.Level)\n        {\n            node.Right.Level = newLevel;\n        }\n\n        return node;\n\n        static int GetLevel(AaTreeNode<TKey>? x) => x?.Level ?? 0;\n    }\n}\n"
  },
  {
    "path": "DataStructures/AATree/AATreeNode.cs",
    "content": "namespace DataStructures.AATree;\n\n/// <summary>\n///     Generic node class for AATree.\n/// </summary>\n/// <typeparam name=\"TKey\">Type of key for node.</typeparam>\n/// <remarks>\n///     Initializes a new instance of the <see cref=\"AaTreeNode{TKey}\" /> class.\n/// </remarks>\n/// <param name=\"key\">The initial key of this node.</param>\n/// <param name=\"level\">The level of this node. See <see cref=\"AaTree{TKey}\" /> for more details.</param>\npublic class AaTreeNode<TKey>(TKey key, int level)\n{\n    /// <summary>\n    ///     Gets or Sets key for this node.\n    /// </summary>\n    public TKey Key { get; set; } = key;\n\n    /// <summary>\n    ///     Gets or Sets level for this node.\n    /// </summary>\n    public int Level { get; set; } = level;\n\n    /// <summary>\n    ///     Gets or sets the left subtree of this node.\n    /// </summary>\n    public AaTreeNode<TKey>? Left { get; set; }\n\n    /// <summary>\n    ///     Gets or sets the right subtree of this node.\n    /// </summary>\n    public AaTreeNode<TKey>? Right { get; set; }\n}\n"
  },
  {
    "path": "DataStructures/AVLTree/AVLTree.cs",
    "content": "namespace DataStructures.AVLTree;\n\n/// <summary>\n///     A simple self-balancing binary tree.\n/// </summary>\n/// <remarks>\n///     An AVL tree is a self-balancing binary search tree (BST) named after\n///     its inventors: Adelson, Velsky, and Landis. It is the first self-\n///     balancing BST invented. The primary property of an AVL tree is that\n///     the height of both child subtrees for any node only differ by one.\n///     Due to the balanced nature of the tree, its time complexities for\n///     insertion, deletion, and search all have a worst-case time\n///     complexity of O(log n). Which is an improvement over the worst-case\n///     O(n) for a regular BST.\n///     See https://en.wikipedia.org/wiki/AVL_tree for more information.\n///     Visualizer: https://visualgo.net/en/bst.\n/// </remarks>\n/// <typeparam name=\"TKey\">Type of key for the tree.</typeparam>\npublic class AvlTree<TKey>\n{\n    /// <summary>\n    ///     Gets the number of nodes in the tree.\n    /// </summary>\n    public int Count { get; private set; }\n\n    /// <summary>\n    ///     Comparer to use when comparing key values.\n    /// </summary>\n    private readonly Comparer<TKey> comparer;\n\n    /// <summary>\n    ///     Reference to the root node.\n    /// </summary>\n    private AvlTreeNode<TKey>? root;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"AvlTree{TKey}\"/>\n    ///     class.\n    /// </summary>\n    public AvlTree()\n    {\n        comparer = Comparer<TKey>.Default;\n    }\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"AvlTree{TKey}\"/>\n    ///     class using the specified comparer.\n    /// </summary>\n    /// <param name=\"customComparer\">\n    /// Comparer to use when comparing keys.\n    /// </param>\n    public AvlTree(Comparer<TKey> customComparer)\n    {\n        comparer = customComparer;\n    }\n\n    /// <summary>\n    ///     Add a single node to the tree.\n    /// </summary>\n    /// <param name=\"key\">Key value to add.</param>\n    public void Add(TKey key)\n    {\n        if (root is null)\n        {\n            root = new AvlTreeNode<TKey>(key);\n        }\n        else\n        {\n            root = Add(root, key);\n        }\n\n        Count++;\n    }\n\n    /// <summary>\n    ///     Add multiple nodes to the tree.\n    /// </summary>\n    /// <param name=\"keys\">Key values to add.</param>\n    public void AddRange(IEnumerable<TKey> keys)\n    {\n        foreach (var key in keys)\n        {\n            Add(key);\n        }\n    }\n\n    /// <summary>\n    ///     Remove a node from the tree.\n    /// </summary>\n    /// <param name=\"key\">Key value to remove.</param>\n    public void Remove(TKey key)\n    {\n        root = Remove(root, key);\n        Count--;\n    }\n\n    /// <summary>\n    ///     Check if given node is in the tree.\n    /// </summary>\n    /// <param name=\"key\">Key value to search for.</param>\n    /// <returns>Whether or not the node is in the tree.</returns>\n    public bool Contains(TKey key)\n    {\n        var node = root;\n        while (node is not null)\n        {\n            var compareResult = comparer.Compare(key, node.Key);\n            if (compareResult < 0)\n            {\n                node = node.Left;\n            }\n            else if (compareResult > 0)\n            {\n                node = node.Right;\n            }\n            else\n            {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /// <summary>\n    ///     Get the minimum value in the tree.\n    /// </summary>\n    /// <returns>Minimum value in tree.</returns>\n    public TKey GetMin()\n    {\n        if (root is null)\n        {\n            throw new InvalidOperationException(\"AVL tree is empty.\");\n        }\n\n        return GetMin(root).Key;\n    }\n\n    /// <summary>\n    ///     Get the maximum value in the tree.\n    /// </summary>\n    /// <returns>Maximum value in tree.</returns>\n    public TKey GetMax()\n    {\n        if (root is null)\n        {\n            throw new InvalidOperationException(\"AVL tree is empty.\");\n        }\n\n        return GetMax(root).Key;\n    }\n\n    /// <summary>\n    ///     Get keys in order from smallest to largest as defined by the\n    ///     comparer.\n    /// </summary>\n    /// <returns>Keys in tree in order from smallest to largest.</returns>\n    public IEnumerable<TKey> GetKeysInOrder()\n    {\n        List<TKey> result = [];\n        InOrderWalk(root);\n        return result;\n\n        void InOrderWalk(AvlTreeNode<TKey>? node)\n        {\n            if (node is null)\n            {\n                return;\n            }\n\n            InOrderWalk(node.Left);\n            result.Add(node.Key);\n            InOrderWalk(node.Right);\n        }\n    }\n\n    /// <summary>\n    ///     Get keys in the pre-order order.\n    /// </summary>\n    /// <returns>Keys in pre-order order.</returns>\n    public IEnumerable<TKey> GetKeysPreOrder()\n    {\n        var result = new List<TKey>();\n        PreOrderWalk(root);\n        return result;\n\n        void PreOrderWalk(AvlTreeNode<TKey>? node)\n        {\n            if (node is null)\n            {\n                return;\n            }\n\n            result.Add(node.Key);\n            PreOrderWalk(node.Left);\n            PreOrderWalk(node.Right);\n        }\n    }\n\n    /// <summary>\n    ///     Get keys in the post-order order.\n    /// </summary>\n    /// <returns>Keys in the post-order order.</returns>\n    public IEnumerable<TKey> GetKeysPostOrder()\n    {\n        var result = new List<TKey>();\n        PostOrderWalk(root);\n        return result;\n\n        void PostOrderWalk(AvlTreeNode<TKey>? node)\n        {\n            if (node is null)\n            {\n                return;\n            }\n\n            PostOrderWalk(node.Left);\n            PostOrderWalk(node.Right);\n            result.Add(node.Key);\n        }\n    }\n\n    /// <summary>\n    ///     Helper function to rebalance the tree so that all nodes have a\n    ///     balance factor in the range [-1, 1].\n    /// </summary>\n    /// <param name=\"node\">Node to rebalance.</param>\n    /// <returns>New node that has been rebalanced.</returns>\n    private static AvlTreeNode<TKey> Rebalance(AvlTreeNode<TKey> node)\n    {\n        if (node.BalanceFactor > 1)\n        {\n            if (node.Right!.BalanceFactor == -1)\n            {\n                node.Right = RotateRight(node.Right);\n            }\n\n            return RotateLeft(node);\n        }\n\n        if (node.BalanceFactor < -1)\n        {\n            if (node.Left!.BalanceFactor == 1)\n            {\n                node.Left = RotateLeft(node.Left);\n            }\n\n            return RotateRight(node);\n        }\n\n        return node;\n    }\n\n    /// <summary>\n    ///     Perform a left (counter-clockwise) rotation.\n    /// </summary>\n    /// <param name=\"node\">Node to rotate about.</param>\n    /// <returns>New node with rotation applied.</returns>\n    private static AvlTreeNode<TKey> RotateLeft(AvlTreeNode<TKey> node)\n    {\n        var temp1 = node;\n        var temp2 = node.Right!.Left;\n        node = node.Right;\n        node.Left = temp1;\n        node.Left.Right = temp2;\n\n        node.Left.UpdateBalanceFactor();\n        node.UpdateBalanceFactor();\n\n        return node;\n    }\n\n    /// <summary>\n    ///     Perform a right (clockwise) rotation.\n    /// </summary>\n    /// <param name=\"node\">Node to rotate about.</param>\n    /// <returns>New node with rotation applied.</returns>\n    private static AvlTreeNode<TKey> RotateRight(AvlTreeNode<TKey> node)\n    {\n        var temp1 = node;\n        var temp2 = node.Left!.Right;\n        node = node.Left;\n        node.Right = temp1;\n        node.Right.Left = temp2;\n\n        node.Right.UpdateBalanceFactor();\n        node.UpdateBalanceFactor();\n\n        return node;\n    }\n\n    /// <summary>\n    ///     Helper function to get node instance with minimum key value\n    ///     in the specified subtree.\n    /// </summary>\n    /// <param name=\"node\">Node specifying root of subtree.</param>\n    /// <returns>Minimum value in node's subtree.</returns>\n    private static AvlTreeNode<TKey> GetMin(AvlTreeNode<TKey> node)\n    {\n        while (node.Left is not null)\n        {\n            node = node.Left;\n        }\n\n        return node;\n    }\n\n    /// <summary>\n    ///     Helper function to get node instance with maximum key value\n    ///     in the specified subtree.\n    /// </summary>\n    /// <param name=\"node\">Node specifying root of subtree.</param>\n    /// <returns>Maximum value in node's subtree.</returns>\n    private static AvlTreeNode<TKey> GetMax(AvlTreeNode<TKey> node)\n    {\n        while (node.Right is not null)\n        {\n            node = node.Right;\n        }\n\n        return node;\n    }\n\n    /// <summary>\n    ///     Recursively function to add a node to the tree.\n    /// </summary>\n    /// <param name=\"node\">Node to check for null leaf.</param>\n    /// <param name=\"key\">Key value to add.</param>\n    /// <returns>New node with key inserted.</returns>\n    private AvlTreeNode<TKey> Add(AvlTreeNode<TKey> node, TKey key)\n    {\n        // Regular binary search tree insertion\n        var compareResult = comparer.Compare(key, node.Key);\n        if (compareResult < 0)\n        {\n            if (node.Left is null)\n            {\n                var newNode = new AvlTreeNode<TKey>(key);\n                node.Left = newNode;\n            }\n            else\n            {\n                node.Left = Add(node.Left, key);\n            }\n        }\n        else if (compareResult > 0)\n        {\n            if (node.Right is null)\n            {\n                var newNode = new AvlTreeNode<TKey>(key);\n                node.Right = newNode;\n            }\n            else\n            {\n                node.Right = Add(node.Right, key);\n            }\n        }\n        else\n        {\n            throw new ArgumentException($\"\"\"Key \"{key}\" already exists in AVL tree.\"\"\");\n        }\n\n        // Check all of the new node's ancestors for imbalance and perform\n        // necessary rotations\n        node.UpdateBalanceFactor();\n\n        return Rebalance(node);\n    }\n\n    /// <summary>\n    ///     Recursive function to remove node from tree.\n    /// </summary>\n    /// <param name=\"node\">Node to check for key.</param>\n    /// <param name=\"key\">Key value to remove.</param>\n    /// <returns>New node with key removed.</returns>\n    private AvlTreeNode<TKey>? Remove(AvlTreeNode<TKey>? node, TKey key)\n    {\n        if (node == null)\n        {\n            throw new KeyNotFoundException(\n                $\"\"\"Key \"{key}\" is not in the AVL tree.\"\"\");\n        }\n\n        // Normal binary search tree removal\n        var compareResult = comparer.Compare(key, node.Key);\n        if (compareResult < 0)\n        {\n            node.Left = Remove(node.Left, key);\n        }\n        else if (compareResult > 0)\n        {\n            node.Right = Remove(node.Right, key);\n        }\n        else\n        {\n            if (node.Left is null && node.Right is null)\n            {\n                return null;\n            }\n\n            if (node.Left is null)\n            {\n                var successor = GetMin(node.Right!);\n                node.Right = Remove(node.Right!, successor.Key);\n                node.Key = successor.Key;\n            }\n            else\n            {\n                var predecessor = GetMax(node.Left!);\n                node.Left = Remove(node.Left!, predecessor.Key);\n                node.Key = predecessor.Key;\n            }\n        }\n\n        // Check all of the removed node's ancestors for rebalance and\n        // perform necessary rotations.\n        node.UpdateBalanceFactor();\n\n        return Rebalance(node);\n    }\n}\n"
  },
  {
    "path": "DataStructures/AVLTree/AVLTreeNode.cs",
    "content": "namespace DataStructures.AVLTree;\n\n/// <summary>\n///     Generic class to represent nodes in an <see cref=\"AvlTree{TKey}\"/>\n///     instance.\n/// </summary>\n/// <typeparam name=\"TKey\">The type of key for the node.</typeparam>\n/// <remarks>\n///     Initializes a new instance of the\n///     <see cref=\"AvlTreeNode{TKey}\"/> class.\n/// </remarks>\n/// <param name=\"key\">Key value for node.</param>\ninternal class AvlTreeNode<TKey>(TKey key)\n{\n    /// <summary>\n    ///     Gets or sets key value of node.\n    /// </summary>\n    public TKey Key { get; set; } = key;\n\n    /// <summary>\n    ///     Gets the balance factor of the node.\n    /// </summary>\n    public int BalanceFactor { get; private set; }\n\n    /// <summary>\n    ///     Gets or sets the left child of the node.\n    /// </summary>\n    public AvlTreeNode<TKey>? Left { get; set; }\n\n    /// <summary>\n    ///     Gets or sets the right child of the node.\n    /// </summary>\n    public AvlTreeNode<TKey>? Right { get; set; }\n\n    /// <summary>\n    ///     Gets or sets the height of the node.\n    /// </summary>\n    private int Height { get; set; }\n\n    /// <summary>\n    ///     Update the node's height and balance factor.\n    /// </summary>\n    public void UpdateBalanceFactor()\n    {\n        if (Left is null && Right is null)\n        {\n            Height = 0;\n            BalanceFactor = 0;\n        }\n        else if (Left is null)\n        {\n            Height = Right!.Height + 1;\n            BalanceFactor = Height;\n        }\n        else if (Right is null)\n        {\n            Height = Left!.Height + 1;\n            BalanceFactor = -Height;\n        }\n        else\n        {\n            Height = Math.Max(Left.Height, Right.Height) + 1;\n            BalanceFactor = Right.Height - Left.Height;\n        }\n    }\n}\n"
  },
  {
    "path": "DataStructures/BTree/BTree.cs",
    "content": "namespace DataStructures.BTree;\n\n/// <summary>\n///     A self-balancing search tree data structure that maintains sorted data\n///     and allows searches, sequential access, insertions, and deletions in\n///     logarithmic time.\n/// </summary>\n/// <remarks>\n///     A B-Tree is a generalization of a binary search tree in which a node\n///     can have more than two children. Unlike self-balancing binary search\n///     trees, the B-Tree is optimized for systems that read and write large\n///     blocks of data. It is commonly used in databases and file systems.\n///\n///     Properties of a B-Tree of minimum degree t:\n///     1. Every node has at most 2t-1 keys.\n///     2. Every node (except root) has at least t-1 keys.\n///     3. The root has at least 1 key (if tree is not empty).\n///     4. All leaves are at the same level.\n///     5. A non-leaf node with k keys has k+1 children.\n///\n///     Time Complexity:\n///     - Search: O(log n)\n///     - Insert: O(log n)\n///     - Delete: O(log n)\n///\n///     Space Complexity: O(n)\n///\n///     See https://en.wikipedia.org/wiki/B-tree for more information.\n///     Visualizer: https://www.cs.usfca.edu/~galles/visualization/BTree.html.\n/// </remarks>\n/// <typeparam name=\"TKey\">Type of key for the tree.</typeparam>\npublic class BTree<TKey>\n{\n    /// <summary>\n    ///     Gets the number of keys in the tree.\n    /// </summary>\n    public int Count { get; private set; }\n\n    /// <summary>\n    ///     Gets the minimum degree (t) of the B-Tree.\n    ///     Each node can contain at most 2t-1 keys and at least t-1 keys (except root).\n    /// </summary>\n    public int MinimumDegree { get; }\n\n    /// <summary>\n    ///     Comparer to use when comparing key values.\n    /// </summary>\n    private readonly Comparer<TKey> comparer;\n\n    /// <summary>\n    ///     Reference to the root node.\n    /// </summary>\n    private BTreeNode<TKey>? root;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"BTree{TKey}\"/>\n    ///     class with the specified minimum degree.\n    /// </summary>\n    /// <param name=\"minimumDegree\">\n    ///     Minimum degree (t) of the B-Tree. Must be at least 2.\n    ///     Each node can contain at most 2t-1 keys.\n    /// </param>\n    /// <exception cref=\"ArgumentException\">\n    ///     Thrown when minimumDegree is less than 2.\n    /// </exception>\n    public BTree(int minimumDegree = 2)\n    {\n        if (minimumDegree < 2)\n        {\n            throw new ArgumentException(\"Minimum degree must be at least 2.\", nameof(minimumDegree));\n        }\n\n        MinimumDegree = minimumDegree;\n        comparer = Comparer<TKey>.Default;\n    }\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"BTree{TKey}\"/>\n    ///     class with the specified minimum degree and custom comparer.\n    /// </summary>\n    /// <param name=\"minimumDegree\">\n    ///     Minimum degree (t) of the B-Tree. Must be at least 2.\n    /// </param>\n    /// <param name=\"customComparer\">\n    ///     Comparer to use when comparing keys.\n    /// </param>\n    /// <exception cref=\"ArgumentException\">\n    ///     Thrown when minimumDegree is less than 2.\n    /// </exception>\n    public BTree(int minimumDegree, Comparer<TKey> customComparer)\n    {\n        if (minimumDegree < 2)\n        {\n            throw new ArgumentException(\"Minimum degree must be at least 2.\", nameof(minimumDegree));\n        }\n\n        MinimumDegree = minimumDegree;\n        comparer = customComparer;\n    }\n\n    /// <summary>\n    ///     Add a single key to the tree.\n    /// </summary>\n    /// <param name=\"key\">Key value to add.</param>\n    public void Add(TKey key)\n    {\n        if (root is null)\n        {\n            root = new BTreeNode<TKey>(MinimumDegree, true);\n            root.InsertKey(0, key);\n            Count++;\n            return;\n        }\n\n        if (root.IsFull())\n        {\n            var newRoot = new BTreeNode<TKey>(MinimumDegree, false);\n            newRoot.InsertChild(0, root);\n            SplitChild(newRoot, 0);\n            root = newRoot;\n        }\n\n        InsertNonFull(root, key);\n        Count++;\n    }\n\n    /// <summary>\n    ///     Add multiple keys to the tree.\n    /// </summary>\n    /// <param name=\"keys\">Key values to add.</param>\n    public void AddRange(IEnumerable<TKey> keys)\n    {\n        foreach (var key in keys)\n        {\n            Add(key);\n        }\n    }\n\n    /// <summary>\n    ///     Remove a key from the tree.\n    /// </summary>\n    /// <param name=\"key\">Key value to remove.</param>\n    /// <exception cref=\"KeyNotFoundException\">\n    ///     Thrown when the key is not found in the tree.\n    /// </exception>\n    public void Remove(TKey key)\n    {\n        if (root is null)\n        {\n            throw new KeyNotFoundException($\"\"\"Key \"{key}\" is not in the B-Tree.\"\"\");\n        }\n\n        Remove(root, key);\n\n        if (root.KeyCount == 0)\n        {\n            root = root.IsLeaf ? null : root.Children[0];\n        }\n\n        Count--;\n    }\n\n    /// <summary>\n    ///     Check if given key is in the tree.\n    /// </summary>\n    /// <param name=\"key\">Key value to search for.</param>\n    /// <returns>Whether or not the key is in the tree.</returns>\n    public bool Contains(TKey key)\n    {\n        return Search(root, key) is not null;\n    }\n\n    /// <summary>\n    ///     Get the minimum key in the tree.\n    /// </summary>\n    /// <returns>Minimum key in tree.</returns>\n    /// <exception cref=\"InvalidOperationException\">\n    ///     Thrown when the tree is empty.\n    /// </exception>\n    public TKey GetMin()\n    {\n        if (root is null)\n        {\n            throw new InvalidOperationException(\"B-Tree is empty.\");\n        }\n\n        return GetMin(root);\n    }\n\n    /// <summary>\n    ///     Get the maximum key in the tree.\n    /// </summary>\n    /// <returns>Maximum key in tree.</returns>\n    /// <exception cref=\"InvalidOperationException\">\n    ///     Thrown when the tree is empty.\n    /// </exception>\n    public TKey GetMax()\n    {\n        if (root is null)\n        {\n            throw new InvalidOperationException(\"B-Tree is empty.\");\n        }\n\n        return GetMax(root);\n    }\n\n    /// <summary>\n    ///     Get keys in order from smallest to largest as defined by the\n    ///     comparer.\n    /// </summary>\n    /// <returns>Keys in tree in order from smallest to largest.</returns>\n    public IEnumerable<TKey> GetKeysInOrder()\n    {\n        List<TKey> result = [];\n        InOrderTraversal(root);\n        return result;\n\n        void InOrderTraversal(BTreeNode<TKey>? node)\n        {\n            if (node is null)\n            {\n                return;\n            }\n\n            for (var i = 0; i < node.KeyCount; i++)\n            {\n                if (!node.IsLeaf)\n                {\n                    InOrderTraversal(node.Children[i]);\n                }\n\n                result.Add(node.Keys[i]);\n            }\n\n            if (!node.IsLeaf)\n            {\n                InOrderTraversal(node.Children[node.KeyCount]);\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Get keys in the pre-order order.\n    /// </summary>\n    /// <returns>Keys in pre-order order.</returns>\n    public IEnumerable<TKey> GetKeysPreOrder()\n    {\n        var result = new List<TKey>();\n        PreOrderTraversal(root);\n        return result;\n\n        void PreOrderTraversal(BTreeNode<TKey>? node)\n        {\n            if (node is null)\n            {\n                return;\n            }\n\n            for (var i = 0; i < node.KeyCount; i++)\n            {\n                result.Add(node.Keys[i]);\n            }\n\n            if (!node.IsLeaf)\n            {\n                for (var i = 0; i <= node.KeyCount; i++)\n                {\n                    PreOrderTraversal(node.Children[i]);\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Get keys in the post-order order.\n    /// </summary>\n    /// <returns>Keys in the post-order order.</returns>\n    public IEnumerable<TKey> GetKeysPostOrder()\n    {\n        var result = new List<TKey>();\n        PostOrderTraversal(root);\n        return result;\n\n        void PostOrderTraversal(BTreeNode<TKey>? node)\n        {\n            if (node is null)\n            {\n                return;\n            }\n\n            if (!node.IsLeaf)\n            {\n                for (var i = 0; i <= node.KeyCount; i++)\n                {\n                    PostOrderTraversal(node.Children[i]);\n                }\n            }\n\n            for (var i = 0; i < node.KeyCount; i++)\n            {\n                result.Add(node.Keys[i]);\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Search for a key in the subtree rooted at the given node.\n    /// </summary>\n    /// <param name=\"node\">Root of the subtree to search.</param>\n    /// <param name=\"key\">Key to search for.</param>\n    /// <returns>Node containing the key, or null if not found.</returns>\n    private BTreeNode<TKey>? Search(BTreeNode<TKey>? node, TKey key)\n    {\n        if (node is null)\n        {\n            return null;\n        }\n\n        var i = 0;\n        while (i < node.KeyCount && comparer.Compare(key, node.Keys[i]) > 0)\n        {\n            i++;\n        }\n\n        if (i < node.KeyCount && comparer.Compare(key, node.Keys[i]) == 0)\n        {\n            return node;\n        }\n\n        if (node.IsLeaf)\n        {\n            return null;\n        }\n\n        return Search(node.Children[i], key);\n    }\n\n    /// <summary>\n    ///     Insert a key into a non-full node.\n    /// </summary>\n    /// <param name=\"node\">Node to insert the key into.</param>\n    /// <param name=\"key\">Key to insert.</param>\n    /// <exception cref=\"ArgumentException\">\n    ///     Thrown when the key already exists in the tree.\n    /// </exception>\n    private void InsertNonFull(BTreeNode<TKey> node, TKey key)\n    {\n        if (node.IsLeaf)\n        {\n            InsertIntoLeaf(node, key);\n        }\n        else\n        {\n            InsertIntoNonLeaf(node, key);\n        }\n    }\n\n    /// <summary>\n    ///     Insert a key into a leaf node.\n    /// </summary>\n    /// <param name=\"node\">Leaf node to insert into.</param>\n    /// <param name=\"key\">Key to insert.</param>\n    private void InsertIntoLeaf(BTreeNode<TKey> node, TKey key)\n    {\n        var i = node.KeyCount - 1;\n\n        while (i >= 0 && comparer.Compare(key, node.Keys[i]) < 0)\n        {\n            node.Keys[i + 1] = node.Keys[i];\n            i--;\n        }\n\n        if (i >= 0 && comparer.Compare(key, node.Keys[i]) == 0)\n        {\n            throw new ArgumentException($\"\"\"Key \"{key}\" already exists in B-Tree.\"\"\");\n        }\n\n        node.Keys[i + 1] = key;\n        node.KeyCount++;\n    }\n\n    /// <summary>\n    ///     Insert a key into a non-leaf node.\n    /// </summary>\n    /// <param name=\"node\">Non-leaf node to insert into.</param>\n    /// <param name=\"key\">Key to insert.</param>\n    private void InsertIntoNonLeaf(BTreeNode<TKey> node, TKey key)\n    {\n        var i = FindInsertionIndex(node, key);\n\n        if (node.Children[i]!.IsFull())\n        {\n            SplitChild(node, i);\n\n            if (comparer.Compare(key, node.Keys[i]) > 0)\n            {\n                i++;\n            }\n        }\n\n        InsertNonFull(node.Children[i]!, key);\n    }\n\n    /// <summary>\n    ///     Find the index where a key should be inserted in a non-leaf node.\n    /// </summary>\n    /// <param name=\"node\">Node to search in.</param>\n    /// <param name=\"key\">Key to insert.</param>\n    /// <returns>Index where the key should be inserted.</returns>\n    private int FindInsertionIndex(BTreeNode<TKey> node, TKey key)\n    {\n        var i = node.KeyCount - 1;\n\n        while (i >= 0 && comparer.Compare(key, node.Keys[i]) < 0)\n        {\n            i--;\n        }\n\n        if (i >= 0 && comparer.Compare(key, node.Keys[i]) == 0)\n        {\n            throw new ArgumentException($\"\"\"Key \"{key}\" already exists in B-Tree.\"\"\");\n        }\n\n        return i + 1;\n    }\n\n    /// <summary>\n    ///     Split a full child of a node.\n    /// </summary>\n    /// <param name=\"parent\">Parent node.</param>\n    /// <param name=\"childIndex\">Index of the child to split.</param>\n    private void SplitChild(BTreeNode<TKey> parent, int childIndex)\n    {\n        var fullChild = parent.Children[childIndex]!;\n        var newChild = new BTreeNode<TKey>(MinimumDegree, fullChild.IsLeaf);\n        var midIndex = MinimumDegree - 1;\n\n        for (var j = 0; j < MinimumDegree - 1; j++)\n        {\n            newChild.Keys[j] = fullChild.Keys[j + MinimumDegree];\n            newChild.KeyCount++;\n        }\n\n        if (!fullChild.IsLeaf)\n        {\n            for (var j = 0; j < MinimumDegree; j++)\n            {\n                newChild.Children[j] = fullChild.Children[j + MinimumDegree];\n            }\n        }\n\n        fullChild.KeyCount = MinimumDegree - 1;\n\n        for (var j = parent.KeyCount; j > childIndex; j--)\n        {\n            parent.Children[j + 1] = parent.Children[j];\n        }\n\n        parent.Children[childIndex + 1] = newChild;\n\n        for (var j = parent.KeyCount - 1; j >= childIndex; j--)\n        {\n            parent.Keys[j + 1] = parent.Keys[j];\n        }\n\n        parent.Keys[childIndex] = fullChild.Keys[midIndex];\n        parent.KeyCount++;\n    }\n\n    /// <summary>\n    ///     Remove a key from the subtree rooted at the given node.\n    /// </summary>\n    /// <param name=\"node\">Root of the subtree.</param>\n    /// <param name=\"key\">Key to remove.</param>\n    /// <exception cref=\"KeyNotFoundException\">\n    ///     Thrown when the key is not found in the subtree.\n    /// </exception>\n    private void Remove(BTreeNode<TKey> node, TKey key)\n    {\n        var idx = FindKey(node, key);\n\n        if (idx < node.KeyCount && comparer.Compare(node.Keys[idx], key) == 0)\n        {\n            if (node.IsLeaf)\n            {\n                RemoveFromLeaf(node, idx);\n            }\n            else\n            {\n                RemoveFromNonLeaf(node, idx);\n            }\n        }\n        else\n        {\n            if (node.IsLeaf)\n            {\n                throw new KeyNotFoundException($\"\"\"Key \"{key}\" is not in the B-Tree.\"\"\");\n            }\n\n            var isInSubtree = idx == node.KeyCount;\n\n            if (node.Children[idx]!.KeyCount < MinimumDegree)\n            {\n                Fill(node, idx);\n            }\n\n            if (isInSubtree && idx > node.KeyCount)\n            {\n                Remove(node.Children[idx - 1]!, key);\n            }\n            else\n            {\n                Remove(node.Children[idx]!, key);\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Find the index of the first key greater than or equal to the given key.\n    /// </summary>\n    /// <param name=\"node\">Node to search in.</param>\n    /// <param name=\"key\">Key to find.</param>\n    /// <returns>Index of the first key >= key.</returns>\n    private int FindKey(BTreeNode<TKey> node, TKey key)\n    {\n        var idx = 0;\n        while (idx < node.KeyCount && comparer.Compare(node.Keys[idx], key) < 0)\n        {\n            idx++;\n        }\n\n        return idx;\n    }\n\n    /// <summary>\n    ///     Remove a key from a leaf node.\n    /// </summary>\n    /// <param name=\"node\">Leaf node to remove from.</param>\n    /// <param name=\"idx\">Index of the key to remove.</param>\n    private void RemoveFromLeaf(BTreeNode<TKey> node, int idx)\n    {\n        node.RemoveKey(idx);\n    }\n\n    /// <summary>\n    ///     Remove a key from a non-leaf node.\n    /// </summary>\n    /// <param name=\"node\">Non-leaf node to remove from.</param>\n    /// <param name=\"idx\">Index of the key to remove.</param>\n    private void RemoveFromNonLeaf(BTreeNode<TKey> node, int idx)\n    {\n        var key = node.Keys[idx];\n\n        if (node.Children[idx]!.KeyCount >= MinimumDegree)\n        {\n            var predecessor = GetPredecessor(node, idx);\n            node.Keys[idx] = predecessor;\n            Remove(node.Children[idx]!, predecessor);\n        }\n        else if (node.Children[idx + 1]!.KeyCount >= MinimumDegree)\n        {\n            var successor = GetSuccessor(node, idx);\n            node.Keys[idx] = successor;\n            Remove(node.Children[idx + 1]!, successor);\n        }\n        else\n        {\n            Merge(node, idx);\n            Remove(node.Children[idx]!, key);\n        }\n    }\n\n    /// <summary>\n    ///     Get the predecessor key of the key at the given index.\n    /// </summary>\n    /// <param name=\"node\">Node containing the key.</param>\n    /// <param name=\"idx\">Index of the key.</param>\n    /// <returns>Predecessor key.</returns>\n    private TKey GetPredecessor(BTreeNode<TKey> node, int idx)\n    {\n        var current = node.Children[idx]!;\n        while (!current.IsLeaf)\n        {\n            current = current.Children[current.KeyCount]!;\n        }\n\n        return current.Keys[current.KeyCount - 1];\n    }\n\n    /// <summary>\n    ///     Get the successor key of the key at the given index.\n    /// </summary>\n    /// <param name=\"node\">Node containing the key.</param>\n    /// <param name=\"idx\">Index of the key.</param>\n    /// <returns>Successor key.</returns>\n    private TKey GetSuccessor(BTreeNode<TKey> node, int idx)\n    {\n        var current = node.Children[idx + 1]!;\n        while (!current.IsLeaf)\n        {\n            current = current.Children[0]!;\n        }\n\n        return current.Keys[0];\n    }\n\n    /// <summary>\n    ///     Fill a child node that has fewer than minimum degree - 1 keys.\n    /// </summary>\n    /// <param name=\"node\">Parent node.</param>\n    /// <param name=\"idx\">Index of the child to fill.</param>\n    private void Fill(BTreeNode<TKey> node, int idx)\n    {\n        if (idx != 0 && node.Children[idx - 1]!.KeyCount >= MinimumDegree)\n        {\n            BorrowFromPrevious(node, idx);\n        }\n        else if (idx != node.KeyCount && node.Children[idx + 1]!.KeyCount >= MinimumDegree)\n        {\n            BorrowFromNext(node, idx);\n        }\n        else\n        {\n            Merge(node, idx != node.KeyCount ? idx : idx - 1);\n        }\n    }\n\n    /// <summary>\n    ///     Borrow a key from the previous sibling.\n    /// </summary>\n    /// <param name=\"node\">Parent node.</param>\n    /// <param name=\"childIdx\">Index of the child that needs a key.</param>\n    private void BorrowFromPrevious(BTreeNode<TKey> node, int childIdx)\n    {\n        var child = node.Children[childIdx]!;\n        var sibling = node.Children[childIdx - 1]!;\n\n        for (var i = child.KeyCount - 1; i >= 0; i--)\n        {\n            child.Keys[i + 1] = child.Keys[i];\n        }\n\n        if (!child.IsLeaf)\n        {\n            for (var i = child.KeyCount; i >= 0; i--)\n            {\n                child.Children[i + 1] = child.Children[i];\n            }\n        }\n\n        child.Keys[0] = node.Keys[childIdx - 1];\n\n        if (!child.IsLeaf)\n        {\n            child.Children[0] = sibling.Children[sibling.KeyCount];\n        }\n\n        node.Keys[childIdx - 1] = sibling.Keys[sibling.KeyCount - 1];\n\n        child.KeyCount++;\n        sibling.KeyCount--;\n    }\n\n    /// <summary>\n    ///     Borrow a key from the next sibling.\n    /// </summary>\n    /// <param name=\"node\">Parent node.</param>\n    /// <param name=\"childIdx\">Index of the child that needs a key.</param>\n    private void BorrowFromNext(BTreeNode<TKey> node, int childIdx)\n    {\n        var child = node.Children[childIdx]!;\n        var sibling = node.Children[childIdx + 1]!;\n\n        child.Keys[child.KeyCount] = node.Keys[childIdx];\n\n        if (!child.IsLeaf)\n        {\n            child.Children[child.KeyCount + 1] = sibling.Children[0];\n        }\n\n        node.Keys[childIdx] = sibling.Keys[0];\n\n        for (var i = 1; i < sibling.KeyCount; i++)\n        {\n            sibling.Keys[i - 1] = sibling.Keys[i];\n        }\n\n        if (!sibling.IsLeaf)\n        {\n            for (var i = 1; i <= sibling.KeyCount; i++)\n            {\n                sibling.Children[i - 1] = sibling.Children[i];\n            }\n        }\n\n        child.KeyCount++;\n        sibling.KeyCount--;\n    }\n\n    /// <summary>\n    ///     Merge a child with its sibling.\n    /// </summary>\n    /// <param name=\"node\">Parent node.</param>\n    /// <param name=\"idx\">Index of the child to merge.</param>\n    private void Merge(BTreeNode<TKey> node, int idx)\n    {\n        var child = node.Children[idx]!;\n        var sibling = node.Children[idx + 1]!;\n\n        child.Keys[MinimumDegree - 1] = node.Keys[idx];\n\n        for (var i = 0; i < sibling.KeyCount; i++)\n        {\n            child.Keys[i + MinimumDegree] = sibling.Keys[i];\n        }\n\n        if (!child.IsLeaf)\n        {\n            for (var i = 0; i <= sibling.KeyCount; i++)\n            {\n                child.Children[i + MinimumDegree] = sibling.Children[i];\n            }\n        }\n\n        for (var i = idx + 1; i < node.KeyCount; i++)\n        {\n            node.Keys[i - 1] = node.Keys[i];\n        }\n\n        for (var i = idx + 2; i <= node.KeyCount; i++)\n        {\n            node.Children[i - 1] = node.Children[i];\n        }\n\n        child.KeyCount += sibling.KeyCount + 1;\n        node.KeyCount--;\n    }\n\n    /// <summary>\n    ///     Get the minimum key in the subtree rooted at the given node.\n    /// </summary>\n    /// <param name=\"node\">Root of the subtree.</param>\n    /// <returns>Minimum key in the subtree.</returns>\n    private TKey GetMin(BTreeNode<TKey> node)\n    {\n        while (!node.IsLeaf)\n        {\n            node = node.Children[0]!;\n        }\n\n        return node.Keys[0];\n    }\n\n    /// <summary>\n    ///     Get the maximum key in the subtree rooted at the given node.\n    /// </summary>\n    /// <param name=\"node\">Root of the subtree.</param>\n    /// <returns>Maximum key in the subtree.</returns>\n    private TKey GetMax(BTreeNode<TKey> node)\n    {\n        while (!node.IsLeaf)\n        {\n            node = node.Children[node.KeyCount]!;\n        }\n\n        return node.Keys[node.KeyCount - 1];\n    }\n}\n"
  },
  {
    "path": "DataStructures/BTree/BTreeNode.cs",
    "content": "namespace DataStructures.BTree;\n\n/// <summary>\n///     Generic class to represent nodes in a <see cref=\"BTree{TKey}\"/>\n///     instance.\n/// </summary>\n/// <typeparam name=\"TKey\">The type of key for the node.</typeparam>\n/// <remarks>\n///     Initializes a new instance of the\n///     <see cref=\"BTreeNode{TKey}\"/> class.\n/// </remarks>\n/// <param name=\"minDegree\">Minimum degree of the B-Tree.</param>\n/// <param name=\"isLeaf\">Whether this node is a leaf node.</param>\ninternal class BTreeNode<TKey>(int minDegree, bool isLeaf)\n{\n    /// <summary>\n    ///     Gets the minimum degree (t) of the B-Tree.\n    ///     A node can contain at most 2t-1 keys and at least t-1 keys (except root).\n    /// </summary>\n    public int MinDegree { get; } = minDegree;\n\n    /// <summary>\n    ///     Gets or sets a value indicating whether this node is a leaf node.\n    /// </summary>\n    public bool IsLeaf { get; set; } = isLeaf;\n\n    /// <summary>\n    ///     Gets or sets the current number of keys stored in this node.\n    /// </summary>\n    public int KeyCount { get; internal set; }\n\n    /// <summary>\n    ///     Gets the array of keys stored in this node.\n    ///     Maximum size is 2*MinDegree - 1.\n    /// </summary>\n    public TKey[] Keys { get; } = new TKey[2 * minDegree - 1];\n\n    /// <summary>\n    ///     Gets the array of child pointers.\n    ///     Maximum size is 2*MinDegree.\n    /// </summary>\n    public BTreeNode<TKey>?[] Children { get; } = new BTreeNode<TKey>[2 * minDegree];\n\n    /// <summary>\n    ///     Inserts a key at the specified position in the keys array.\n    /// </summary>\n    /// <param name=\"index\">Position to insert the key.</param>\n    /// <param name=\"key\">Key to insert.</param>\n    public void InsertKey(int index, TKey key)\n    {\n        Keys[index] = key;\n        KeyCount++;\n    }\n\n    /// <summary>\n    ///     Removes the key at the specified position in the keys array.\n    /// </summary>\n    /// <param name=\"index\">Position of the key to remove.</param>\n    public void RemoveKey(int index)\n    {\n        for (var i = index; i < KeyCount - 1; i++)\n        {\n            Keys[i] = Keys[i + 1];\n        }\n\n        Keys[KeyCount - 1] = default!;\n        KeyCount--;\n    }\n\n    /// <summary>\n    ///     Inserts a child pointer at the specified position.\n    /// </summary>\n    /// <param name=\"index\">Position to insert the child.</param>\n    /// <param name=\"child\">Child node to insert.</param>\n    public void InsertChild(int index, BTreeNode<TKey> child)\n    {\n        Children[index] = child;\n    }\n\n    /// <summary>\n    ///     Checks if the node is full (contains maximum number of keys).\n    /// </summary>\n    /// <returns>True if the node is full, false otherwise.</returns>\n    public bool IsFull() => KeyCount == 2 * MinDegree - 1;\n}\n"
  },
  {
    "path": "DataStructures/Bag/Bag.cs",
    "content": "using System.Collections;\nusing System.Collections.Generic;\n\nnamespace DataStructures.Bag;\n\n/// <summary>\n/// Implementation of a Bag (or multiset) data structure using a basic linked list.\n/// </summary>\n/// <remarks>\n/// A bag (or multiset, or mset) is a modification of the concept of a set that, unlike a set, allows for multiple instances for each of its elements.\n/// The number of instances given for each element is called the multiplicity of that element in the multiset.\n/// As a consequence, an infinite number of multisets exist that contain only elements a and b, but vary in the multiplicities of their elements.\n/// See https://en.wikipedia.org/wiki/Multiset for more information.\n/// </remarks>\n/// <typeparam name=\"T\">Generic Type.</typeparam>\npublic class Bag<T> : IEnumerable<T> where T : notnull\n{\n    private BagNode<T>? head;\n    private int totalCount;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"Bag{T}\" /> class.\n    /// </summary>\n    public Bag()\n    {\n        head = null;\n        totalCount = 0;\n    }\n\n    /// <summary>\n    /// Adds an item to the bag. If the item already exists, increases its multiplicity.\n    /// </summary>\n    public void Add(T item)\n    {\n        // If the bag is empty, create the first node\n        if (head == null)\n        {\n            head = new BagNode<T>(item);\n            totalCount = 1;\n            return;\n        }\n\n        // Check if item already exists\n        var current = head;\n        BagNode<T>? previous = null;\n\n        while (current != null)\n        {\n            if (EqualityComparer<T>.Default.Equals(current.Item, item))\n            {\n                current.Multiplicity++;\n                totalCount++;\n                return;\n            }\n\n            previous = current;\n            current = current.Next;\n        }\n\n        previous!.Next = new BagNode<T>(item);\n        totalCount++;\n    }\n\n    /// <summary>\n    /// Clears the bag.\n    /// </summary>\n    public void Clear()\n    {\n        head = null;\n        totalCount = 0;\n    }\n\n    /// <summary>\n    /// Gets the number of items in the bag.\n    /// </summary>\n    public int Count => totalCount;\n\n    /// <summary>\n    /// Returns a boolean indicating whether the bag is empty.\n    /// </summary>\n    public bool IsEmpty() => head == null;\n\n    /// <summary>\n    /// Returns an enumerator that iterates through the bag.\n    /// </summary>\n    public IEnumerator<T> GetEnumerator()\n    {\n        var current = head;\n\n        while (current != null)\n        {\n            // Yield the item as many times as its multiplicity, pretending they are separate items\n            for (var i = 0; i < current.Multiplicity; i++)\n            {\n                yield return current.Item;\n            }\n\n            current = current.Next;\n        }\n    }\n\n    /// <summary>\n    /// Returns an enumerator that iterates through the bag.\n    /// </summary>\n    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n}\n"
  },
  {
    "path": "DataStructures/Bag/BagNode.cs",
    "content": "namespace DataStructures.Bag;\n\n/// <summary>\n/// Generic node class for Bag.\n/// </summary>\n/// <typeparam name=\"T\">A type for node.</typeparam>\npublic class BagNode<T>(T item)\n{\n    public T Item { get; } = item;\n\n    public int Multiplicity { get; set; } = 1;\n\n    public BagNode<T>? Next { get; set; }\n}\n"
  },
  {
    "path": "DataStructures/BinarySearchTree/BinarySearchTree.cs",
    "content": "namespace DataStructures.BinarySearchTree;\n\n/// <summary>\n///     An ordered tree with efficient insertion, removal, and lookup.\n/// </summary>\n/// <remarks>\n///     A Binary Search Tree (BST) is a tree that satisfies the following properties:\n///     <list type=\"bullet\">\n///         <item>All nodes in the tree contain two children, usually called Left and Right.</item>\n///         <item>All nodes in the Left subtree contain keys that are less than the node's key.</item>\n///         <item>All nodes in the Right subtree contain keys that are greater than the node's key.</item>\n///     </list>\n///     A BST will have an average complexity of O(log n) for insertion, removal, and lookup operations.\n/// </remarks>\n/// <typeparam name=\"TKey\">Type of key for the BST. Keys must implement IComparable.</typeparam>\npublic class BinarySearchTree<TKey>\n{\n    /// <summary>\n    ///     Comparer to use when comparing node elements/keys.\n    /// </summary>\n    private readonly Comparer<TKey> comparer;\n\n    /// <summary>\n    ///     Gets the root of the BST.\n    /// </summary>\n    public BinarySearchTreeNode<TKey>? Root { get; private set; }\n\n    public BinarySearchTree() => (Root, Count, comparer) = (null, 0, Comparer<TKey>.Default);\n\n    public BinarySearchTree(Comparer<TKey> customComparer) => (Root, Count, comparer) = (null, 0, customComparer);\n\n    /// <summary>\n    ///     Gets the number nodes currently in the BST.\n    /// </summary>\n    public int Count { get; private set; }\n\n    /// <summary>\n    ///     Insert a key into the BST.\n    /// </summary>\n    /// <param name=\"key\">The key to insert.</param>\n    /// <exception cref=\"ArgumentException\">\n    ///     Thrown if key is already in BST.\n    /// </exception>\n    public void Add(TKey key)\n    {\n        if (Root is null)\n        {\n            Root = new BinarySearchTreeNode<TKey>(key);\n        }\n        else\n        {\n            Add(Root, key);\n        }\n\n        Count++;\n    }\n\n    /// <summary>\n    ///     Insert multiple keys into the BST.\n    ///     Keys are inserted in the order they appear in the sequence.\n    /// </summary>\n    /// <param name=\"keys\">Sequence of keys to insert.</param>\n    public void AddRange(IEnumerable<TKey> keys)\n    {\n        foreach (var key in keys)\n        {\n            Add(key);\n        }\n    }\n\n    /// <summary>\n    ///     Find a node with the specified key.\n    /// </summary>\n    /// <param name=\"key\">The key to search for.</param>\n    /// <returns>The node with the specified key if it exists, otherwise a default value is returned.</returns>\n    public BinarySearchTreeNode<TKey>? Search(TKey key) => Search(Root, key);\n\n    /// <summary>\n    ///     Checks if the specified key is in the BST.\n    /// </summary>\n    /// <param name=\"key\">The key to search for.</param>\n    /// <returns>true if the key is in the BST, false otherwise.</returns>\n    public bool Contains(TKey key) => Search(Root, key) is not null;\n\n    /// <summary>\n    ///     Removes a node with a key that matches <paramref name=\"key\" />.\n    /// </summary>\n    /// <param name=\"key\">The key to search for.</param>\n    /// <returns>true if the removal was successful, false otherwise.</returns>\n    public bool Remove(TKey key)\n    {\n        if (Root is null)\n        {\n            return false;\n        }\n\n        var result = Remove(Root, Root, key);\n        if (result)\n        {\n            Count--;\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Returns a node with the smallest key.\n    /// </summary>\n    /// <returns>The node if possible, a default value otherwise.</returns>\n    public BinarySearchTreeNode<TKey>? GetMin()\n    {\n        if (Root is null)\n        {\n            return default;\n        }\n\n        return GetMin(Root);\n    }\n\n    /// <summary>\n    ///     Returns a node with the largest key.\n    /// </summary>\n    /// <returns>The node if possible, a default value otherwise.</returns>\n    public BinarySearchTreeNode<TKey>? GetMax()\n    {\n        if (Root is null)\n        {\n            return default;\n        }\n\n        return GetMax(Root);\n    }\n\n    /// <summary>\n    ///     Returns all the keys in the BST, sorted In-Order.\n    /// </summary>\n    /// <returns>A list of keys in the BST.</returns>\n    public ICollection<TKey> GetKeysInOrder() => GetKeysInOrder(Root);\n\n    /// <summary>\n    ///     Returns all the keys in the BST, sorted Pre-Order.\n    /// </summary>\n    /// <returns>A list of keys in the BST.</returns>\n    public ICollection<TKey> GetKeysPreOrder() => GetKeysPreOrder(Root);\n\n    /// <summary>\n    ///     Returns all the keys in the BST, sorted Post-Order.\n    /// </summary>\n    /// <returns>A list of keys in the BST.</returns>\n    public ICollection<TKey> GetKeysPostOrder() => GetKeysPostOrder(Root);\n\n    /// <summary>\n    ///     Recursive method to add a key to the BST.\n    /// </summary>\n    /// <param name=\"node\">Node to search from.</param>\n    /// <param name=\"key\">Key to add.</param>\n    /// <exception cref=\"ArgumentException\">\n    ///     Thrown if key is already in the BST.\n    /// </exception>\n    private void Add(BinarySearchTreeNode<TKey> node, TKey key)\n    {\n        var compareResult = comparer.Compare(node.Key, key);\n        if (compareResult > 0)\n        {\n            if (node.Left is not null)\n            {\n                Add(node.Left, key);\n            }\n            else\n            {\n                var newNode = new BinarySearchTreeNode<TKey>(key);\n                node.Left = newNode;\n            }\n        }\n        else if (compareResult < 0)\n        {\n            if (node.Right is not null)\n            {\n                Add(node.Right, key);\n            }\n            else\n            {\n                var newNode = new BinarySearchTreeNode<TKey>(key);\n                node.Right = newNode;\n            }\n        }\n\n        // Key is already in tree.\n        else\n        {\n            throw new ArgumentException($\"\"\"Key \"{key}\" already exists in tree!\"\"\");\n        }\n    }\n\n    /// <summary>\n    ///     Removes a node with the specified key from the BST.\n    /// </summary>\n    /// <param name=\"parent\">The parent node of <paramref name=\"node\" />.</param>\n    /// <param name=\"node\">The node to check/search from.</param>\n    /// <param name=\"key\">The key to remove.</param>\n    /// <returns>true if the operation was successful, false otherwise.</returns>\n    /// <remarks>\n    ///     Removing a node from the BST can be split into three cases:\n    ///     <br></br>\n    ///     0. The node to be removed has no children. In this case, the node can just be removed from the tree.\n    ///     <br></br>\n    ///     1. The node to be removed has one child. In this case, the node's child is moved to the node's parent,\n    ///     then the node is removed from the tree.\n    ///     <br></br>\n    ///     2. The node to be removed has two children. In this case, we must find a suitable node among the children\n    ///     subtrees to replace the node. This can be done with either the in-order predecessor or the in-order successor.\n    ///     The in-order predecessor is the largest node in Left subtree, or the largest node that is still smaller then the\n    ///     current node. The in-order successor is the smallest node in the Right subtree, or the smallest node that is\n    ///     still larger than the current node. Either way, once this suitable node is found, remove it from the tree (it\n    ///     should be either a case 1 or 2 node) and replace the node to be removed with this suitable node.\n    ///     <br></br>\n    ///     More information: https://en.wikipedia.org/wiki/Binary_search_tree#Deletion .\n    /// </remarks>\n    private bool Remove(BinarySearchTreeNode<TKey>? parent, BinarySearchTreeNode<TKey>? node, TKey key)\n    {\n        if (node is null || parent is null)\n        {\n            return false;\n        }\n\n        var compareResult = comparer.Compare(node.Key, key);\n\n        if (compareResult > 0)\n        {\n            return Remove(node, node.Left, key);\n        }\n\n        if (compareResult < 0)\n        {\n            return Remove(node, node.Right, key);\n        }\n\n        BinarySearchTreeNode<TKey>? replacementNode;\n\n        // Case 0: Node has no children.\n        // Case 1: Node has one child.\n        if (node.Left is null || node.Right is null)\n        {\n            replacementNode = node.Left ?? node.Right;\n        }\n\n        // Case 2: Node has two children. (This implementation uses the in-order predecessor to replace node.)\n        else\n        {\n            var predecessorNode = GetMax(node.Left);\n            Remove(Root, Root, predecessorNode.Key);\n            replacementNode = new BinarySearchTreeNode<TKey>(predecessorNode.Key)\n            {\n                Left = node.Left,\n                Right = node.Right,\n            };\n        }\n\n        // Replace the relevant node with a replacement found in the previous stages.\n        // Special case for replacing the root node.\n        if (node == Root)\n        {\n            Root = replacementNode;\n        }\n        else if (parent.Left == node)\n        {\n            parent.Left = replacementNode;\n        }\n        else\n        {\n            parent.Right = replacementNode;\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    ///     Recursive method to get node with largest key.\n    /// </summary>\n    /// <param name=\"node\">Node to search from.</param>\n    /// <returns>Node with largest value.</returns>\n    private BinarySearchTreeNode<TKey> GetMax(BinarySearchTreeNode<TKey> node)\n    {\n        if (node.Right is null)\n        {\n            return node;\n        }\n\n        return GetMax(node.Right);\n    }\n\n    /// <summary>\n    ///     Recursive method to get node with smallest key.\n    /// </summary>\n    /// <param name=\"node\">Node to search from.</param>\n    /// <returns>Node with smallest value.</returns>\n    private BinarySearchTreeNode<TKey> GetMin(BinarySearchTreeNode<TKey> node)\n    {\n        if (node.Left is null)\n        {\n            return node;\n        }\n\n        return GetMin(node.Left);\n    }\n\n    /// <summary>\n    ///     Recursive method to get a list with the keys sorted in in-order order.\n    /// </summary>\n    /// <param name=\"node\">Node to traverse from.</param>\n    /// <returns>List of keys in in-order order.</returns>\n    private IList<TKey> GetKeysInOrder(BinarySearchTreeNode<TKey>? node)\n    {\n        if (node is null)\n        {\n            return [];\n        }\n\n        // Use mutable list approach instead of spread operator for better performance\n        var result = new List<TKey>();\n        result.AddRange(GetKeysInOrder(node.Left));\n        result.Add(node.Key);\n        result.AddRange(GetKeysInOrder(node.Right));\n        return result;\n    }\n\n    /// <summary>\n    ///     Recursive method to get a list with the keys sorted in pre-order order.\n    /// </summary>\n    /// <param name=\"node\">Node to traverse from.</param>\n    /// <returns>List of keys in pre-order order.</returns>\n    private IList<TKey> GetKeysPreOrder(BinarySearchTreeNode<TKey>? node)\n    {\n        if (node is null)\n        {\n            return [];\n        }\n\n        // Use mutable list approach instead of spread operator for better performance\n        var result = new List<TKey>\n        {\n            node.Key,\n        };\n        result.AddRange(GetKeysPreOrder(node.Left));\n        result.AddRange(GetKeysPreOrder(node.Right));\n        return result;\n    }\n\n    /// <summary>\n    ///     Recursive method to get a list with the keys sorted in post-order order.\n    /// </summary>\n    /// <param name=\"node\">Node to traverse from.</param>\n    /// <returns>List of keys in post-order order.</returns>\n    private IList<TKey> GetKeysPostOrder(BinarySearchTreeNode<TKey>? node)\n    {\n        if (node is null)\n        {\n            return [];\n        }\n\n        // Use mutable list approach instead of spread operator for better performance\n        var result = new List<TKey>();\n        result.AddRange(GetKeysPostOrder(node.Left));\n        result.AddRange(GetKeysPostOrder(node.Right));\n        result.Add(node.Key);\n        return result;\n    }\n\n    /// <summary>\n    ///     Recursive method to find a node with a matching key.\n    /// </summary>\n    /// <param name=\"node\">Node to search from.</param>\n    /// <param name=\"key\">Key to find.</param>\n    /// <returns>The node with the specified if it exists, a default value otherwise.</returns>\n    private BinarySearchTreeNode<TKey>? Search(BinarySearchTreeNode<TKey>? node, TKey key)\n    {\n        if (node is null)\n        {\n            return default;\n        }\n\n        var compareResult = comparer.Compare(node.Key, key);\n        if (compareResult > 0)\n        {\n            return Search(node.Left, key);\n        }\n\n        if (compareResult < 0)\n        {\n            return Search(node.Right, key);\n        }\n\n        return node;\n    }\n}\n"
  },
  {
    "path": "DataStructures/BinarySearchTree/BinarySearchTreeNode.cs",
    "content": "namespace DataStructures.BinarySearchTree;\n\n/// <summary>\n///     Generic node class for BinarySearchTree.\n///     Keys for each node are immutable.\n/// </summary>\n/// <typeparam name=\"TKey\">Type of key for the node. Keys must implement IComparable.</typeparam>\n/// <remarks>\n///     Initializes a new instance of the <see cref=\"BinarySearchTreeNode{TKey}\" /> class.\n/// </remarks>\n/// <param name=\"key\">The key of this node.</param>\npublic class BinarySearchTreeNode<TKey>(TKey key)\n{\n    /// <summary>\n    ///     Gets the key for this node.\n    /// </summary>\n    public TKey Key { get; } = key;\n\n    /// <summary>\n    ///     Gets or sets the reference to a child node that precedes/comes before this node.\n    /// </summary>\n    public BinarySearchTreeNode<TKey>? Left { get; set; }\n\n    /// <summary>\n    ///     Gets or sets the reference to a child node that follows/comes after this node.\n    /// </summary>\n    public BinarySearchTreeNode<TKey>? Right { get; set; }\n}\n"
  },
  {
    "path": "DataStructures/BitArray.cs",
    "content": "// Original Author: Christian Bender\n// Class: BitArray\n//\n// implements IComparable, ICloneable, IEnumerator, IEnumerable\n//\n// This class implements a bit-array and provides some\n// useful functions/operations to deal with this type of\n// data structure. You see a overview about the functionality, below.\n//\n//\n// Overview\n//\n// Constructor (N : int)\n// The constructor receives a length (N) of the to create bit-field.\n//\n// Constructor (sequence : string)\n// setups the array with the input sequence.\n// assumes: the sequence may only be allowed contains onese or zeros.\n//\n// Constructor (bits : bool[] )\n// setups the bit-field with the input array.\n//\n// Compile(sequence : string)\n// compiles a string sequence of 0's and 1's in the inner structure.\n// assumes: the sequence may only be allowed contains onese or zeros.\n//\n// Compile (number : int)\n// compiles a positive integer number in the inner data structure.\n//\n// Compile (number : long)\n// compiles a positive long integer number in the inner data structure.\n//\n// ToString ()\n// returns a string representation of the inner structure.\n// The returned string is a sequence of 0's and 1's.\n//\n// Length : int\n// Is a property that returns the length of the bit-field.\n//\n// Indexer : bool\n// indexer for selecting the individual bits of the bit array.\n//\n// NumberOfOneBits() : int\n// returns the number of One-bits.\n//\n// NumberOfZeroBits() : int\n// returns the number of Zero-Bits.\n//\n// EvenParity() : bool\n// returns true if parity is even, otherwise false.\n//\n// OddParity() : bool\n// returns true if parity is odd, otherwise false.\n//\n// ToInt64() : long\n// returns a long integer representation of the bit-array.\n// assumes: the bit-array length must been smaller or equal to 64 bit.\n//\n// ToInt32() : int\n// returns a integer representation of the bit-array.\n// assumes: the bit-array length must been smaller or equal to 32 bit.\n//\n// ResetField() : void\n// sets all bits on false.\n//\n// SetAll(flag : bool) : void\n// sets all bits on the value of the flag.\n//\n// GetHashCode() : int\n// returns hash-code (ToInt32())\n//\n// Equals (other : Object) : bool\n// returns true if there inputs are equal otherwise false.\n// assumes: the input bit-arrays must have same length.\n//\n// CompareTo (other : Object) : int  (interface IComparable)\n// output:  0 - if the bit-arrays a equal.\n// -1 - if this bit-array is smaller.\n// 1 - if this bit-array is greater.\n// assumes: bit-array lentgh must been smaller or equal to 64 bit\n//\n// Clone () : object\n// returns a copy of this bit-array\n//\n// Current : object\n// returns the current selected bit.\n//\n// MoveNext() : bool\n// purpose: increases the position of the enumerator\n// returns true if 'position' successful increased otherwise false.\n//\n// Reset() : void\n// resets the position of the enumerator.\n//\n// GetEnumerator() : IEnumerator\n// returns a enumerator for this BitArray-object.\n//\n// Operations:\n//\n// &amp; bitwise AND\n// | bitwise OR\n// ~ bitwise NOT\n// >> bitwise shift right\n// >> bitwise shift left\n// ^ bitwise XOR\n//\n// Each operation (above) returns a new BitArray-object.\n//\n// == equal operator. : bool\n// returns true if there inputs are equal otherwise false.\n// assumes: the input bit-arrays must have same length.\n//\n// != not-equal operator : bool\n// returns true if there inputs aren't equal otherwise false.\n// assumes: the input bit-arrays must have same length.\n\nusing System.Collections;\n\nnamespace DataStructures;\n\n/// <summary>\n///     This class implements a bit-array and provides some\n///     useful functions/operations to deal with this type of\n///     data structure.\n/// </summary>\npublic sealed class BitArray : ICloneable, IEnumerator<bool>, IEnumerable<bool>\n{\n    private readonly bool[] field; // the actual bit-field\n    private int position = -1; // position for enumerator\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"BitArray\" /> class.\n    ///     setups the array with false-values.\n    /// </summary>\n    /// <param name=\"n\">length of the array.</param>\n    public BitArray(int n)\n    {\n        field = n <= 0 ? new bool[0] : new bool[n];\n    }\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"BitArray\" /> class.\n    ///     Setups the array with the input sequence.\n    ///     purpose: Setups the array with the input sequence.\n    ///     assumes: sequence must been greater or equal to 1.\n    ///     the sequence may only contain ones or zeros.\n    /// </summary>\n    /// <param name=\"sequence\">A string sequence of 0's and 1's.</param>\n    public BitArray(string sequence)\n    {\n        // precondition I\n        if (sequence.Length <= 0)\n        {\n            throw new ArgumentException(\"Sequence must been greater than or equal to 1\");\n        }\n\n        // precondition II\n        ThrowIfSequenceIsInvalid(sequence);\n\n        field = new bool[sequence.Length];\n        Compile(sequence);\n    }\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"BitArray\" /> class.\n    ///     Setups the bit-array with the input array.\n    /// </summary>\n    /// <param name=\"bits\">A boolean array of bits.</param>\n    public BitArray(bool[] bits) => field = bits;\n\n    /// <summary>\n    ///     Gets the length of the current bit array.\n    /// </summary>\n    private int Length => field.Length;\n\n    /// <summary>\n    ///     Gets element given an offset.\n    /// </summary>\n    /// <param name=\"offset\">Position.</param>\n    /// <returns>Element on array.</returns>\n    public bool this[int offset]\n    {\n        get => field[offset];\n        private set => field[offset] = value;\n    }\n\n    /// <summary>\n    ///     Returns a copy of the current bit-array.\n    /// </summary>\n    /// <returns>Bit-array clone.</returns>\n    public object Clone()\n    {\n        var theClone = new BitArray(Length);\n\n        for (var i = 0; i < Length; i++)\n        {\n            theClone[i] = field[i];\n        }\n\n        return theClone;\n    }\n\n    /// <summary>\n    ///     Gets a enumerator for this BitArray-Object.\n    /// </summary>\n    /// <returns>Returns a enumerator for this BitArray-Object.</returns>\n    public IEnumerator<bool> GetEnumerator() => this;\n\n    /// <summary>\n    ///     Gets a enumerator for this BitArray-Object.\n    /// </summary>\n    /// <returns>Returns a enumerator for this BitArray-Object.</returns>\n    IEnumerator IEnumerable.GetEnumerator() => this;\n\n    /// <summary>\n    ///     Gets a value indicating whether the current bit of the array is set.\n    /// </summary>\n    public bool Current => field[position];\n\n    /// <summary>\n    ///     Gets a value indicating whether the current bit of the array is set.\n    /// </summary>\n    object IEnumerator.Current => field[position];\n\n    /// <summary>\n    ///     MoveNext (for interface IEnumerator).\n    /// </summary>\n    /// <returns>Returns True if 'position' successful increased; False otherwise.</returns>\n    public bool MoveNext()\n    {\n        if (position + 1 >= field.Length)\n        {\n            return false;\n        }\n\n        position++;\n        return true;\n    }\n\n    /// <summary>\n    ///     Resets the position of the enumerator.\n    ///     Reset (for interface IEnumerator).\n    /// </summary>\n    public void Reset() => position = -1;\n\n    /// <summary>\n    ///     Disposes object, nothing to dispose here though.\n    /// </summary>\n    public void Dispose()\n    {\n        // Done\n    }\n\n    /// <summary>\n    ///     Returns a bit-array that represents the bit by bit AND (&amp;).\n    ///     Assumes arrays have the same length.\n    /// </summary>\n    /// <param name=\"one\">First bit-array.</param>\n    /// <param name=\"two\">Second bit-array.</param>\n    /// <returns>bit-array.</returns>\n    public static BitArray operator &(BitArray one, BitArray two)\n    {\n        var sequence1 = one.ToString();\n        var sequence2 = two.ToString();\n        var result = new StringBuilder();\n        var tmp = new StringBuilder();\n\n        // for scaling of same length.\n        if (one.Length != two.Length)\n        {\n            int difference;\n            if (one.Length > two.Length)\n            {\n                // one is greater\n                difference = one.Length - two.Length;\n\n                // fills up with 0's\n                for (var i = 0; i < difference; i++)\n                {\n                    tmp.Append('0');\n                }\n\n                tmp.Append(two);\n                sequence2 = tmp.ToString();\n            }\n            else\n            {\n                // two is greater\n                difference = two.Length - one.Length;\n\n                // fills up with 0's\n                for (var i = 0; i < difference; i++)\n                {\n                    tmp.Append('0');\n                }\n\n                tmp.Append(one);\n                sequence1 = tmp.ToString();\n            }\n        } // end scaling\n\n        var len = one.Length > two.Length ? one.Length : two.Length;\n        var ans = new BitArray(len);\n\n        for (var i = 0; i < one.Length; i++)\n        {\n            result.Append(sequence1[i].Equals('1') && sequence2[i].Equals('1') ? '1' : '0');\n        }\n\n        ans.Compile(result.ToString().Trim());\n\n        return ans;\n    }\n\n    /// <summary>\n    ///     Returns a bit-array that represents the bit by bit OR.\n    ///     Assumes arrays have the same length.\n    /// </summary>\n    /// <param name=\"one\">First bit-array.</param>\n    /// <param name=\"two\">Second bit-array.</param>\n    /// <returns>bit-array that represents the bit by bit OR.</returns>\n    public static BitArray operator |(BitArray one, BitArray two)\n    {\n        var sequence1 = one.ToString();\n        var sequence2 = two.ToString();\n        var result = new StringBuilder();\n\n        // for scaling of same length.\n        if (one.Length != two.Length)\n        {\n            var tmp = new StringBuilder();\n            int difference;\n            if (one.Length > two.Length)\n            {\n                // one is greater\n                difference = one.Length - two.Length;\n\n                // fills up with 0's\n                tmp.Append('0', difference);\n                tmp.Append(two.ToString());\n                sequence2 = tmp.ToString();\n            }\n            else\n            {\n                // two is greater\n                difference = two.Length - one.Length;\n\n                // fills up with 0's\n                tmp.Append('0', difference);\n                tmp.Append(one.ToString());\n                sequence1 = tmp.ToString();\n            }\n        } // end scaling\n\n        var len = one.Length > two.Length ? one.Length : two.Length;\n        var ans = new BitArray(len);\n\n        for (var i = 0; i < len; i++)\n        {\n            result.Append(sequence1[i].Equals('0') && sequence2[i].Equals('0') ? '0' : '1');\n        }\n\n        ans.Compile(result.ToString());\n\n        return ans;\n    }\n\n    /// <summary>\n    ///     Returns a bit-array that represents the operator ~ (NOT).\n    ///     Assumes arrays have the same length.\n    /// </summary>\n    /// <param name=\"one\">Bit-array.</param>\n    /// <returns>bitwise not.</returns>\n    public static BitArray operator ~(BitArray one)\n    {\n        var ans = new BitArray(one.Length);\n        var sequence = one.ToString();\n        var result = new StringBuilder(sequence.Length);\n\n        foreach (var ch in sequence)\n        {\n            result.Append(ch == '1' ? '0' : '1');\n        }\n\n        ans.Compile(result.ToString());\n\n        return ans;\n    }\n\n    /// <summary>\n    ///     Returns a bit-array that represents bitwise shift left (&gt;&gt;).\n    ///     Assumes arrays have the same length.\n    /// </summary>\n    /// <param name=\"other\">Bit-array.</param>\n    /// <param name=\"n\">Number of bits.</param>\n    /// <returns>Bitwise shifted BitArray.</returns>\n    public static BitArray operator <<(BitArray other, int n)\n    {\n        var ans = new BitArray(other.Length + n);\n\n        // actual shifting process\n        for (var i = 0; i < other.Length; i++)\n        {\n            ans[i] = other[i];\n        }\n\n        return ans;\n    }\n\n    /// <summary>\n    ///     Returns a bit-array that represents the bit by bit XOR.\n    ///     Assumes arrays have the same length.\n    /// </summary>\n    /// <param name=\"one\">First bit-array.</param>\n    /// <param name=\"two\">Second bit-array.</param>\n    /// <returns>bit-array.</returns>\n    public static BitArray operator ^(BitArray one, BitArray two)\n    {\n        var sequence1 = one.ToString();\n        var sequence2 = two.ToString();\n\n        // for scaling of same length.\n        if (one.Length != two.Length)\n        {\n            var tmp = new StringBuilder();\n            int difference;\n            if (one.Length > two.Length)\n            {\n                // one is greater\n                difference = one.Length - two.Length;\n\n                // fills up with 0's\n                tmp.Append('0', difference);\n                tmp.Append(two.ToString());\n                sequence2 = tmp.ToString();\n            }\n            else\n            {\n                // two is greater\n                difference = two.Length - one.Length;\n\n                // fills up with 0's\n                tmp.Append('0', difference);\n                tmp.Append(one.ToString());\n                sequence1 = tmp.ToString();\n            }\n        } // end scaling\n\n        var len = one.Length > two.Length ? one.Length : two.Length;\n        var ans = new BitArray(len);\n\n        var sb = new StringBuilder(len);\n\n        for (var i = 0; i < len; i++)\n        {\n            sb.Append(sequence1[i] == sequence2[i] ? '0' : '1');\n        }\n\n        ans.Compile(sb.ToString());\n\n        return ans;\n    }\n\n    /// <summary>\n    ///     Returns a bit-array that represents bitwise shift right (>>).\n    ///     Assumes arrays have the same length.\n    /// </summary>\n    /// <param name=\"other\">Bit-array.</param>\n    /// <param name=\"n\">Number of bits.</param>\n    /// <returns>Bitwise shifted BitArray.</returns>\n    public static BitArray operator >>(BitArray other, int n)\n    {\n        var ans = new BitArray(other.Length - n);\n\n        // actual shifting process.\n        for (var i = 0; i < other.Length - n; i++)\n        {\n            ans[i] = other[i];\n        }\n\n        return ans;\n    }\n\n    /// <summary>\n    ///     Checks if both arrays are == (equal).\n    ///     The input assumes arrays have the same length.\n    /// </summary>\n    /// <param name=\"one\">First bit-array.</param>\n    /// <param name=\"two\">Second bit-array.</param>\n    /// <returns>Returns True if there inputs are equal; False otherwise.</returns>\n    public static bool operator ==(BitArray one, BitArray two)\n    {\n        if (ReferenceEquals(one, two))\n        {\n            return true;\n        }\n\n        if (one.Length != two.Length)\n        {\n            return false;\n        }\n\n        var status = true;\n        for (var i = 0; i < one.Length; i++)\n        {\n            if (one[i] != two[i])\n            {\n                status = false;\n                break;\n            }\n        }\n\n        return status;\n    }\n\n    /// <summary>\n    ///     Checks if both arrays are != (not-equal).\n    ///     The input assumes arrays have the same length.\n    /// </summary>\n    /// <param name=\"one\">First bit-array.</param>\n    /// <param name=\"two\">Second bit-array.</param>\n    /// <returns>Returns True if there inputs aren't equal; False otherwise.</returns>\n    public static bool operator !=(BitArray one, BitArray two) => !(one == two);\n\n    /// <summary>\n    ///     Compiles the binary sequence into the inner data structure.\n    ///     The sequence must have the same length, as the bit-array.\n    ///     The sequence may only be allowed contains ones or zeros.\n    /// </summary>\n    /// <param name=\"sequence\">A string sequence of 0's and 1's.</param>\n    public void Compile(string sequence)\n    {\n        // precondition I\n        if (sequence.Length > field.Length)\n        {\n            throw new ArgumentException($\"{nameof(sequence)} must be not longer than the bit array length\");\n        }\n\n        // precondition II\n        ThrowIfSequenceIsInvalid(sequence);\n\n        // for appropriate scaling\n        if (sequence.Length < field.Length)\n        {\n            var difference = field.Length - sequence.Length;\n            sequence = new string('0', difference) + sequence;\n        }\n\n        // actual compile procedure.\n        for (var i = 0; i < sequence.Length; i++)\n        {\n            field[i] = sequence[i] == '1';\n        }\n    }\n\n    /// <summary>\n    ///     Compiles integer number into the inner data structure.\n    ///     Assumes: the number must have the same bit length.\n    /// </summary>\n    /// <param name=\"number\">A positive integer number.</param>\n    public void Compile(int number)\n    {\n        // precondition I\n        if (number <= 0)\n        {\n            throw new ArgumentException($\"{nameof(number)} must be positive\");\n        }\n\n        // converts to binary representation\n        var binaryNumber = Convert.ToString(number, 2);\n\n        // precondition II\n        if (binaryNumber.Length > field.Length)\n        {\n            throw new ArgumentException(\"Provided number is too big\");\n        }\n\n        // for appropriate scaling\n        if (binaryNumber.Length < field.Length)\n        {\n            var difference = field.Length - binaryNumber.Length;\n            binaryNumber = new string('0', difference) + binaryNumber;\n        }\n\n        // actual compile procedure.\n        for (var i = 0; i < binaryNumber.Length; i++)\n        {\n            field[i] = binaryNumber[i] == '1';\n        }\n    }\n\n    /// <summary>\n    ///     Compiles integer number into the inner data structure.\n    ///     The number must have the same bit length.\n    /// </summary>\n    /// <param name=\"number\">A positive long integer number.</param>\n    public void Compile(long number)\n    {\n        // precondition I\n        if (number <= 0)\n        {\n            throw new ArgumentException($\"{nameof(number)} must be positive\");\n        }\n\n        // converts to binary representation\n        var binaryNumber = Convert.ToString(number, 2);\n\n        // precondition II\n        if (binaryNumber.Length > field.Length)\n        {\n            throw new ArgumentException(\"Provided number is too big\");\n        }\n\n        // for appropriate scaling\n        if (binaryNumber.Length < field.Length)\n        {\n            var difference = field.Length - binaryNumber.Length;\n            binaryNumber = new string('0', difference) + binaryNumber;\n        }\n\n        // actual compile procedure.\n        for (var i = 0; i < binaryNumber.Length; i++)\n        {\n            field[i] = binaryNumber[i] == '1';\n        }\n    }\n\n    /// <summary>\n    ///     Is the opposit of the Compile(...) method.\n    /// </summary>\n    /// <returns>Returns a string representation of the inner data structure.</returns>\n    public override string ToString()\n    {\n        // creates return-string\n        return field.Aggregate(string.Empty, (current, t) => current + (t ? \"1\" : \"0\"));\n    }\n\n    /// <summary>\n    ///     Gets the number of one-bits in the field.\n    /// </summary>\n    /// <returns>quantity of bits in current bit-array.</returns>\n    public int NumberOfOneBits()\n    {\n        // counting one-bits.\n        return field.Count(bit => bit);\n    }\n\n    /// <summary>\n    ///     Gets the number of zero-bits in the field.\n    /// </summary>\n    /// <returns>quantity of bits.</returns>\n    public int NumberOfZeroBits()\n    {\n        // counting zero-bits\n        return field.Count(bit => !bit);\n    }\n\n    /// <summary>\n    ///     To check for even parity.\n    /// </summary>\n    /// <returns>Returns True if parity is even; False otherwise.</returns>\n    public bool EvenParity() => NumberOfOneBits() % 2 == 0;\n\n    /// <summary>\n    ///     To check for odd parity.\n    /// </summary>\n    /// <returns>Returns True if parity is odd; False otherwise.</returns>\n    public bool OddParity() => NumberOfOneBits() % 2 != 0;\n\n    /// <summary>\n    ///     Returns a long integer representation of the bit-array.\n    ///     Assumes the bit-array length must been smaller or equal to 64 bit.\n    /// </summary>\n    /// <returns>Long integer array.</returns>\n    public long ToInt64()\n    {\n        // Precondition\n        if (field.Length > 64)\n        {\n            throw new InvalidOperationException(\"Value is too big to fit into Int64\");\n        }\n\n        var sequence = ToString();\n        return Convert.ToInt64(sequence, 2);\n    }\n\n    /// <summary>\n    ///     Returns a long integer representation of the bit-array.\n    ///     Assumes the bit-array length must been smaller or equal to 32 bit.\n    /// </summary>\n    /// <returns>integer array.</returns>\n    public int ToInt32()\n    {\n        // Precondition\n        if (field.Length > 32)\n        {\n            throw new InvalidOperationException(\"Value is too big to fit into Int32\");\n        }\n\n        var sequence = ToString();\n        return Convert.ToInt32(sequence, 2);\n    }\n\n    /// <summary>\n    ///     Sets all bits on false.\n    /// </summary>\n    public void ResetField()\n    {\n        for (var i = 0; i < field.Length; i++)\n        {\n            field[i] = false;\n        }\n    }\n\n    /// <summary>\n    ///     Sets all bits on the value of the flag.\n    /// </summary>\n    /// <param name=\"flag\">Bollean flag (false-true).</param>\n    public void SetAll(bool flag)\n    {\n        for (var i = 0; i < field.Length; i++)\n        {\n            field[i] = flag;\n        }\n    }\n\n    /// <summary>\n    ///     Checks if bit-array are equal.\n    ///     Assumes the input bit-arrays must have same length.\n    /// </summary>\n    /// <param name=\"obj\">Bit-array object.</param>\n    /// <returns>Returns true if there inputs are equal otherwise false.</returns>\n    public override bool Equals(object? obj)\n    {\n        if (obj is null)\n        {\n            return false;\n        }\n\n        var otherBitArray = (BitArray)obj;\n\n        if (Length != otherBitArray.Length)\n        {\n            return false;\n        }\n\n        for (var i = 0; i < Length; i++)\n        {\n            if (field[i] != otherBitArray[i])\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    ///     Gets has-code of bit-array.\n    ///     Assumes bit-array length must been smaller or equal to 32.\n    /// </summary>\n    /// <returns>hash-code for this BitArray instance.</returns>\n    public override int GetHashCode() => ToInt32();\n\n    private static void ThrowIfSequenceIsInvalid(string sequence)\n    {\n        if (!Match(sequence))\n        {\n            throw new ArgumentException(\"The sequence may only contain ones or zeros\");\n        }\n    }\n\n    /// <summary>\n    ///     Utility method for checking a given sequence contains only zeros and ones.\n    ///     This method will used in Constructor (sequence : string) and Compile(sequence : string).\n    /// </summary>\n    /// <param name=\"sequence\">String sequence.</param>\n    /// <returns>returns True if sequence contains only zeros and ones; False otherwise.</returns>\n    private static bool Match(string sequence) => sequence.All(ch => ch == '0' || ch == '1');\n}\n"
  },
  {
    "path": "DataStructures/Cache/LfuCache.cs",
    "content": "namespace DataStructures.Cache;\n\n/// <summary>\n/// Least Frequently Used (LFU) cache implementation.\n/// </summary>\n/// <typeparam name=\"TKey\">The type of the key (must be not null).</typeparam>\n/// <typeparam name=\"TValue\">The type of the value.</typeparam>\n/// <remarks>\n/// Cache keeps up to <c>capacity</c> items. When new item is added and cache is full,\n/// one of the least frequently used item is removed (e.g. it keeps N items that were the most\n/// frequently requested using <c>Get()</c> or <c>Put()</c> methods).\n/// When there are multiple items with the same frequency, the least recently used item is removed.\n///\n/// Cache is built on top of two data structures:\n/// - <c>Dictionary</c>. Allows items to be looked up by key in O(1) time. Another dictionary\n///   is used to store the frequency of each key.\n/// - <c>LinkedList</c> - Allows items with the same frequency to be ordered by the last\n///   usage in O(1) time.\n///\n/// Useful links:\n/// https://en.wikipedia.org/wiki/Cache_replacement_policies\n/// https://www.enjoyalgorithms.com/blog/least-frequently-used-cache\n/// https://www.educative.io/answers/what-is-least-frequently-used-cache-replace-policy\n/// https://leetcode.com/problems/lfu-cache/ .\n/// </remarks>\n/// <remarks>\n/// Initializes a new instance of the <see cref=\"LfuCache{TKey, TValue}\"/> class.\n/// </remarks>\n/// <param name=\"capacity\">The max number of items the cache can store.</param>\npublic class LfuCache<TKey, TValue>(int capacity = LfuCache<TKey, TValue>.DefaultCapacity) where TKey : notnull\n{\n    private class CachedItem\n    {\n        public TKey Key { get; set; } = default!;\n\n        public TValue? Value { get; set; }\n\n        public int Frequency { get; set; }\n    }\n\n    private const int DefaultCapacity = 100;\n\n    private readonly int capacity = capacity;\n\n    // Note that <c>Dictionary</c> stores <c>LinkedListNode</c> as it allows\n    // removing the node from the <c>LinkedList</c> in O(1) time.\n    private readonly Dictionary<TKey, LinkedListNode<CachedItem>> cache = [];\n\n    // Map frequency (number of times the item was requested or updated)\n    // to the LRU linked list.\n    private readonly Dictionary<int, LinkedList<CachedItem>> frequencies = [];\n\n    // Track the minimum frequency with non-empty linked list in <c>frequencies</c>.\n    // When the last item with the minFrequency is promoted (after being requested or updated),\n    // the <c>minFrequency</c> is increased.\n    // When a new item is added, the <c>minFrequency</c> is set to 1.\n    private int minFrequency = -1;\n\n    public bool Contains(TKey key) => cache.ContainsKey(key);\n\n    /// <summary>\n    /// Gets the cached item by key.\n    /// </summary>\n    /// <param name=\"key\">The key of cached item.</param>\n    /// <returns>The cached item or <c>default</c> if item is not found.</returns>\n    /// <remarks> Time complexity: O(1). </remarks>\n    public TValue? Get(TKey key)\n    {\n        if (!cache.ContainsKey(key))\n        {\n            return default;\n        }\n\n        var node = cache[key];\n        UpdateFrequency(node, isNew: false);\n        return node.Value.Value;\n    }\n\n    /// <summary>\n    /// Adds or updates the value in the cache.\n    /// </summary>\n    /// <param name=\"key\">The key of item to cache.</param>\n    /// <param name=\"value\">The value to cache.</param>\n    /// <remarks>\n    /// Time complexity: O(1).\n    /// If the value is already cached, it is updated and the item is moved\n    /// to the end of the LRU list.\n    /// If the cache is full, one of the least frequently used items is removed.\n    /// </remarks>\n    public void Put(TKey key, TValue value)\n    {\n        if (cache.ContainsKey(key))\n        {\n            var existingNode = cache[key];\n            existingNode.Value.Value = value;\n            UpdateFrequency(existingNode, isNew: false);\n            return;\n        }\n\n        if (cache.Count >= capacity)\n        {\n            EvictOneItem();\n        }\n\n        var item = new CachedItem { Key = key, Value = value };\n        var newNode = new LinkedListNode<CachedItem>(item);\n        UpdateFrequency(newNode, isNew: true);\n        cache.Add(key, newNode);\n    }\n\n    private void UpdateFrequency(LinkedListNode<CachedItem> node, bool isNew)\n    {\n        var item = node.Value;\n\n        if (isNew)\n        {\n            item.Frequency = 1;\n            minFrequency = 1;\n        }\n        else\n        {\n            // Remove the existing node from the LRU list with its previous frequency.\n            var lruList = frequencies[item.Frequency];\n            lruList.Remove(node);\n            if (lruList.Count == 0 && minFrequency == item.Frequency)\n            {\n                minFrequency++;\n            }\n\n            item.Frequency++;\n        }\n\n        // Insert item to the end of the LRU list that corresponds to its new frequency.\n        if (!frequencies.ContainsKey(item.Frequency))\n        {\n            frequencies[item.Frequency] = new LinkedList<CachedItem>();\n        }\n\n        frequencies[item.Frequency].AddLast(node);\n    }\n\n    private void EvictOneItem()\n    {\n        var lruList = frequencies[minFrequency];\n        var itemToRemove = lruList.First!.Value;\n        lruList.RemoveFirst();\n        cache.Remove(itemToRemove.Key);\n    }\n}\n"
  },
  {
    "path": "DataStructures/Cache/LruCache.cs",
    "content": "namespace DataStructures.Cache;\n\n/// <summary>\n/// Least Recently Used (LRU) cache implementation.\n/// </summary>\n/// <typeparam name=\"TKey\">The type of the key (must be not null).</typeparam>\n/// <typeparam name=\"TValue\">The type of the value.</typeparam>\n/// <remarks>\n/// Cache keeps up to <c>capacity</c> items. When new item is added and cache is full,\n/// the least recently used item is removed (e.g. it keeps N items that were recently requested\n/// using <c>Get()</c> or <c>Put()</c> methods).\n///\n/// Cache is built on top of two data structures:\n/// - <c>Dictionary</c> - allows items to be looked up by key in O(1) time.\n/// - <c>LinkedList</c> - allows items to be ordered by last usage time in O(1) time.\n///\n/// Useful links:\n/// https://en.wikipedia.org/wiki/Cache_replacement_policies\n/// https://www.educative.io/m/implement-least-recently-used-cache\n/// https://leetcode.com/problems/lru-cache/\n///\n/// In order to make the most recently used (MRU) cache, when the cache is full,\n/// just remove the last node from the linked list in the method <c>Put</c>\n/// (replace <c>RemoveFirst</c> with <c>RemoveLast</c>).\n/// </remarks>\n/// <remarks>\n/// Initializes a new instance of the <see cref=\"LruCache{TKey, TValue}\"/> class.\n/// </remarks>\n/// <param name=\"capacity\">The max number of items the cache can store.</param>\npublic class LruCache<TKey, TValue>(int capacity = LruCache<TKey, TValue>.DefaultCapacity) where TKey : notnull\n{\n    private class CachedItem\n    {\n        public TKey Key { get; set; } = default!;\n\n        public TValue? Value { get; set; }\n    }\n\n    private const int DefaultCapacity = 100;\n\n    private readonly int capacity = capacity;\n\n    // Note that <c>Dictionary</c> stores <c>LinkedListNode</c> as it allows\n    // removing the node from the <c>LinkedList</c> in O(1) time.\n    private readonly Dictionary<TKey, LinkedListNode<CachedItem>> cache = [];\n    private readonly LinkedList<CachedItem> lruList = new();\n\n    public bool Contains(TKey key) => cache.ContainsKey(key);\n\n    /// <summary>\n    /// Gets the cached item by key.\n    /// </summary>\n    /// <param name=\"key\">The key of cached item.</param>\n    /// <returns>The cached item or <c>default</c> if item is not found.</returns>\n    /// <remarks> Time complexity: O(1). </remarks>\n    public TValue? Get(TKey key)\n    {\n        if (!cache.ContainsKey(key))\n        {\n            return default;\n        }\n\n        var node = cache[key];\n        lruList.Remove(node);\n        lruList.AddLast(node);\n\n        return node.Value.Value;\n    }\n\n    /// <summary>\n    /// Adds or updates the value in the cache.\n    /// </summary>\n    /// <param name=\"key\">The key of item to cache.</param>\n    /// <param name=\"value\">The value to cache.</param>\n    /// <remarks>\n    /// Time complexity: O(1).\n    /// If the value is already cached, it is updated and the item is moved\n    /// to the end of the LRU list.\n    /// If the cache is full, the least recently used item is removed.\n    /// </remarks>\n    public void Put(TKey key, TValue value)\n    {\n        if (cache.ContainsKey(key))\n        {\n            var existingNode = cache[key];\n            existingNode.Value.Value = value;\n            lruList.Remove(existingNode);\n            lruList.AddLast(existingNode);\n            return;\n        }\n\n        if (cache.Count >= capacity)\n        {\n            var first = lruList.First!;\n            lruList.RemoveFirst();\n            cache.Remove(first.Value.Key);\n        }\n\n        var item = new CachedItem { Key = key, Value = value };\n        var newNode = lruList.AddLast(item);\n        cache.Add(key, newNode);\n    }\n}\n"
  },
  {
    "path": "DataStructures/DataStructures.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <CodeAnalysisRuleSet>..\\stylecop.ruleset</CodeAnalysisRuleSet>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n    <DocumentationFile>./bin/DataStructures.xml</DocumentationFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <AdditionalFiles Include=\"..\\stylecop.json\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"StyleCop.Analyzers\" Version=\"1.2.0-beta.556\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Utilities\\Utilities.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "DataStructures/Deque/Deque.cs",
    "content": "namespace DataStructures.Deque;\n\n/// <summary>\n///     Implementation of a Deque (Double-Ended Queue) data structure.\n///     A deque allows insertion and deletion of elements from both ends (front and rear).\n///     This implementation uses a circular array for efficient operations.\n///\n///     Key Features:\n///     - O(1) time complexity for AddFront, AddRear, RemoveFront, RemoveRear operations\n///     - O(1) amortized time for insertions (due to dynamic resizing)\n///     - Space efficient with circular array implementation\n///     - Automatic capacity doubling when full\n///\n///     Use Cases:\n///     - Implementing sliding window algorithms\n///     - Palindrome checking\n///     - Undo/Redo functionality\n///     - Task scheduling with priority at both ends\n///\n///     Reference: \"Data Structures and Algorithms in C#\" by Michael T. Goodrich.\n/// </summary>\n/// <typeparam name=\"T\">The type of elements in the deque.</typeparam>\npublic class Deque<T>\n{\n    // Internal circular array to store elements\n    private T[] items;\n\n    // Index of the front element (next element to remove from front)\n    private int front;\n\n    // Index where the next element will be added at rear\n    private int rear;\n\n    // Current number of elements in the deque\n    private int count;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"Deque{T}\" /> class with default capacity.\n    ///     Default capacity is 16 elements, which provides a good balance between\n    ///     memory usage and avoiding early resizing for typical use cases.\n    /// </summary>\n    public Deque()\n        : this(16)\n    {\n    }\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"Deque{T}\" /> class with specified capacity.\n    /// </summary>\n    /// <param name=\"capacity\">The initial capacity of the deque.</param>\n    /// <exception cref=\"ArgumentException\">Thrown when capacity is less than 1.</exception>\n    public Deque(int capacity)\n    {\n        if (capacity < 1)\n        {\n            throw new ArgumentException(\"Capacity must be at least 1.\", nameof(capacity));\n        }\n\n        items = new T[capacity];\n        front = 0;\n        rear = 0;\n        count = 0;\n    }\n\n    /// <summary>\n    ///     Gets the number of elements in the deque.\n    /// </summary>\n    public int Count => count;\n\n    /// <summary>\n    ///     Gets a value indicating whether the deque is empty.\n    /// </summary>\n    public bool IsEmpty => count == 0;\n\n    /// <summary>\n    ///     Adds an element to the front of the deque.\n    ///     This operation is O(1) time complexity (amortized due to occasional resizing).\n    /// </summary>\n    /// <param name=\"item\">The item to add.</param>\n    /// <example>\n    ///     deque.AddFront(5);  // Deque: [5].\n    ///     deque.AddFront(3);  // Deque: [3, 5].\n    /// </example>\n    public void AddFront(T item)\n    {\n        // Check if we need to resize before adding\n        if (count == items.Length)\n        {\n            Resize();\n        }\n\n        // Move front pointer backward in circular fashion\n        // Adding items.Length ensures the result is always positive\n        front = (front - 1 + items.Length) % items.Length;\n        items[front] = item;\n        count++;\n    }\n\n    /// <summary>\n    ///     Adds an element to the rear of the deque.\n    ///     This operation is O(1) time complexity (amortized due to occasional resizing).\n    /// </summary>\n    /// <param name=\"item\">The item to add.</param>\n    /// <example>\n    ///     deque.AddRear(5);  // Deque: [5].\n    ///     deque.AddRear(7);  // Deque: [5, 7].\n    /// </example>\n    public void AddRear(T item)\n    {\n        // Check if we need to resize before adding\n        if (count == items.Length)\n        {\n            Resize();\n        }\n\n        // Add item at rear position\n        items[rear] = item;\n\n        // Move rear pointer forward in circular fashion\n        rear = (rear + 1) % items.Length;\n        count++;\n    }\n\n    /// <summary>\n    ///     Removes and returns the element at the front of the deque.\n    ///     This operation is O(1) time complexity.\n    /// </summary>\n    /// <returns>The element at the front of the deque.</returns>\n    /// <exception cref=\"InvalidOperationException\">Thrown when the deque is empty.</exception>\n    /// <example>\n    ///     // Deque: [3, 5, 7].\n    ///     int value = deque.RemoveFront();  // Returns 3, Deque: [5, 7].\n    /// </example>\n    public T RemoveFront()\n    {\n        // Validate that deque is not empty\n        if (IsEmpty)\n        {\n            throw new InvalidOperationException(\"Deque is empty.\");\n        }\n\n        // Retrieve the front element\n        T item = items[front];\n\n        // Clear the reference to help garbage collection\n        items[front] = default!;\n\n        // Move front pointer forward in circular fashion\n        front = (front + 1) % items.Length;\n        count--;\n\n        return item;\n    }\n\n    /// <summary>\n    ///     Removes and returns the element at the rear of the deque.\n    ///     This operation is O(1) time complexity.\n    /// </summary>\n    /// <returns>The element at the rear of the deque.</returns>\n    /// <exception cref=\"InvalidOperationException\">Thrown when the deque is empty.</exception>\n    /// <example>\n    ///     // Deque: [3, 5, 7].\n    ///     int value = deque.RemoveRear();  // Returns 7, Deque: [3, 5].\n    /// </example>\n    public T RemoveRear()\n    {\n        // Validate that deque is not empty\n        if (IsEmpty)\n        {\n            throw new InvalidOperationException(\"Deque is empty.\");\n        }\n\n        // Move rear pointer backward to the last element\n        rear = (rear - 1 + items.Length) % items.Length;\n\n        // Retrieve the rear element\n        T item = items[rear];\n\n        // Clear the reference to help garbage collection\n        items[rear] = default!;\n        count--;\n\n        return item;\n    }\n\n    /// <summary>\n    ///     Returns the element at the front of the deque without removing it.\n    ///     This operation is O(1) time complexity and does not modify the deque.\n    /// </summary>\n    /// <returns>The element at the front of the deque.</returns>\n    /// <exception cref=\"InvalidOperationException\">Thrown when the deque is empty.</exception>\n    /// <example>\n    ///     // Deque: [3, 5, 7].\n    ///     int value = deque.PeekFront();  // Returns 3, Deque unchanged: [3, 5, 7].\n    /// </example>\n    public T PeekFront()\n    {\n        // Validate that deque is not empty\n        if (IsEmpty)\n        {\n            throw new InvalidOperationException(\"Deque is empty.\");\n        }\n\n        return items[front];\n    }\n\n    /// <summary>\n    ///     Returns the element at the rear of the deque without removing it.\n    ///     This operation is O(1) time complexity and does not modify the deque.\n    /// </summary>\n    /// <returns>The element at the rear of the deque.</returns>\n    /// <exception cref=\"InvalidOperationException\">Thrown when the deque is empty.</exception>\n    /// <example>\n    ///     // Deque: [3, 5, 7].\n    ///     int value = deque.PeekRear();  // Returns 7, Deque unchanged: [3, 5, 7].\n    /// </example>\n    public T PeekRear()\n    {\n        // Validate that deque is not empty\n        if (IsEmpty)\n        {\n            throw new InvalidOperationException(\"Deque is empty.\");\n        }\n\n        // Calculate the index of the last element (rear - 1 in circular array)\n        int rearIndex = (rear - 1 + items.Length) % items.Length;\n        return items[rearIndex];\n    }\n\n    /// <summary>\n    ///     Removes all elements from the deque.\n    ///     This operation is O(n) where n is the capacity of the internal array.\n    ///     After clearing, the deque can be reused without reallocation.\n    /// </summary>\n    public void Clear()\n    {\n        // Clear all references in the array to help garbage collection\n        Array.Clear(items, 0, items.Length);\n\n        // Reset pointers to initial state\n        front = 0;\n        rear = 0;\n        count = 0;\n    }\n\n    /// <summary>\n    ///     Converts the deque to an array.\n    ///     This operation is O(n) where n is the number of elements.\n    ///     The resulting array maintains the order from front to rear.\n    /// </summary>\n    /// <returns>An array containing all elements in the deque from front to rear.</returns>\n    /// <example>\n    ///     // Deque: [3, 5, 7].\n    ///     int[] array = deque.ToArray();  // Returns [3, 5, 7].\n    /// </example>\n    public T[] ToArray()\n    {\n        // Create result array with exact size needed\n        T[] result = new T[count];\n        int index = front;\n\n        // Copy elements from front to rear, handling circular wrap-around\n        for (int i = 0; i < count; i++)\n        {\n            result[i] = items[index];\n            index = (index + 1) % items.Length;\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Determines whether the deque contains a specific element.\n    ///     This operation is O(n) where n is the number of elements.\n    ///     Uses the default equality comparer for type T.\n    /// </summary>\n    /// <param name=\"item\">The item to locate in the deque.</param>\n    /// <returns>true if the item is found; otherwise, false.</returns>\n    /// <example>\n    ///     // Deque: [3, 5, 7].\n    ///     bool exists = deque.Contains(5);  // Returns true.\n    ///     bool missing = deque.Contains(9);  // Returns false.\n    /// </example>\n    public bool Contains(T item)\n    {\n        int index = front;\n\n        // Iterate through all elements in order from front to rear\n        for (int i = 0; i < count; i++)\n        {\n            // Use default equality comparer to compare elements\n            if (EqualityComparer<T>.Default.Equals(items[index], item))\n            {\n                return true;\n            }\n\n            // Move to next element in circular array\n            index = (index + 1) % items.Length;\n        }\n\n        return false;\n    }\n\n    /// <summary>\n    ///     Resizes the internal array to accommodate more elements.\n    ///     This is a private helper method called automatically when capacity is reached.\n    ///     Doubles the capacity and reorganizes elements to start at index 0.\n    ///     Time complexity: O(n) where n is the current number of elements.\n    /// </summary>\n    private void Resize()\n    {\n        // Double the capacity to reduce frequency of future resizes\n        int newCapacity = items.Length * 2;\n        T[] newItems = new T[newCapacity];\n\n        // Copy all elements to new array starting from index 0\n        // This \"unwraps\" the circular structure for simplicity\n        int index = front;\n        for (int i = 0; i < count; i++)\n        {\n            newItems[i] = items[index];\n            index = (index + 1) % items.Length;\n        }\n\n        // Replace old array with new larger array\n        items = newItems;\n\n        // Reset pointers: front at 0, rear at position after last element\n        front = 0;\n        rear = count;\n    }\n}\n"
  },
  {
    "path": "DataStructures/DisjointSet/DisjointSet.cs",
    "content": "namespace DataStructures.DisjointSet;\n\n/// <summary>\n/// Implementation of Disjoint Set with Union By Rank and Path Compression heuristics.\n/// </summary>\n/// <typeparam name=\"T\"> generic type for implementation.</typeparam>\npublic class DisjointSet<T>\n{\n    /// <summary>\n    /// make a new set and return its representative.\n    /// </summary>\n    /// <param name=\"x\">element to add in to the DS.</param>\n    /// <returns>representative of x.</returns>\n    public Node<T> MakeSet(T x) => new(x);\n\n    /// <summary>\n    /// find the representative of a certain node.\n    /// </summary>\n    /// <param name=\"node\">node to find representative.</param>\n    /// <returns>representative of x.</returns>\n    public Node<T> FindSet(Node<T> node)\n    {\n        if (node != node.Parent)\n        {\n            node.Parent = FindSet(node.Parent);\n        }\n\n        return node.Parent;\n    }\n\n    /// <summary>\n    /// merge two sets.\n    /// </summary>\n    /// <param name=\"x\">first set member.</param>\n    /// <param name=\"y\">second set member.</param>\n    public void UnionSet(Node<T> x, Node<T> y)\n    {\n        Node<T> nx = FindSet(x);\n        Node<T> ny = FindSet(y);\n        if (nx == ny)\n        {\n            return;\n        }\n\n        if (nx.Rank > ny.Rank)\n        {\n            ny.Parent = nx;\n        }\n        else if (ny.Rank > nx.Rank)\n        {\n            nx.Parent = ny;\n        }\n        else\n        {\n            nx.Parent = ny;\n            ny.Rank++;\n        }\n    }\n}\n"
  },
  {
    "path": "DataStructures/DisjointSet/Node.cs",
    "content": "namespace DataStructures.DisjointSet;\n\n/// <summary>\n/// node class to be used by disjoint set to represent nodes in Disjoint Set forest.\n/// </summary>\n/// <typeparam name=\"T\">generic type for data to be stored.</typeparam>\npublic class Node<T>\n{\n    public int Rank { get; set; }\n\n    public Node<T> Parent { get; set; }\n\n    public T Data { get; set; }\n\n    public Node(T data)\n    {\n        Data = data;\n        Parent = this;\n    }\n}\n"
  },
  {
    "path": "DataStructures/Fenwick/BinaryIndexedTree.cs",
    "content": "namespace DataStructures.Fenwick;\n\n/// <summary>\n/// Represent classical realization of Fenwiсk tree or Binary Indexed tree.\n///\n/// BITree[0..n] --> Array that represents Binary Indexed Tree.\n/// arr[0..n-1] --> Input array for which prefix sum is evaluated.\n/// </summary>\npublic class BinaryIndexedTree\n{\n    private readonly int[] fenwickTree;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"BinaryIndexedTree\"/> class.\n    /// Create Binary indexed tree from the given array.\n    /// </summary>\n    /// <param name=\"array\">Initial array.</param>\n    public BinaryIndexedTree(int[] array)\n    {\n        fenwickTree = new int[array.Length + 1];\n\n        for (var i = 0; i < array.Length; i++)\n        {\n            UpdateTree(i, array[i]);\n        }\n    }\n\n    /// <summary>\n    /// This method assumes that the array is preprocessed and\n    /// partial sums of array elements are stored in BITree[].\n    /// </summary>\n    /// <param name=\"index\">The position to sum from.</param>\n    /// <returns>Returns sum of arr[0..index].</returns>\n    public int GetSum(int index)\n    {\n        var sum = 0;\n        var startFrom = index + 1;\n\n        while (startFrom > 0)\n        {\n            sum += fenwickTree[startFrom];\n            startFrom -= startFrom & (-startFrom);\n        }\n\n        return sum;\n    }\n\n    /// <summary>\n    /// Updates a node in Binary Index Tree at given index.\n    /// The given value 'val' is added to BITree[i] and all of its ancestors in tree.\n    /// </summary>\n    /// <param name=\"index\">Given index.</param>\n    /// <param name=\"val\">Value to be update on.</param>\n    public void UpdateTree(int index, int val)\n    {\n        var startFrom = index + 1;\n\n        while (startFrom <= fenwickTree.Length)\n        {\n            fenwickTree[startFrom] += val;\n            startFrom += startFrom & (-startFrom);\n        }\n    }\n}\n"
  },
  {
    "path": "DataStructures/GlobalUsings.cs",
    "content": "// -----------------------------------------------------------------------------\n// Global using directives for the C-Sharp solution.\n// These namespaces are imported globally so they don’t need to be repeatedly declared\n// in individual files, improving readability and reducing boilerplate.\n//\n// Guidelines:\n// - Keep only the most commonly used namespaces here.\n// - Add project-specific namespaces (e.g., Utilities.Extensions) only if they are\n//   required across the majority of files in the project.\n// - Avoid placing rarely used namespaces here to maintain clarity.\n// -----------------------------------------------------------------------------\n\nglobal using System;                        // Core base classes and fundamental types\nglobal using System.Collections.Generic;    // Generic collection types (List, Dictionary, etc.)\nglobal using System.Linq;                   // LINQ query operators for collections\nglobal using System.Text;                   // Text encoding, StringBuilder, etc.\n"
  },
  {
    "path": "DataStructures/Graph/DirectedWeightedGraph.cs",
    "content": "namespace DataStructures.Graph;\n\n/// <summary>\n///     Implementation of the directed weighted graph via adjacency matrix.\n/// </summary>\n/// <typeparam name=\"T\">Generic Type.</typeparam>\npublic class DirectedWeightedGraph<T> : IDirectedWeightedGraph<T>\n{\n    /// <summary>\n    ///     Capacity of the graph, indicates the maximum amount of vertices.\n    /// </summary>\n    private readonly int capacity;\n\n    /// <summary>\n    ///     Adjacency matrix which reflects the edges between vertices and their weight.\n    ///     Zero value indicates no edge between two vertices.\n    /// </summary>\n    private readonly double[,] adjacencyMatrix;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"DirectedWeightedGraph{T}\"/> class.\n    /// </summary>\n    /// <param name=\"capacity\">Capacity of the graph, indicates the maximum amount of vertices.</param>\n    public DirectedWeightedGraph(int capacity)\n    {\n        ThrowIfNegativeCapacity(capacity);\n\n        this.capacity = capacity;\n        Vertices = new Vertex<T>[capacity];\n        adjacencyMatrix = new double[capacity, capacity];\n        Count = 0;\n    }\n\n    /// <summary>\n    ///     Gets list of vertices of the graph.\n    /// </summary>\n    public Vertex<T>?[] Vertices { get; private set; }\n\n    /// <summary>\n    ///     Gets current amount of vertices in the graph.\n    /// </summary>\n    public int Count { get; private set; }\n\n    /// <summary>\n    ///     Adds new vertex to the graph.\n    /// </summary>\n    /// <param name=\"data\">Data of the vertex.</param>\n    /// <returns>Reference to created vertex.</returns>\n    public Vertex<T> AddVertex(T data)\n    {\n        ThrowIfOverflow();\n        var vertex = new Vertex<T>(data, Count, this);\n        Vertices[Count] = vertex;\n        Count++;\n        return vertex;\n    }\n\n    /// <summary>\n    ///     Creates an edge between two vertices of the graph.\n    /// </summary>\n    /// <param name=\"startVertex\">Vertex, edge starts at.</param>\n    /// <param name=\"endVertex\">Vertex, edge ends at.</param>\n    /// <param name=\"weight\">Double weight of an edge.</param>\n    public void AddEdge(Vertex<T> startVertex, Vertex<T> endVertex, double weight)\n    {\n        ThrowIfVertexNotInGraph(startVertex);\n        ThrowIfVertexNotInGraph(endVertex);\n\n        ThrowIfWeightZero(weight);\n\n        var currentEdgeWeight = adjacencyMatrix[startVertex.Index, endVertex.Index];\n\n        ThrowIfEdgeExists(currentEdgeWeight);\n\n        adjacencyMatrix[startVertex.Index, endVertex.Index] = weight;\n    }\n\n    /// <summary>\n    ///     Removes vertex from the graph.\n    /// </summary>\n    /// <param name=\"vertex\">Vertex to be removed.</param>\n    public void RemoveVertex(Vertex<T> vertex)\n    {\n        ThrowIfVertexNotInGraph(vertex);\n\n        int indexToRemove = vertex.Index;\n        vertex.Index = -1;\n        vertex.SetGraphNull();\n\n        // Update the vertex array and the index of vertices.\n        for (int i = indexToRemove; i < Count - 1; i++)\n        {\n            Vertices[i] = Vertices[i + 1];\n            Vertices[i]!.Index = i;\n        }\n\n        Vertices[Count - 1] = null;\n\n        // Update adjacency matrix to remove the row and column of the removed vertex.\n        for (int i = 0; i < Count; i++)\n        {\n            for (int j = 0; j < Count; j++)\n            {\n                if (i < indexToRemove && j < indexToRemove)\n                {\n                    continue;\n                }\n                else if (i < indexToRemove && j >= indexToRemove && j < Count - 1)\n                {\n                    adjacencyMatrix[i, j] = adjacencyMatrix[i, j + 1];\n                }\n                else if (i >= indexToRemove && i < Count - 1 && j < indexToRemove)\n                {\n                    adjacencyMatrix[i, j] = adjacencyMatrix[i + 1, j];\n                }\n                else if (i >= indexToRemove && i < Count - 1 && j >= indexToRemove && j < Count - 1)\n                {\n                    adjacencyMatrix[i, j] = adjacencyMatrix[i + 1, j + 1];\n                }\n                else if (i == Count - 1 || j == Count - 1)\n                {\n                    adjacencyMatrix[i, j] = 0;\n                }\n                else\n                {\n                    throw new InvalidOperationException();\n                }\n            }\n        }\n\n        Count--;\n    }\n\n    /// <summary>\n    ///     Removes edge between two vertices.\n    /// </summary>\n    /// <param name=\"startVertex\">Vertex, edge starts at.</param>\n    /// <param name=\"endVertex\">Vertex, edge ends at.</param>\n    public void RemoveEdge(Vertex<T> startVertex, Vertex<T> endVertex)\n    {\n        ThrowIfVertexNotInGraph(startVertex);\n        ThrowIfVertexNotInGraph(endVertex);\n        adjacencyMatrix[startVertex.Index, endVertex.Index] = 0;\n    }\n\n    /// <summary>\n    ///     Gets a neighbors of particular vertex.\n    /// </summary>\n    /// <param name=\"vertex\">Vertex, method gets list of neighbors for.</param>\n    /// <returns>Collection of the neighbors of particular vertex.</returns>\n    public IEnumerable<Vertex<T>?> GetNeighbors(Vertex<T> vertex)\n    {\n        ThrowIfVertexNotInGraph(vertex);\n\n        for (var i = 0; i < Count; i++)\n        {\n            if (adjacencyMatrix[vertex.Index, i] != 0)\n            {\n                yield return Vertices[i];\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Returns true, if there is an edge between two vertices.\n    /// </summary>\n    /// <param name=\"startVertex\">Vertex, edge starts at.</param>\n    /// <param name=\"endVertex\">Vertex, edge ends at.</param>\n    /// <returns>True if edge exists, otherwise false.</returns>\n    public bool AreAdjacent(Vertex<T> startVertex, Vertex<T> endVertex)\n    {\n        ThrowIfVertexNotInGraph(startVertex);\n        ThrowIfVertexNotInGraph(endVertex);\n\n        return adjacencyMatrix[startVertex.Index, endVertex.Index] != 0;\n    }\n\n    /// <summary>\n    /// Return the distance between two vertices in the graph.\n    /// </summary>\n    /// <param name=\"startVertex\">first vertex in edge.</param>\n    /// <param name=\"endVertex\">secnod vertex in edge.</param>\n    /// <returns>distance between the two.</returns>\n    public double AdjacentDistance(Vertex<T> startVertex, Vertex<T> endVertex)\n    {\n        if (AreAdjacent(startVertex, endVertex))\n        {\n            return adjacencyMatrix[startVertex.Index, endVertex.Index];\n        }\n\n        return 0;\n    }\n\n    private static void ThrowIfNegativeCapacity(int capacity)\n    {\n        if (capacity < 0)\n        {\n            throw new InvalidOperationException(\"Graph capacity should always be a non-negative integer.\");\n        }\n    }\n\n    private static void ThrowIfWeightZero(double weight)\n    {\n        if (weight.Equals(0.0d))\n        {\n            throw new InvalidOperationException(\"Edge weight cannot be zero.\");\n        }\n    }\n\n    private static void ThrowIfEdgeExists(double currentEdgeWeight)\n    {\n        if (!currentEdgeWeight.Equals(0.0d))\n        {\n            throw new InvalidOperationException($\"Vertex already exists: {currentEdgeWeight}\");\n        }\n    }\n\n    private void ThrowIfOverflow()\n    {\n        if (Count == capacity)\n        {\n            throw new InvalidOperationException(\"Graph overflow.\");\n        }\n    }\n\n    private void ThrowIfVertexNotInGraph(Vertex<T> vertex)\n    {\n        if (vertex.Graph != this)\n        {\n            throw new InvalidOperationException($\"Vertex does not belong to graph: {vertex}.\");\n        }\n    }\n}\n"
  },
  {
    "path": "DataStructures/Graph/IDirectedWeightedGraph.cs",
    "content": "namespace DataStructures.Graph;\n\npublic interface IDirectedWeightedGraph<T>\n{\n    int Count { get; }\n\n    Vertex<T>?[] Vertices { get; }\n\n    void AddEdge(Vertex<T> startVertex, Vertex<T> endVertex, double weight);\n\n    Vertex<T> AddVertex(T data);\n\n    bool AreAdjacent(Vertex<T> startVertex, Vertex<T> endVertex);\n\n    double AdjacentDistance(Vertex<T> startVertex, Vertex<T> endVertex);\n\n    IEnumerable<Vertex<T>?> GetNeighbors(Vertex<T> vertex);\n\n    void RemoveEdge(Vertex<T> startVertex, Vertex<T> endVertex);\n\n    void RemoveVertex(Vertex<T> vertex);\n}\n"
  },
  {
    "path": "DataStructures/Graph/Vertex.cs",
    "content": "namespace DataStructures.Graph;\n\n/// <summary>\n///     Implementation of graph vertex.\n/// </summary>\n/// <typeparam name=\"T\">Generic Type.</typeparam>\npublic class Vertex<T>\n{\n    /// <summary>\n    ///     Gets vertex data.\n    /// </summary>\n    public T Data { get; }\n\n    /// <summary>\n    ///     Gets an index of the vertex in graph adjacency matrix.\n    /// </summary>\n    public int Index { get; internal set; }\n\n    /// <summary>\n    ///     Gets reference to the graph this vertex belongs to.\n    /// </summary>\n    public DirectedWeightedGraph<T>? Graph { get; private set; }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"Vertex{T}\"/> class.\n    /// </summary>\n    /// <param name=\"data\">Vertex data. Generic type.</param>\n    /// <param name=\"index\">Index of the vertex in graph adjacency matrix.</param>\n    /// <param name=\"graph\">Graph this vertex belongs to.</param>\n    public Vertex(T data, int index, DirectedWeightedGraph<T>? graph)\n    {\n        Data = data;\n        Index = index;\n        Graph = graph;\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"Vertex{T}\"/> class.\n    /// </summary>\n    /// <param name=\"data\">Vertex data. Generic type.</param>\n    /// <param name=\"index\">Index of the vertex in graph adjacency matrix.</param>\n    public Vertex(T data, int index)\n    {\n        Data = data;\n        Index = index;\n    }\n\n    /// <summary>\n    ///     Sets graph reference to the null. This method called when vertex removed from the graph.\n    /// </summary>\n    public void SetGraphNull() => Graph = null;\n\n    /// <summary>\n    ///     Override of base ToString method. Prints vertex data and index in graph adjacency matrix.\n    /// </summary>\n    /// <returns>String which contains vertex data and index in graph adjacency matrix..</returns>\n    public override string ToString() => $\"Vertex Data: {Data}, Index: {Index}\";\n}\n"
  },
  {
    "path": "DataStructures/Hashing/Entry.cs",
    "content": "namespace DataStructures.Hashing;\n\n/// <summary>\n/// Entry in the hash table.\n/// </summary>\n/// <typeparam name=\"TKey\">Type of the key.</typeparam>\n/// <typeparam name=\"TValue\">Type of the value.</typeparam>\n/// <remarks>\n/// This class is used to store the key-value pairs in the hash table.\n/// </remarks>\npublic class Entry<TKey, TValue>(TKey key, TValue value)\n{\n    public TKey? Key { get; set; } = key;\n\n    public TValue? Value { get; set; } = value;\n}\n"
  },
  {
    "path": "DataStructures/Hashing/HashTable.cs",
    "content": "using DataStructures.Hashing.NumberTheory;\n\nnamespace DataStructures.Hashing;\n\n/// <summary>\n/// Hash table implementation.\n/// </summary>\n/// <typeparam name=\"TKey\">Type of the key.</typeparam>\n/// <typeparam name=\"TValue\">Type of the value.</typeparam>\npublic class HashTable<TKey, TValue>\n{\n    private const int DefaultCapacity = 16;\n    private const float DefaultLoadFactor = 0.75f;\n    private readonly float loadFactor;\n    private int capacity;\n    private int size;\n    private int threshold;\n\n    private Entry<TKey, TValue>?[] entries;\n\n    /// <summary>\n    /// Gets the number of elements in the hash table.\n    /// </summary>\n    public int Count => size;\n\n    /// <summary>\n    /// Gets the capacity of the hash table.\n    /// </summary>\n    public int Capacity => capacity;\n\n    /// <summary>\n    /// Gets the load factor of the hash table.\n    /// </summary>\n    public float LoadFactor => loadFactor;\n\n    /// <summary>\n    /// Gets the keys in the hash table.\n    /// </summary>\n    public IEnumerable<TKey> Keys => entries.Where(e => e != null).Select(e => e!.Key!);\n\n    /// <summary>\n    /// Gets the values in the hash table.\n    /// </summary>\n    public IEnumerable<TValue> Values => entries.Where(e => e != null).Select(e => e!.Value!);\n\n    /// <summary>\n    /// Gets or sets the value associated with the specified key.\n    /// </summary>\n    /// <param name=\"key\">Key to get or set.</param>\n    /// <returns>Value associated with the key.</returns>\n    public TValue this[TKey? key]\n    {\n        get\n        {\n            if (EqualityComparer<TKey>.Default.Equals(key, default))\n            {\n                throw new ArgumentNullException(nameof(key));\n            }\n\n            var entry = FindEntry(key)\n                ?? throw new KeyNotFoundException();\n            return entry.Value!;\n        }\n\n        set\n        {\n            if (EqualityComparer<TKey>.Default.Equals(key, default))\n            {\n                throw new ArgumentNullException(nameof(key));\n            }\n\n            var entry = FindEntry(key)\n                ?? throw new KeyNotFoundException();\n            entry.Value = value;\n        }\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"HashTable{TKey, TValue}\"/> class.\n    /// </summary>\n    /// <param name=\"capacity\">Initial capacity of the hash table.</param>\n    /// <param name=\"loadFactor\">Load factor of the hash table.</param>\n    /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when <paramref name=\"capacity\"/> is less than or equal to 0.</exception>\n    /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when <paramref name=\"loadFactor\"/> is less than or equal to 0.</exception>\n    /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when <paramref name=\"loadFactor\"/> is greater than 1.</exception>\n    /// <remarks>\n    /// <paramref name=\"capacity\"/> is rounded to the next prime number.\n    /// </remarks>\n    /// <see cref=\"PrimeNumber.NextPrime(int, int, bool)\"/>\n    /// <see cref=\"PrimeNumber.IsPrime(int)\"/>\n    public HashTable(int capacity = DefaultCapacity, float loadFactor = DefaultLoadFactor)\n    {\n        if (capacity <= 0)\n        {\n            throw new ArgumentOutOfRangeException(nameof(capacity), \"Capacity must be greater than 0\");\n        }\n\n        if (loadFactor <= 0)\n        {\n            throw new ArgumentOutOfRangeException(nameof(loadFactor), \"Load factor must be greater than 0\");\n        }\n\n        if (loadFactor > 1)\n        {\n            throw new ArgumentOutOfRangeException(nameof(loadFactor), \"Load factor must be less than or equal to 1\");\n        }\n\n        this.capacity = PrimeNumber.NextPrime(capacity);\n        this.loadFactor = loadFactor;\n        threshold = (int)(this.capacity * loadFactor);\n        entries = new Entry<TKey, TValue>[this.capacity];\n    }\n\n    /// <summary>\n    /// Adds a key-value pair to the hash table.\n    /// </summary>\n    /// <param name=\"key\">Key to add.</param>\n    /// <param name=\"value\">Value to add.</param>\n    /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"key\"/> is null.</exception>\n    /// <exception cref=\"ArgumentException\">Thrown when <paramref name=\"key\"/> already exists in the hash table.</exception>\n    /// <remarks>\n    /// If the number of elements in the hash table is greater than or equal to the threshold, the hash table is resized.\n    /// </remarks>\n    public void Add(TKey? key, TValue? value)\n    {\n        if (EqualityComparer<TKey>.Default.Equals(key, default))\n        {\n            throw new ArgumentNullException(nameof(key));\n        }\n\n        if (size >= threshold)\n        {\n            Resize();\n        }\n\n        var index = GetIndex(key);\n        if (entries[index] != null &&\n            EqualityComparer<TKey>.Default.Equals(entries[index]!.Key!, key))\n        {\n            throw new ArgumentException(\"Key already exists\");\n        }\n\n        if (EqualityComparer<TValue>.Default.Equals(value, default))\n        {\n            throw new ArgumentNullException(nameof(value));\n        }\n\n        entries[index] = new Entry<TKey, TValue>(key!, value!);\n        size++;\n    }\n\n    /// <summary>\n    /// Removes the key-value pair associated with the specified key.\n    /// </summary>\n    /// <param name=\"key\">Key to remove.</param>\n    /// <returns>True if the key-value pair was removed, false otherwise.</returns>\n    /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"key\"/> is null.</exception>\n    /// <remarks>\n    /// If the number of elements in the hash table is less than or equal to the threshold divided by 4, the hash table is resized.\n    /// </remarks>\n    public bool Remove(TKey? key)\n    {\n        if (EqualityComparer<TKey>.Default.Equals(key, default))\n        {\n            throw new ArgumentNullException(nameof(key));\n        }\n\n        var index = GetIndex(key);\n        if (entries[index] == null)\n        {\n            return false;\n        }\n\n        entries[index] = null;\n        size--;\n\n        if (size <= threshold / 4)\n        {\n            Resize();\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    /// Find the index of the entry associated with the specified key.\n    /// </summary>\n    /// <param name=\"key\">Key to find.</param>\n    /// <returns>Index of the entry associated with the key.</returns>\n    /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"key\"/> is null.</exception>\n    public int GetIndex(TKey? key)\n    {\n        if (EqualityComparer<TKey>.Default.Equals(key, default))\n        {\n            throw new ArgumentNullException(nameof(key));\n        }\n\n        var hash = key!.GetHashCode();\n        var index = hash % capacity;\n\n        if (index < 0)\n        {\n            index += capacity;\n        }\n\n        return index;\n    }\n\n    /// <summary>\n    /// Finds the entry associated with the specified key.\n    /// </summary>\n    /// <param name=\"key\">Key to find.</param>\n    /// <returns>Entry associated with the key.</returns>\n    /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"key\"/> is null.</exception>\n    /// <remarks>\n    /// This method uses <see cref=\"GetIndex(TKey)\"/> internally.\n    /// </remarks>\n    public Entry<TKey, TValue>? FindEntry(TKey? key)\n    {\n        if (EqualityComparer<TKey>.Default.Equals(key, default))\n        {\n            throw new ArgumentNullException(nameof(key));\n        }\n\n        var index = GetIndex(key);\n        return entries[index];\n    }\n\n    /// <summary>\n    /// Checks if the hash table contains the specified key.\n    /// </summary>\n    /// <param name=\"key\">Key to check.</param>\n    /// <returns>True if the hash table contains the key, false otherwise.</returns>\n    /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"key\"/> is null.</exception>\n    /// <remarks>\n    /// This method uses <see cref=\"FindEntry(TKey)\"/> internally.\n    /// </remarks>\n    public bool ContainsKey(TKey? key)\n    {\n        if (EqualityComparer<TKey>.Default.Equals(key, default))\n        {\n            throw new ArgumentNullException(nameof(key));\n        }\n\n        return FindEntry(key) != null;\n    }\n\n    /// <summary>\n    /// Checks if the hash table contains the specified value.\n    /// </summary>\n    /// <param name=\"value\">Value to check.</param>\n    /// <returns>True if the hash table contains the value, false otherwise.</returns>\n    public bool ContainsValue(TValue? value)\n    {\n        if (EqualityComparer<TValue>.Default.Equals(value, default))\n        {\n            throw new ArgumentNullException(nameof(value));\n        }\n\n        return entries.Any(e => e != null && e.Value!.Equals(value));\n    }\n\n    /// <summary>\n    /// Clears the hash table.\n    /// </summary>\n    /// <remarks>\n    /// This method resets the capacity of the hash table to the default capacity.\n    /// </remarks>\n    public void Clear()\n    {\n        capacity = DefaultCapacity;\n        threshold = (int)(capacity * loadFactor);\n        entries = new Entry<TKey, TValue>[capacity];\n        size = 0;\n    }\n\n    /// <summary>\n    /// Resizes the hash table.\n    /// </summary>\n    /// <remarks>\n    /// This method doubles or halves the capacity of the hash table and rehashes all the elements.\n    /// </remarks>\n    public void Resize()\n    {\n        var newCapacity = size <= threshold / 2\n            ? Math.Max(capacity / 2, DefaultCapacity)\n            : capacity * 2;\n        var newEntries = new Entry<TKey, TValue>[newCapacity];\n\n        foreach (var entry in entries)\n        {\n            if (entry == null)\n            {\n                continue;\n            }\n\n            var index = entry.Key!.GetHashCode() % newCapacity;\n            if (index < 0)\n            {\n                index += newCapacity;\n            }\n\n            newEntries[index] = entry;\n        }\n\n        capacity = newCapacity;\n        threshold = (int)(capacity * loadFactor);\n        entries = newEntries;\n    }\n}\n"
  },
  {
    "path": "DataStructures/Hashing/NumberTheory/PrimeNumber.cs",
    "content": "namespace DataStructures.Hashing.NumberTheory;\n\n/// <summary>\n/// Class for prime number operations.\n/// </summary>\n/// <remarks>\n/// A prime number is a natural number greater than 1 that is not a product of two smaller natural numbers.\n/// </remarks>\npublic static class PrimeNumber\n{\n    /// <summary>\n    /// Checks if a number is prime or not.\n    /// </summary>\n    /// <param name=\"number\">Number to check.</param>\n    /// <returns>True if number is prime, false otherwise.</returns>\n    public static bool IsPrime(int number)\n    {\n        if (number <= 1)\n        {\n            return false;\n        }\n\n        if (number <= 3)\n        {\n            return true;\n        }\n\n        if (number % 2 == 0 || number % 3 == 0)\n        {\n            return false;\n        }\n\n        for (int i = 5; i * i <= number; i += 6)\n        {\n            if (number % i == 0 || number % (i + 2) == 0)\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    /// Gets the next prime number.\n    /// </summary>\n    /// <param name=\"number\">Number to start from.</param>\n    /// <param name=\"factor\">Factor to multiply the number by.</param>\n    /// <param name=\"desc\">True to get the previous prime number, false otherwise.</param>\n    /// <returns>The next prime number.</returns>\n    public static int NextPrime(int number, int factor = 1, bool desc = false)\n    {\n        number = factor * number;\n        int firstValue = number;\n\n        while (!IsPrime(number))\n        {\n            number += desc ? -1 : 1;\n        }\n\n        if (number == firstValue)\n        {\n            return NextPrime(\n                number + (desc ? -1 : 1),\n                factor,\n                desc);\n        }\n\n        return number;\n    }\n}\n"
  },
  {
    "path": "DataStructures/Heap/BinaryHeap.cs",
    "content": "namespace DataStructures.Heap;\n\n/// <summary>\n///     A generic implementation of a binary heap.\n/// </summary>\n/// <remarks>\n///     A binary heap is a complete binary tree that satisfies the heap property;\n///     that is every node in the tree compares greater/less than or equal to its left and right\n///     child nodes. Note that this is different from a binary search tree, where every node\n///     must be the largest/smallest node of all of its children.\n///     Although binary heaps are not very efficient, they are (probably) the simpliest heaps\n///     to understand and implement.\n///     More information: https://en.wikipedia.org/wiki/Binary_heap .\n/// </remarks>\n/// <typeparam name=\"T\">Type of elements in binary heap.</typeparam>\npublic class BinaryHeap<T>\n{\n    /// <summary>\n    ///     Comparer to use when comparing elements.\n    /// </summary>\n    private readonly Comparer<T> comparer;\n\n    /// <summary>\n    ///     List to hold the elements of the heap.\n    /// </summary>\n    private readonly List<T> data;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"BinaryHeap{T}\" /> class.\n    /// </summary>\n    public BinaryHeap()\n    {\n        data = [];\n        comparer = Comparer<T>.Default;\n    }\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"BinaryHeap{T}\" /> class with a custom comparision function.\n    /// </summary>\n    /// <param name=\"customComparer\">The custom comparing function to use to compare elements.</param>\n    public BinaryHeap(Comparer<T> customComparer)\n    {\n        data = [];\n        comparer = customComparer;\n    }\n\n    /// <summary>\n    ///     Gets the number of elements in the heap.\n    /// </summary>\n    public int Count => data.Count;\n\n    /// <summary>\n    ///     Add an element to the binary heap.\n    /// </summary>\n    /// <remarks>\n    ///     Adding to the heap is done by append the element to the end of the backing list,\n    ///     and pushing the added element up until the heap property is restored.\n    /// </remarks>\n    /// <param name=\"element\">The element to add to the heap.</param>\n    /// <exception cref=\"ArgumentException\">Thrown if element is already in heap.</exception>\n    public void Push(T element)\n    {\n        data.Add(element);\n        HeapifyUp(data.Count - 1);\n    }\n\n    /// <summary>\n    ///     Remove the top/root of the binary heap (ie: the largest/smallest element).\n    /// </summary>\n    /// <remarks>\n    ///     Removing from the heap is done by swapping the top/root with the last element in\n    ///     the backing list, removing the last element, and pushing the new root down\n    ///     until the heap property is restored.\n    /// </remarks>\n    /// <returns>The top/root of the heap.</returns>\n    /// <exception cref=\"InvalidOperationException\">Thrown if heap is empty.</exception>\n    public T Pop()\n    {\n        if (Count == 0)\n        {\n            throw new InvalidOperationException(\"Heap is empty!\");\n        }\n\n        var elem = data[0];\n        data[0] = data[^1];\n        data.RemoveAt(data.Count - 1);\n        HeapifyDown(0);\n\n        return elem;\n    }\n\n    /// <summary>\n    ///     Return the top/root of the heap without removing it.\n    /// </summary>\n    /// <returns>The top/root of the heap.</returns>\n    /// <exception cref=\"InvalidOperationException\">Thrown if heap is empty.</exception>\n    public T Peek()\n    {\n        if (Count == 0)\n        {\n            throw new InvalidOperationException(\"Heap is empty!\");\n        }\n\n        return data[0];\n    }\n\n    /// <summary>\n    ///     Returns element if it compares larger to the top/root of the heap, else\n    ///     inserts element into the heap and returns the top/root of the heap.\n    /// </summary>\n    /// <param name=\"element\">The element to check/insert.</param>\n    /// <returns>element if element compares larger than top/root of heap, top/root of heap otherwise.</returns>\n    public T PushPop(T element)\n    {\n        if (Count == 0)\n        {\n            return element;\n        }\n\n        if (comparer.Compare(element, data[0]) < 0)\n        {\n            var tmp = data[0];\n            data[0] = element;\n            HeapifyDown(0);\n            return tmp;\n        }\n\n        return element;\n    }\n\n    /// <summary>\n    ///     Check if element is in the heap.\n    /// </summary>\n    /// <param name=\"element\">The element to check for.</param>\n    /// <returns>true if element is in the heap, false otherwise.</returns>\n    public bool Contains(T element) => data.Contains(element);\n\n    /// <summary>\n    ///     Remove an element from the heap.\n    /// </summary>\n    /// <remarks>\n    ///     In removing an element from anywhere in the heap, we only need to push down or up\n    ///     the replacement value depending on how the removed value compares to its\n    ///     replacement value.\n    /// </remarks>\n    /// <param name=\"element\">The element to remove from the heap.</param>\n    /// <exception cref=\"ArgumentException\">Thrown if element is not in heap.</exception>\n    public void Remove(T element)\n    {\n        var idx = data.IndexOf(element);\n\n        if (idx == -1)\n        {\n            throw new ArgumentException($\"{element} not in heap!\");\n        }\n\n        Swap(idx, data.Count - 1);\n        var tmp = data[^1];\n        data.RemoveAt(data.Count - 1);\n\n        if (idx < data.Count)\n        {\n            if (comparer.Compare(tmp, data[idx]) > 0)\n            {\n                HeapifyDown(idx);\n            }\n            else\n            {\n                HeapifyUp(idx);\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Swap the elements in the heap array at the given indices.\n    /// </summary>\n    /// <param name=\"idx1\">First index.</param>\n    /// <param name=\"idx2\">Second index.</param>\n    private void Swap(int idx1, int idx2)\n    {\n        var tmp = data[idx1];\n        data[idx1] = data[idx2];\n        data[idx2] = tmp;\n    }\n\n    /// <summary>\n    ///     Recursive function to restore heap properties.\n    /// </summary>\n    /// <remarks>\n    ///     Restores heap property by swapping the element at <paramref name=\"elemIdx\" />\n    ///     with its parent if the element compares greater than its parent.\n    /// </remarks>\n    /// <param name=\"elemIdx\">The element to check with its parent.</param>\n    private void HeapifyUp(int elemIdx)\n    {\n        var parent = (elemIdx - 1) / 2;\n\n        if (parent >= 0 && comparer.Compare(data[elemIdx], data[parent]) > 0)\n        {\n            Swap(elemIdx, parent);\n            HeapifyUp(parent);\n        }\n    }\n\n    /// <summary>\n    ///     Recursive function to restore heap properties.\n    /// </summary>\n    /// <remarks>\n    ///     Restores heap property by swapping the element at <paramref name=\"elemIdx\" />\n    ///     with the larger of its children.\n    /// </remarks>\n    /// <param name=\"elemIdx\">The element to check with its children.</param>\n    private void HeapifyDown(int elemIdx)\n    {\n        var left = 2 * elemIdx + 1;\n        var right = 2 * elemIdx + 2;\n\n        var leftLargerThanElem = left < Count && comparer.Compare(data[elemIdx], data[left]) < 0;\n        var rightLargerThanElem = right < Count && comparer.Compare(data[elemIdx], data[right]) < 0;\n        var leftLargerThanRight = left < Count && right < Count && comparer.Compare(data[left], data[right]) > 0;\n\n        if (leftLargerThanElem && leftLargerThanRight)\n        {\n            Swap(elemIdx, left);\n            HeapifyDown(left);\n        }\n        else if (rightLargerThanElem && !leftLargerThanRight)\n        {\n            Swap(elemIdx, right);\n            HeapifyDown(right);\n        }\n    }\n}\n"
  },
  {
    "path": "DataStructures/Heap/FibonacciHeap/FHeapNode.cs",
    "content": "namespace DataStructures.Heap.FibonacciHeap;\n\n/// <summary>\n///     These FHeapNodes are the bulk of the data structure. The have pointers to\n///     their parent, a left and right sibling, and to a child. A node and its\n///     siblings comprise a circularly doubly linked list.\n/// </summary>\n/// <typeparam name=\"T\">A type that can be compared.</typeparam>\npublic class FHeapNode<T> where T : IComparable\n{\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"FHeapNode{T}\" /> class.\n    /// </summary>\n    /// <param name=\"key\">An item in the Fibonacci heap.</param>\n    public FHeapNode(T key)\n    {\n        Key = key;\n\n        // Since even a single node must form a circularly doubly linked list,\n        // initialize it as such\n        Left = Right = this;\n        Parent = Child = null;\n    }\n\n    /// <summary>\n    ///     Gets or sets the data of this node.\n    /// </summary>\n    public T Key { get; set; }\n\n    /// <summary>\n    ///     Gets or sets a reference to the parent.\n    /// </summary>\n    public FHeapNode<T>? Parent { get; set; }\n\n    /// <summary>\n    ///     Gets or sets a reference to the left sibling.\n    /// </summary>\n    public FHeapNode<T> Left { get; set; }\n\n    /// <summary>\n    ///     Gets or sets a reference to the right sibling.\n    /// </summary>\n    public FHeapNode<T> Right { get; set; }\n\n    /// <summary>\n    ///     Gets or sets a reference to one of the children, there may be more that\n    ///     are siblings the this child, however this structure only maintains a\n    ///     reference to one of them.\n    /// </summary>\n    public FHeapNode<T>? Child { get; set; }\n\n    /// <summary>\n    ///     Gets or sets a value indicating whether this node has been marked,\n    ///     used in some operations.\n    /// </summary>\n    public bool Mark { get; set; }\n\n    /// <summary>\n    ///     Gets or sets the number of nodes in the child linked list.\n    /// </summary>\n    public int Degree { get; set; }\n\n    public void SetSiblings(FHeapNode<T> left, FHeapNode<T> right)\n    {\n        Left = left;\n        Right = right;\n    }\n\n    /// <summary>\n    ///     A helper function to add a node to the right of this one in the current\n    ///     circularly doubly linked list.\n    /// </summary>\n    /// <param name=\"node\">A node to go in the linked list.</param>\n    public void AddRight(FHeapNode<T> node)\n    {\n        Right.Left = node;\n        node.Right = Right;\n        node.Left = this;\n        Right = node;\n    }\n\n    /// <summary>\n    ///     Similar to AddRight, but adds the node as a sibling to the child node.\n    /// </summary>\n    /// <param name=\"node\">A node to add to the child list of this node.</param>\n    public void AddChild(FHeapNode<T> node)\n    {\n        Degree++;\n\n        if (Child == null)\n        {\n            Child = node;\n            Child.Parent = this;\n            Child.Left = Child.Right = Child;\n\n            return;\n        }\n\n        Child.AddRight(node);\n    }\n\n    /// <summary>\n    ///     Remove this item from the linked list it's in.\n    /// </summary>\n    public void Remove()\n    {\n        Left.Right = Right;\n        Right.Left = Left;\n    }\n\n    /// <summary>\n    ///     Combine the linked list that <c>otherList</c> sits inside, with the\n    ///     linked list this is in. Do this by cutting the link between this node,\n    ///     and the node to the right of this, and inserting the contents of the\n    ///     otherList in between.\n    /// </summary>\n    /// <param name=\"otherList\">\n    ///     A node from another list whose elements we want\n    ///     to concatenate to this list.\n    /// </param>\n    public void ConcatenateRight(FHeapNode<T> otherList)\n    {\n        Right.Left = otherList.Left;\n        otherList.Left.Right = Right;\n\n        Right = otherList;\n        otherList.Left = this;\n    }\n}\n"
  },
  {
    "path": "DataStructures/Heap/FibonacciHeap/FibonacciHeap.cs",
    "content": "namespace DataStructures.Heap.FibonacciHeap;\n\n/// <summary>\n///     A generic implementation of a Fibonacci heap.\n/// </summary>\n/// <remarks>\n///     <para>\n///         A Fibonacci heap is similar to a standard binary heap\n///         <see cref=\"DataStructures.Heap.BinaryHeap{T}\" />, however it uses concepts\n///         of amortized analysis to provide theoretical speedups on common operations like\n///         insert, union, and decrease-key while maintaining the same speed on all other\n///         operations.\n///     </para>\n///     <para>\n///         In practice, Fibonacci heaps are more complicated than binary heaps and require\n///         a large input problems before the benifits of the theoretical speed up\n///         begin to show.\n///     </para>\n///     <para>\n///         References:\n///         [1] Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest,\n///         and Clifford Stein. 2009. Introduction to Algorithms, Third Edition (3rd. ed.).\n///         The MIT Press.\n///     </para>\n/// </remarks>\n/// <typeparam name=\"T\">Type of elements in binary heap.</typeparam>\npublic class FibonacciHeap<T> where T : IComparable\n{\n    /// <summary>\n    ///     Gets or sets the count of the number of nodes in the Fibonacci heap.\n    /// </summary>\n    public int Count { get; set; }\n\n    /// <summary>\n    ///     Gets or sets a reference to the MinItem. The MinItem and all of its siblings\n    ///     comprise the root list, a list of trees that satisfy the heap property and\n    ///     are joined in a circularly doubly linked list.\n    /// </summary>\n    private FHeapNode<T>? MinItem { get; set; }\n\n    /// <summary>\n    ///     Add item <c>x</c> to this Fibonacci heap.\n    /// </summary>\n    /// <remarks>\n    ///     To add an item to a Fibonacci heap, we simply add it to the \"root list\",\n    ///     a circularly doubly linked list where our minimum item sits. Since adding\n    ///     items to a linked list takes O(1) time, the overall time to perform this\n    ///     operation is O(1).\n    /// </remarks>\n    /// <param name=\"x\">An item to push onto the heap.</param>\n    /// <returns>\n    ///     A reference to the item as it is in the heap. This is used for\n    ///     operations like decresing key.\n    /// </returns>\n    public FHeapNode<T> Push(T x)\n    {\n        Count++;\n\n        var newItem = new FHeapNode<T>(x);\n\n        if (MinItem == null)\n        {\n            MinItem = newItem;\n        }\n        else\n        {\n            MinItem.AddRight(newItem);\n\n            if (newItem.Key.CompareTo(MinItem.Key) < 0)\n            {\n                MinItem = newItem;\n            }\n        }\n\n        return newItem;\n    }\n\n    /// <summary>\n    ///     Combines all the elements of two fibonacci heaps.\n    /// </summary>\n    /// <remarks>\n    ///     To union two Fibonacci heaps is a single fibonacci heap is a single heap\n    ///     that contains all the elements of both heaps. This can be done in O(1) time\n    ///     by concatenating the root lists together.\n    ///     For more details on how two circularly linked lists are concatenated, see\n    ///     <see cref=\"FHeapNode{T}.ConcatenateRight\" />\n    ///     Finally, check to see which of <c>this.MinItem</c> and <c>other.MinItem</c>\n    ///     is smaller, and set <c>this.MinItem</c> accordingly\n    ///     This operation destroys <c>other</c>.\n    /// </remarks>\n    /// <param name=\"other\">\n    ///     Another heap whose elements we wish to add to this heap.\n    ///     The other heap will be destroyed as a result.\n    /// </param>\n    public void Union(FibonacciHeap<T> other)\n    {\n        // If there are no items in the other heap, then there is nothing to do.\n        if (other.MinItem == null)\n        {\n            return;\n        }\n\n        // If this heap is empty, simply set it equal to the other heap\n        if (MinItem == null)\n        {\n            // Set this heap to the other one\n            MinItem = other.MinItem;\n            Count = other.Count;\n\n            // Destroy the other heap\n            other.MinItem = null;\n            other.Count = 0;\n\n            return;\n        }\n\n        Count += other.Count;\n\n        // <see cref=\"DataStructures.FibonacciHeap{T}.FHeapNode.ConcatenateRight(DataStructures.FibonacciHeap{T}.FHeapNode)\"/>\n        MinItem.ConcatenateRight(other.MinItem);\n\n        // Set the MinItem to the smaller of the two MinItems\n        if (other.MinItem.Key.CompareTo(MinItem.Key) < 0)\n        {\n            MinItem = other.MinItem;\n        }\n\n        other.MinItem = null;\n        other.Count = 0;\n    }\n\n    /// <summary>\n    ///     Return the MinItem and remove it from the heap.\n    /// </summary>\n    /// <remarks>\n    ///     This function (with all of its helper functions) is the most complicated\n    ///     part of the Fibonacci Heap. However, it can be broken down into a few steps.\n    ///     <list type=\"number\">\n    ///         <item>\n    ///             Add the children of MinItem to the root list. Either one of these children,\n    ///             or another of the items in the root list is a candidate to become the new\n    ///             MinItem.\n    ///         </item>\n    ///         <item>\n    ///             Remove the MinItem from the root list and appoint a new MinItem temporarily.\n    ///         </item>\n    ///         <item>\n    ///             <see cref=\"Consolidate\" /> what's left\n    ///             of the heap.\n    ///         </item>\n    ///     </list>\n    /// </remarks>\n    /// <returns>The minimum item from the heap.</returns>\n    public T Pop()\n    {\n        FHeapNode<T>? z = null;\n        if (MinItem == null)\n        {\n            throw new InvalidOperationException(\"Heap is empty!\");\n        }\n\n        z = MinItem;\n\n        // Since z is leaving the heap, add its children to the root list\n        if (z.Child != null)\n        {\n            foreach (var x in SiblingIterator(z.Child))\n            {\n                x.Parent = null;\n            }\n\n            // This effectively adds each child x to the root list\n            z.ConcatenateRight(z.Child);\n        }\n\n        if (Count == 1)\n        {\n            MinItem = null;\n            Count = 0;\n            return z.Key;\n        }\n\n        // Temporarily reassign MinItem to an arbitrary item in the root\n        // list\n        MinItem = MinItem.Right;\n\n        // Remove the old MinItem from the root list altogether\n        z.Remove();\n\n        // Consolidate the heap\n        Consolidate();\n\n        Count -= 1;\n\n        return z.Key;\n    }\n\n    /// <summary>\n    ///     A method to see what's on top of the heap without changing its structure.\n    /// </summary>\n    /// <returns>\n    ///     Returns the top element without popping it from the structure of\n    ///     the heap.\n    /// </returns>\n    public T Peek()\n    {\n        if (MinItem == null)\n        {\n            throw new InvalidOperationException(\"The heap is empty\");\n        }\n\n        return MinItem.Key;\n    }\n\n    /// <summary>\n    ///     Reduce the key of x to be k.\n    /// </summary>\n    /// <remarks>\n    ///     k must be less than x.Key, increasing the key of an item is not supported.\n    /// </remarks>\n    /// <param name=\"x\">The item you want to reduce in value.</param>\n    /// <param name=\"k\">The new value for the item.</param>\n    public void DecreaseKey(FHeapNode<T> x, T k)\n    {\n        if (MinItem == null)\n        {\n            throw new ArgumentException($\"{nameof(x)} is not from the heap\");\n        }\n\n        if (x.Key == null)\n        {\n            throw new ArgumentException(\"x has no value\");\n        }\n\n        if (k.CompareTo(x.Key) > 0)\n        {\n            throw new InvalidOperationException(\"Value cannot be increased\");\n        }\n\n        x.Key = k;\n        var y = x.Parent;\n        if (y != null && x.Key.CompareTo(y.Key) < 0)\n        {\n            Cut(x, y);\n            CascadingCut(y);\n        }\n\n        if (x.Key.CompareTo(MinItem.Key) < 0)\n        {\n            MinItem = x;\n        }\n    }\n\n    /// <summary>\n    ///     Remove x from the child list of y.\n    /// </summary>\n    /// <param name=\"x\">A child of y we just decreased the value of.</param>\n    /// <param name=\"y\">The now former parent of x.</param>\n    protected void Cut(FHeapNode<T> x, FHeapNode<T> y)\n    {\n        if (MinItem == null)\n        {\n            throw new InvalidOperationException(\"Heap malformed\");\n        }\n\n        if (y.Degree == 1)\n        {\n            y.Child = null;\n            MinItem.AddRight(x);\n        }\n        else if (y.Degree > 1)\n        {\n            x.Remove();\n        }\n        else\n        {\n            throw new InvalidOperationException(\"Heap malformed\");\n        }\n\n        y.Degree--;\n        x.Mark = false;\n        x.Parent = null;\n    }\n\n    /// <summary>\n    ///     Rebalances the heap after the decrease operation takes place.\n    /// </summary>\n    /// <param name=\"y\">An item that may no longer obey the heap property.</param>\n    protected void CascadingCut(FHeapNode<T> y)\n    {\n        var z = y.Parent;\n        if (z != null)\n        {\n            if (!y.Mark)\n            {\n                y.Mark = true;\n            }\n            else\n            {\n                Cut(y, z);\n                CascadingCut(z);\n            }\n        }\n    }\n\n    /// <summary>\n    ///     <para>\n    ///         Consolidate is analogous to Heapify in <see cref=\"DataStructures.Heap.BinaryHeap{T}\" />.\n    ///     </para>\n    ///     <para>\n    ///         First, an array <c>A</c> [0...D(H.n)] is created where H.n is the number\n    ///         of items in this heap, and D(x) is the max degree any node can have in a\n    ///         Fibonacci heap with x nodes.\n    ///     </para>\n    ///     <para>\n    ///         For each node <c>x</c> in the root list, try to add it to <c>A[d]</c> where\n    ///         d is the degree of <c>x</c>.\n    ///         If there is already a node in <c>A[d]</c>, call it <c>y</c>, and make\n    ///         <c>y</c> a child of <c>x</c>. (Swap <c>x</c> and <c>y</c> beforehand if\n    ///         <c>x</c> is greater than <c>y</c>). Now that <c>x</c> has one more child,\n    ///         remove if from <c>A[d]</c> and add it to <c>A[d+1]</c> to reflect that its\n    ///         degree is one more. Loop this behavior until we find an empty spot to put\n    ///         <c>x</c>.\n    ///     </para>\n    ///     <para>\n    ///         With <c>A</c> all filled, empty the root list of the heap. And add each item\n    ///         from <c>A</c> into the root list, one by one, making sure to keep track of\n    ///         which is smallest.\n    ///     </para>\n    /// </summary>\n    protected void Consolidate()\n    {\n        if (MinItem == null)\n        {\n            return;\n        }\n\n        // There's a fact in Intro to Algorithms:\n        // \"the max degree of any node in an n-node fibonacci heap is O(lg(n)).\n        // In particular, we shall show that D(n) <= floor(log_phi(n)) where phi is\n        // the golden ratio, defined in equation 3.24 as phi = (1 + sqrt(5))/2\"\n        //\n        // For a proof, see [1]\n        var maxDegree = 1 + (int)Math.Log(Count, (1 + Math.Sqrt(5)) / 2);\n\n        // Create slots for every possible node degree of x\n        var a = new FHeapNode<T>?[maxDegree];\n        var siblings = SiblingIterator(MinItem).ToList();\n        foreach (var w in siblings)\n        {\n            var x = w;\n            var d = x.Degree;\n\n            var y = a[d];\n\n            // While A[d] is not empty, we can't blindly put x here\n            while (y != null)\n            {\n                if (x.Key.CompareTo(y.Key) > 0)\n                {\n                    // Exchange x and y\n                    var temp = x;\n                    x = y;\n                    y = temp;\n                }\n\n                // Make y a child of x\n                FibHeapLink(y, x);\n\n                // Empty out this spot since x now has a higher degree\n                a[d] = null;\n\n                // Add 1 to x's degree before going back into the loop\n                d++;\n\n                y = a[d];\n            }\n\n            // Now that there's an empty spot for x, place it there\n            a[d] = x;\n        }\n\n        ReconstructHeap(a);\n    }\n\n    /// <summary>\n    ///     Reconstructs the heap based on the array of node degrees created by the consolidate step.\n    /// </summary>\n    /// <param name=\"a\">An array of FHeapNodes where a[i] represents a node of degree i.</param>\n    private void ReconstructHeap(FHeapNode<T>?[] a)\n    {\n        // Once all items are in A, empty out the root list\n        MinItem = null;\n\n        for (var i = 0; i < a.Length; i++)\n        {\n            var r = a[i];\n            if (r == null)\n            {\n                continue;\n            }\n\n            if (MinItem == null)\n            {\n                // If the root list is completely empty, make this the new\n                // MinItem\n                MinItem = r;\n\n                // Make a new root list with just this item. Make sure to make\n                // it its own list.\n                MinItem.SetSiblings(MinItem, MinItem);\n                MinItem.Parent = null;\n            }\n            else\n            {\n                // Add A[i] to the root list\n                MinItem.AddRight(r);\n\n                // If this item is smaller, make it the new min item\n                if (MinItem.Key.CompareTo(r.Key) > 0)\n                {\n                    MinItem = a[i];\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Make y a child of x.\n    /// </summary>\n    /// <param name=\"y\">A node to become the child of x.</param>\n    /// <param name=\"x\">A node to become the parent of y.</param>\n    private void FibHeapLink(FHeapNode<T> y, FHeapNode<T> x)\n    {\n        y.Remove();\n        x.AddChild(y);\n        y.Mark = false;\n    }\n\n    /// <summary>\n    ///     A helper function to iterate through all the siblings of this node in the\n    ///     circularly doubly linked list.\n    /// </summary>\n    /// <param name=\"node\">A node we want the siblings of.</param>\n    /// <returns>An iterator over all of the siblings.</returns>\n    private IEnumerable<FHeapNode<T>> SiblingIterator(FHeapNode<T> node)\n    {\n        var currentNode = node;\n        yield return currentNode;\n\n        currentNode = node.Right;\n        while (currentNode != node)\n        {\n            yield return currentNode;\n            currentNode = currentNode.Right;\n        }\n    }\n}\n"
  },
  {
    "path": "DataStructures/Heap/MinMaxHeap.cs",
    "content": "namespace DataStructures.Heap;\n\n/// <summary>\n///     This class implements min-max heap.\n///     It provides functionality of both min-heap and max-heap with the same time complexity.\n///     Therefore it provides constant time retrieval and logarithmic time removal\n///     of both the minimum and maximum elements in it.\n/// </summary>\n/// <typeparam name=\"T\">Generic type.</typeparam>\npublic class MinMaxHeap<T>\n{\n    private readonly List<T> heap;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"MinMaxHeap{T}\" /> class that contains\n    ///     elements copied from a specified enumerable collection and that uses a specified comparer.\n    /// </summary>\n    /// <param name=\"collection\">The enumerable collection to be copied.</param>\n    /// <param name=\"comparer\">The default comparer to use for comparing objects.</param>\n    public MinMaxHeap(IEnumerable<T>? collection = null, IComparer<T>? comparer = null)\n    {\n        Comparer = comparer ?? Comparer<T>.Default;\n        collection ??= Enumerable.Empty<T>();\n\n        heap = collection.ToList();\n        for (var i = Count / 2 - 1; i >= 0; --i)\n        {\n            PushDown(i);\n        }\n    }\n\n    /// <summary>\n    ///     Gets the  <see cref=\"IComparer{T}\" />. object that is used to order the values in the <see cref=\"MinMaxHeap{T}\" />.\n    /// </summary>\n    public IComparer<T> Comparer { get; }\n\n    /// <summary>\n    ///     Gets the number of elements in the <see cref=\"MinMaxHeap{T}\" />.\n    /// </summary>\n    public int Count => heap.Count;\n\n    /// <summary>\n    ///     Adds an element to the heap.\n    /// </summary>\n    /// <param name=\"item\">The element to add to the heap.</param>\n    public void Add(T item)\n    {\n        heap.Add(item);\n        PushUp(Count - 1);\n    }\n\n    /// <summary>\n    ///     Removes the maximum node from the heap and returns its value.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown if heap is empty.</exception>\n    /// <returns>Value of the removed maximum node.</returns>\n    public T ExtractMax()\n    {\n        if (Count == 0)\n        {\n            throw new InvalidOperationException(\"Heap is empty\");\n        }\n\n        var max = GetMax();\n        RemoveNode(GetMaxNodeIndex());\n        return max;\n    }\n\n    /// <summary>\n    ///     Removes the minimum node from the heap and returns its value.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown if heap is empty.</exception>\n    /// <returns>Value of the removed minimum node.</returns>\n    public T ExtractMin()\n    {\n        if (Count == 0)\n        {\n            throw new InvalidOperationException(\"Heap is empty\");\n        }\n\n        var min = GetMin();\n        RemoveNode(0);\n        return min;\n    }\n\n    /// <summary>\n    ///     Gets the maximum value in the heap, as defined by the comparer.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown if heap is empty.</exception>\n    /// <returns>The maximum value in the heap.</returns>\n    public T GetMax()\n    {\n        if (Count == 0)\n        {\n            throw new InvalidOperationException(\"Heap is empty\");\n        }\n\n        return heap[GetMaxNodeIndex()];\n    }\n\n    /// <summary>\n    ///     Gets the minimum value in the heap, as defined by the comparer.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown if heap is empty.</exception>\n    /// <returns>The minimum value in the heap.</returns>\n    public T GetMin()\n    {\n        if (Count == 0)\n        {\n            throw new InvalidOperationException(\"Heap is empty\");\n        }\n\n        return heap[0];\n    }\n\n    /// <summary>\n    ///     Finds maximum value among children and grandchildren of the specified node.\n    /// </summary>\n    /// <param name=\"index\">Index of the node in the Heap array.</param>\n    /// <returns>Index of the maximum descendant.</returns>\n    private int IndexOfMaxChildOrGrandchild(int index)\n    {\n        var descendants = new[]\n        {\n            2 * index + 1,\n            2 * index + 2,\n            4 * index + 3,\n            4 * index + 4,\n            4 * index + 5,\n            4 * index + 6,\n        };\n        var resIndex = descendants[0];\n        foreach (var descendant in descendants)\n        {\n            if (descendant >= Count)\n            {\n                break;\n            }\n\n            if (Comparer.Compare(heap[descendant], heap[resIndex]) > 0)\n            {\n                resIndex = descendant;\n            }\n        }\n\n        return resIndex;\n    }\n\n    /// <summary>\n    ///     Finds minumum value among children and grandchildren of the specified node.\n    /// </summary>\n    /// <param name=\"index\">Index of the node in the Heap array.</param>\n    /// <returns>Index of the minimum descendant.</returns>\n    private int IndexOfMinChildOrGrandchild(int index)\n    {\n        var descendants = new[] { 2 * index + 1, 2 * index + 2, 4 * index + 3, 4 * index + 4, 4 * index + 5, 4 * index + 6 };\n        var resIndex = descendants[0];\n        foreach (var descendant in descendants)\n        {\n            if (descendant >= Count)\n            {\n                break;\n            }\n\n            if (Comparer.Compare(heap[descendant], heap[resIndex]) < 0)\n            {\n                resIndex = descendant;\n            }\n        }\n\n        return resIndex;\n    }\n\n    private int GetMaxNodeIndex()\n    {\n        return Count switch\n        {\n            0 => throw new InvalidOperationException(\"Heap is empty\"),\n            1 => 0,\n            2 => 1,\n            _ => Comparer.Compare(heap[1], heap[2]) > 0 ? 1 : 2,\n        };\n    }\n\n    private bool HasChild(int index) => index * 2 + 1 < Count;\n\n    private bool IsGrandchild(int node, int grandchild) => grandchild > 2 && Grandparent(grandchild) == node;\n\n    /// <summary>\n    ///     Checks if node at index belongs to Min or Max level of the heap.\n    ///     Root node belongs to Min level, its children - Max level,\n    ///     its grandchildren - Min level, and so on.\n    /// </summary>\n    /// <param name=\"index\">Index to check.</param>\n    /// <returns>true if index is at Min level; false if it is at Max Level.</returns>\n    private bool IsMinLevelIndex(int index)\n    {\n        // For all Min levels, value (index + 1) has the leftmost bit set to '1' at even position.\n        const uint minLevelsBits = 0x55555555;\n        const uint maxLevelsBits = 0xAAAAAAAA;\n        return ((index + 1) & minLevelsBits) > ((index + 1) & maxLevelsBits);\n    }\n\n    private int Parent(int index) => (index - 1) / 2;\n\n    private int Grandparent(int index) => ((index - 1) / 2 - 1) / 2;\n\n    /// <summary>\n    ///     Assuming that children sub-trees are valid heaps, pushes node to lower levels\n    ///     to make heap valid.\n    /// </summary>\n    /// <param name=\"index\">Node index.</param>\n    private void PushDown(int index)\n    {\n        if (IsMinLevelIndex(index))\n        {\n            PushDownMin(index);\n        }\n        else\n        {\n            PushDownMax(index);\n        }\n    }\n\n    private void PushDownMax(int index)\n    {\n        if (!HasChild(index))\n        {\n            return;\n        }\n\n        var maxIndex = IndexOfMaxChildOrGrandchild(index);\n\n        // If smaller element are put at min level (as result of swaping), it doesn't affect sub-tree validity.\n        // If smaller element are put at max level, PushDownMax() should be called for that node.\n        if (IsGrandchild(index, maxIndex))\n        {\n            if (Comparer.Compare(heap[maxIndex], heap[index]) > 0)\n            {\n                SwapNodes(maxIndex, index);\n                if (Comparer.Compare(heap[maxIndex], heap[Parent(maxIndex)]) < 0)\n                {\n                    SwapNodes(maxIndex, Parent(maxIndex));\n                }\n\n                PushDownMax(maxIndex);\n            }\n        }\n        else\n        {\n            if (Comparer.Compare(heap[maxIndex], heap[index]) > 0)\n            {\n                SwapNodes(maxIndex, index);\n            }\n        }\n    }\n\n    private void PushDownMin(int index)\n    {\n        if (!HasChild(index))\n        {\n            return;\n        }\n\n        var minIndex = IndexOfMinChildOrGrandchild(index);\n\n        // If bigger element are put at max level (as result of swaping), it doesn't affect sub-tree validity.\n        // If bigger element are put at min level, PushDownMin() should be called for that node.\n        if (IsGrandchild(index, minIndex))\n        {\n            if (Comparer.Compare(heap[minIndex], heap[index]) < 0)\n            {\n                SwapNodes(minIndex, index);\n                if (Comparer.Compare(heap[minIndex], heap[Parent(minIndex)]) > 0)\n                {\n                    SwapNodes(minIndex, Parent(minIndex));\n                }\n\n                PushDownMin(minIndex);\n            }\n        }\n        else\n        {\n            if (Comparer.Compare(heap[minIndex], heap[index]) < 0)\n            {\n                SwapNodes(minIndex, index);\n            }\n        }\n    }\n\n    /// <summary>\n    ///     Having a new node in the heap, swaps this node with its ancestors to make heap valid.\n    ///     For node at min level. If new node is less than its parent, then it is surely less then\n    ///     all other nodes on max levels on path to the root of the heap. So node are pushed up, by\n    ///     swaping with its grandparent, until they are ordered correctly.\n    ///     For node at max level algorithm is analogical.\n    /// </summary>\n    /// <param name=\"index\">Index of the new node.</param>\n    private void PushUp(int index)\n    {\n        if (index == 0)\n        {\n            return;\n        }\n\n        var parent = Parent(index);\n\n        if (IsMinLevelIndex(index))\n        {\n            if (Comparer.Compare(heap[index], heap[parent]) > 0)\n            {\n                SwapNodes(index, parent);\n                PushUpMax(parent);\n            }\n            else\n            {\n                PushUpMin(index);\n            }\n        }\n        else\n        {\n            if (Comparer.Compare(heap[index], heap[parent]) < 0)\n            {\n                SwapNodes(index, parent);\n                PushUpMin(parent);\n            }\n            else\n            {\n                PushUpMax(index);\n            }\n        }\n    }\n\n    private void PushUpMax(int index)\n    {\n        if (index > 2)\n        {\n            var grandparent = Grandparent(index);\n            if (Comparer.Compare(heap[index], heap[grandparent]) > 0)\n            {\n                SwapNodes(index, grandparent);\n                PushUpMax(grandparent);\n            }\n        }\n    }\n\n    private void PushUpMin(int index)\n    {\n        if (index > 2)\n        {\n            var grandparent = Grandparent(index);\n            if (Comparer.Compare(heap[index], heap[grandparent]) < 0)\n            {\n                SwapNodes(index, grandparent);\n                PushUpMin(grandparent);\n            }\n        }\n    }\n\n    private void RemoveNode(int index)\n    {\n        SwapNodes(index, Count - 1);\n        heap.RemoveAt(Count - 1);\n        if (Count != 0)\n        {\n            PushDown(index);\n        }\n    }\n\n    private void SwapNodes(int i, int j)\n    {\n        var temp = heap[i];\n        heap[i] = heap[j];\n        heap[j] = temp;\n    }\n}\n"
  },
  {
    "path": "DataStructures/Heap/PairingHeap/PairingHeap.cs",
    "content": "using System.Collections;\n\nnamespace DataStructures.Heap.PairingHeap;\n\n/// <summary>\n/// A pairing minMax heap implementation.\n/// </summary>\n/// <typeparam name=\"T\">Base type.</typeparam>\npublic class PairingHeap<T>(Sorting sortDirection = Sorting.Ascending) : IEnumerable<T> where T : IComparable\n{\n    private readonly Sorting sorting = sortDirection;\n    private readonly IComparer<T> comparer = new PairingNodeComparer<T>(sortDirection, Comparer<T>.Default);\n    private readonly Dictionary<T, List<PairingHeapNode<T>>> mapping = [];\n\n    private PairingHeapNode<T> root = null!;\n\n    public int Count { get; private set; }\n\n    /// <summary>\n    /// Insert a new Node [O(1)].\n    /// </summary>\n    public void Insert(T newItem)\n    {\n        var newNode = new PairingHeapNode<T>(newItem);\n\n        root = RebuildHeap(root, newNode);\n        Map(newItem, newNode);\n\n        Count++;\n    }\n\n    /// <summary>\n    /// Get the element from heap [O(log(n))].\n    /// </summary>\n    public T Extract()\n    {\n        var minMax = root;\n\n        RemoveMapping(minMax.Value, minMax);\n        RebuildHeap(root.ChildrenHead);\n\n        Count--;\n        return minMax.Value;\n    }\n\n    /// <summary>\n    /// Update heap key [O(log(n))].\n    /// </summary>\n    public void UpdateKey(T currentValue, T newValue)\n    {\n        if (!mapping.ContainsKey(currentValue))\n        {\n            throw new ArgumentException(\"Current value is not present in this heap.\");\n        }\n\n        var node = mapping[currentValue]?.Where(x => x.Value.Equals(currentValue)).FirstOrDefault();\n\n        if (comparer.Compare(newValue, node!.Value) > 0)\n        {\n            throw new ArgumentException($\"New value is not {(sorting != Sorting.Descending ? \"less\" : \"greater\")} than old value.\");\n        }\n\n        UpdateNodeValue(currentValue, newValue, node);\n\n        if (node == root)\n        {\n            return;\n        }\n\n        DeleteChild(node);\n\n        root = RebuildHeap(root, node);\n    }\n\n    IEnumerator IEnumerable.GetEnumerator()\n    {\n        return GetEnumerator();\n    }\n\n    public IEnumerator<T> GetEnumerator()\n    {\n        return mapping.SelectMany(x => x.Value).Select(x => x.Value).GetEnumerator();\n    }\n\n    /// <summary>\n    /// Rebuild heap on action [O(log(n))].\n    /// </summary>\n    private void RebuildHeap(PairingHeapNode<T> headNode)\n    {\n        if (headNode == null)\n        {\n            return;\n        }\n\n        var passOneResult = new List<PairingHeapNode<T>>();\n        var current = headNode;\n\n        if (current.Next == null)\n        {\n            headNode.Next = null!;\n            headNode.Previous = null!;\n            passOneResult.Add(headNode);\n        }\n        else\n        {\n            while (true)\n            {\n                if (current == null)\n                {\n                    break;\n                }\n\n                if (current.Next != null)\n                {\n                    var next = current.Next;\n                    var nextNext = next.Next;\n                    passOneResult.Add(RebuildHeap(current, next));\n                    current = nextNext;\n                }\n                else\n                {\n                    var lastInserted = passOneResult[^1];\n                    passOneResult[^1] = RebuildHeap(lastInserted, current);\n                    break;\n                }\n            }\n        }\n\n        var passTwoResult = passOneResult[^1];\n\n        if (passOneResult.Count == 1)\n        {\n            root = passTwoResult;\n            return;\n        }\n\n        for (var i = passOneResult.Count - 2; i >= 0; i--)\n        {\n            current = passOneResult[i];\n            passTwoResult = RebuildHeap(passTwoResult, current);\n        }\n\n        root = passTwoResult;\n    }\n\n    private PairingHeapNode<T> RebuildHeap(PairingHeapNode<T> node1, PairingHeapNode<T> node2)\n    {\n        if (node2 != null)\n        {\n            node2.Previous = null!;\n            node2.Next = null!;\n        }\n\n        if (node1 == null)\n        {\n            return node2!;\n        }\n\n        node1.Previous = null!;\n        node1.Next = null!;\n\n        if (node2 != null && comparer.Compare(node1.Value, node2.Value) <= 0)\n        {\n            AddChild(ref node1, node2);\n            return node1;\n        }\n\n        AddChild(ref node2!, node1);\n        return node2;\n    }\n\n    private void AddChild(ref PairingHeapNode<T> parent, PairingHeapNode<T> child)\n    {\n        if (parent.ChildrenHead == null)\n        {\n            parent.ChildrenHead = child;\n            child.Previous = parent;\n            return;\n        }\n\n        var head = parent.ChildrenHead;\n\n        child.Previous = head;\n        child.Next = head.Next;\n\n        if (head.Next != null)\n        {\n            head.Next.Previous = child;\n        }\n\n        head.Next = child;\n    }\n\n    private void DeleteChild(PairingHeapNode<T> node)\n    {\n        if (node.IsHeadChild)\n        {\n            var parent = node.Previous;\n\n            if (node.Next != null)\n            {\n                node.Next.Previous = parent;\n            }\n\n            parent.ChildrenHead = node.Next!;\n        }\n        else\n        {\n            node.Previous.Next = node.Next;\n\n            if (node.Next != null)\n            {\n                node.Next.Previous = node.Previous;\n            }\n        }\n    }\n\n    private void Map(T newItem, PairingHeapNode<T> newNode)\n    {\n        if (mapping.ContainsKey(newItem))\n        {\n            mapping[newItem].Add(newNode);\n        }\n        else\n        {\n            mapping[newItem] = [newNode];\n        }\n    }\n\n    private void UpdateNodeValue(T currentValue, T newValue, PairingHeapNode<T> node)\n    {\n        RemoveMapping(currentValue, node);\n        node.Value = newValue;\n        Map(newValue, node);\n    }\n\n    private void RemoveMapping(T currentValue, PairingHeapNode<T> node)\n    {\n        mapping[currentValue].Remove(node);\n        if (mapping[currentValue].Count == 0)\n        {\n            mapping.Remove(currentValue);\n        }\n    }\n}\n"
  },
  {
    "path": "DataStructures/Heap/PairingHeap/PairingHeapNode.cs",
    "content": "namespace DataStructures.Heap.PairingHeap;\n\n/// <summary>\n/// Node represented the value and connections.\n/// </summary>\n/// <typeparam name=\"T\">Type, supported comparing.</typeparam>\npublic class PairingHeapNode<T>(T value)\n{\n    public T Value { get; set; } = value;\n\n    public PairingHeapNode<T> ChildrenHead { get; set; } = null!;\n\n    public bool IsHeadChild => Previous != null && Previous.ChildrenHead == this;\n\n    public PairingHeapNode<T> Previous { get; set; } = null!;\n\n    public PairingHeapNode<T> Next { get; set; } = null!;\n}\n"
  },
  {
    "path": "DataStructures/Heap/PairingHeap/PairingNodeComparer.cs",
    "content": "namespace DataStructures.Heap.PairingHeap;\n\n/// <summary>\n/// Node comparer.\n/// </summary>\n/// <typeparam name=\"T\">Node type.</typeparam>\npublic class PairingNodeComparer<T>(Sorting sortDirection, IComparer<T> comparer) : IComparer<T> where T : IComparable\n{\n    private readonly bool isMax = sortDirection == Sorting.Descending;\n    private readonly IComparer<T> nodeComparer = comparer;\n\n    public int Compare(T? x, T? y)\n    {\n        return !isMax\n            ? CompareNodes(x, y)\n            : CompareNodes(y, x);\n    }\n\n    private int CompareNodes(T? one, T? second)\n    {\n        return nodeComparer.Compare(one, second);\n    }\n}\n"
  },
  {
    "path": "DataStructures/Heap/PairingHeap/Sorting.cs",
    "content": "namespace DataStructures.Heap.PairingHeap;\n\npublic enum Sorting\n{\n    /// <summary>\n    /// Ascending order.\n    /// </summary>\n    Ascending = 0,\n\n    /// <summary>\n    /// Descending order.\n    /// </summary>\n    Descending = 1,\n}\n"
  },
  {
    "path": "DataStructures/InvertedIndex.cs",
    "content": "namespace DataStructures;\n\n/// <summary>\n/// Inverted index is the simplest form of document indexing,\n/// allowing performing boolean queries on text data.\n///\n/// This realization is just simplified for better understanding the process of indexing\n/// and working on straightforward string inputs.\n/// </summary>\npublic class InvertedIndex\n{\n    private readonly Dictionary<string, List<string>> invertedIndex = [];\n\n    /// <summary>\n    /// Build inverted index with source name and source content.\n    /// </summary>\n    /// <param name=\"sourceName\">Name of the source.</param>\n    /// <param name=\"sourceContent\">Content of the source.</param>\n    public void AddToIndex(string sourceName, string sourceContent)\n    {\n        var context = sourceContent.Split(' ').Distinct();\n        foreach (var word in context)\n        {\n            if (!invertedIndex.ContainsKey(word))\n            {\n                invertedIndex.Add(word, [sourceName]);\n            }\n            else\n            {\n                invertedIndex[word].Add(sourceName);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Returns the source names contains ALL terms inside at same time.\n    /// </summary>\n    /// <param name=\"terms\">List of terms.</param>\n    /// <returns>Source names.</returns>\n    public IEnumerable<string> And(IEnumerable<string> terms)\n    {\n        var entries = terms\n            .Select(term => invertedIndex\n                .Where(x => x.Key.Equals(term))\n                .SelectMany(x => x.Value))\n            .ToList();\n\n        var intersection = entries\n            .Skip(1)\n            .Aggregate(new HashSet<string>(entries.First()), (hashSet, enumerable) =>\n            {\n                hashSet.IntersectWith(enumerable);\n                return hashSet;\n            });\n\n        return intersection;\n    }\n\n    /// <summary>\n    /// Returns the source names contains AT LEAST ONE from terms inside.\n    /// </summary>\n    /// <param name=\"terms\">List of terms.</param>\n    /// <returns>Source names.</returns>\n    public IEnumerable<string> Or(IEnumerable<string> terms)\n    {\n        var sources = new List<string>();\n        foreach (var term in terms)\n        {\n            var source = invertedIndex\n                .Where(x => x.Key.Equals(term))\n                .SelectMany(x => x.Value);\n\n            sources.AddRange(source);\n        }\n\n        return sources.Distinct();\n    }\n}\n"
  },
  {
    "path": "DataStructures/LinkedList/CircularLinkedList/CircularLinkedList.cs",
    "content": "namespace DataStructures.LinkedList.CircularLinkedList\n{\n    /// <summary>\n    /// CircularLinkedList.\n    /// @author Mohit Singh. <a href=\"https://github.com/mohit-gogitter\">mohit-gogitter</a>\n    /// </summary>\n    /// <typeparam name=\"T\">The generic type parameter.</typeparam>\n    public class CircularLinkedList<T>\n    {\n        /// <summary>\n        /// Points to the last node in the Circular Linked List.\n        /// </summary>\n        private CircularLinkedListNode<T>? tail;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CircularLinkedList{T}\"/> class.\n        /// </summary>\n        public CircularLinkedList()\n        {\n            tail = null;\n        }\n\n        /// <summary>\n        /// Gets the head node (tail.Next) of the Circular Linked List.\n        /// </summary>\n        public CircularLinkedListNode<T>? GetHead()\n        {\n            return tail?.Next;\n        }\n\n        /// <summary>\n        /// Determines whether the Circular Linked List is empty.\n        /// </summary>\n        /// <returns>True if the list is empty; otherwise, false.</returns>\n        public bool IsEmpty()\n        {\n            return tail == null;\n        }\n\n        /// <summary>\n        /// Inserts a new node at the beginning of the Circular Linked List.\n        /// </summary>\n        /// <param name=\"data\">The data to insert into the new node.</param>\n        public void InsertAtBeginning(T data)\n        {\n            var newNode = new CircularLinkedListNode<T>(data);\n            if (IsEmpty())\n            {\n                tail = newNode;\n                tail.Next = tail;\n            }\n            else\n            {\n                newNode.Next = tail!.Next;\n                tail.Next = newNode;\n            }\n        }\n\n        /// <summary>\n        /// Inserts a new node at the end of the Circular Linked List.\n        /// </summary>\n        /// <param name=\"data\">The data to insert into the new node.</param>\n        public void InsertAtEnd(T data)\n        {\n            var newNode = new CircularLinkedListNode<T>(data);\n            if (IsEmpty())\n            {\n                tail = newNode;\n                tail.Next = tail;\n            }\n            else\n            {\n                newNode.Next = tail!.Next;\n                tail.Next = newNode;\n                tail = newNode;\n            }\n        }\n\n        /// <summary>\n        /// Inserts a new node after a specific value in the list.\n        /// </summary>\n        /// <param name=\"value\">The value to insert the node after.</param>\n        /// <param name=\"data\">The data to insert into the new node.</param>\n        public void InsertAfter(T value, T data)\n        {\n            if (IsEmpty())\n            {\n                throw new InvalidOperationException(\"List is empty.\");\n            }\n\n            var current = tail!.Next;\n            do\n            {\n                if (current!.Data!.Equals(value))\n                {\n                    var newNode = new CircularLinkedListNode<T>(data);\n                    newNode.Next = current.Next;\n                    current.Next = newNode;\n\n                    return;\n                }\n\n                current = current.Next;\n            }\n            while (current != tail.Next);\n        }\n\n        /// <summary>\n        /// Deletes a node with a specific value from the list.\n        /// </summary>\n        /// <param name=\"value\">The value of the node to delete.</param>\n        public void DeleteNode(T value)\n        {\n            if (IsEmpty())\n            {\n                throw new InvalidOperationException(\"List is empty.\");\n            }\n\n            var current = tail!.Next;\n            var previous = tail;\n\n            do\n            {\n                if (current!.Data!.Equals(value))\n                {\n                    if (current == tail && current.Next == tail)\n                    {\n                        tail = null;\n                    }\n                    else if (current == tail)\n                    {\n                        previous!.Next = tail.Next;\n                        tail = previous;\n                    }\n                    else if (current == tail.Next)\n                    {\n                        tail.Next = current.Next;\n                    }\n                    else\n                    {\n                        previous!.Next = current.Next;\n                    }\n\n                    return;\n                }\n\n                previous = current;\n                current = current.Next;\n            }\n            while (current != tail!.Next);\n        }\n    }\n}\n"
  },
  {
    "path": "DataStructures/LinkedList/CircularLinkedList/CircularLinkedListNode.cs",
    "content": "namespace DataStructures.LinkedList.CircularLinkedList\n{\n    /// <summary>\n    /// Represents a node in the Circular Linked List.\n    /// Each node contains generic data and a reference to the next node.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of the data stored in the node.</typeparam>\n    /// <remarks>\n    /// Initializes a new instance of the <see cref=\"CircularLinkedListNode{T}\"/> class.\n    /// </remarks>\n    /// <param name=\"data\">The data to be stored in the node.</param>\n    public class CircularLinkedListNode<T>(T data)\n    {\n        /// <summary>\n        /// Gets or sets the data for the node.\n        /// </summary>\n        public T Data { get; set; } = data;\n\n        /// <summary>\n        /// Gets or sets the reference to the next node in the list.\n        /// </summary>\n        public CircularLinkedListNode<T>? Next { get; set; }\n    }\n}\n"
  },
  {
    "path": "DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs",
    "content": "using Utilities.Exceptions;\n\nnamespace DataStructures.LinkedList.DoublyLinkedList;\n\n/// <summary>\n///     Similar to a Singly Linked List but each node contains a refenrence to the previous node in the list.\n///     <see cref=\"System.Collections.Generic.LinkedList{T}\" /> is a doubly linked list.\n///     Compared to singly linked lists it can be traversed forwards and backwards.\n///     Adding a node to a doubly linked list is simpler because ever node contains a reference to the previous node.\n/// </summary>\n/// <typeparam name=\"T\">Generic type.</typeparam>\npublic class DoublyLinkedList<T>\n{\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"DoublyLinkedList{T}\" /> class.\n    /// </summary>\n    /// <param name=\"data\"> Data of the original head of the list.</param>\n    public DoublyLinkedList(T data)\n    {\n        Head = new DoublyLinkedListNode<T>(data);\n        Tail = Head;\n        Count = 1;\n    }\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"DoublyLinkedList{T}\" /> class from an enumerable.\n    /// </summary>\n    /// <param name=\"data\"> Enumerable of data to be stored in the list.</param>\n    public DoublyLinkedList(IEnumerable<T> data)\n    {\n        foreach (var d in data)\n        {\n            Add(d);\n        }\n    }\n\n    /// <summary>\n    ///     Gets the amount of nodes in the list.\n    /// </summary>\n    public int Count { get; private set; }\n\n    /// <summary>\n    ///     Gets or sets the first node of the list.\n    /// </summary>\n    private DoublyLinkedListNode<T>? Head { get; set; }\n\n    /// <summary>\n    ///     Gets or sets the last node of the list.\n    /// </summary>\n    private DoublyLinkedListNode<T>? Tail { get; set; }\n\n    /// <summary>\n    ///     Replaces the Head of the list with the new value.\n    /// </summary>\n    /// <param name=\"data\"> Value for the new Head of the list.</param>\n    /// <returns>The new Head node.</returns>\n    public DoublyLinkedListNode<T> AddHead(T data)\n    {\n        var node = new DoublyLinkedListNode<T>(data);\n\n        if (Head is null)\n        {\n            Head = node;\n            Tail = node;\n            Count = 1;\n            return node;\n        }\n\n        Head.Previous = node;\n        node.Next = Head;\n        Head = node;\n        Count++;\n        return node;\n    }\n\n    /// <summary>\n    ///     Adds a new value at the end of the list.\n    /// </summary>\n    /// <param name=\"data\"> New value to be added to the list.</param>\n    /// <returns>The new node created based on the new value.</returns>\n    public DoublyLinkedListNode<T> Add(T data)\n    {\n        if (Head is null)\n        {\n            return AddHead(data);\n        }\n\n        var node = new DoublyLinkedListNode<T>(data);\n        Tail!.Next = node;\n        node.Previous = Tail;\n        Tail = node;\n        Count++;\n        return node;\n    }\n\n    /// <summary>\n    ///     Adds a new value after an existing node.\n    /// </summary>\n    /// <param name=\"data\"> New value to be added to the list.</param>\n    /// <param name=\"existingNode\"> An existing node in the list.</param>\n    /// <returns>The new node created based on the new value.</returns>\n    public DoublyLinkedListNode<T> AddAfter(T data, DoublyLinkedListNode<T> existingNode)\n    {\n        if (existingNode == Tail)\n        {\n            return Add(data);\n        }\n\n        var node = new DoublyLinkedListNode<T>(data);\n        node.Next = existingNode.Next;\n        node.Previous = existingNode;\n        existingNode.Next = node;\n\n        if (node.Next is not null)\n        {\n            node.Next.Previous = node;\n        }\n\n        Count++;\n        return node;\n    }\n\n    /// <summary>\n    ///     Gets an enumerable based on the data in the list.\n    /// </summary>\n    /// <returns>The data in the list in an IEnumerable. It can used to create a list or an array with LINQ.</returns>\n    public IEnumerable<T> GetData()\n    {\n        var current = Head;\n        while (current is not null)\n        {\n            yield return current.Data;\n            current = current.Next;\n        }\n    }\n\n    /// <summary>\n    ///     Gets an enumerable based on the data in the list reversed.\n    /// </summary>\n    /// <returns>The data in the list in an IEnumerable. It can used to create a list or an array with LINQ.</returns>\n    public IEnumerable<T> GetDataReversed()\n    {\n        var current = Tail;\n        while (current is not null)\n        {\n            yield return current.Data;\n            current = current.Previous;\n        }\n    }\n\n    /// <summary>\n    ///     Reverses the list. Because of how doubly linked list are structured this is not a complex action.\n    /// </summary>\n    public void Reverse()\n    {\n        var current = Head;\n        DoublyLinkedListNode<T>? temp = null;\n\n        while (current is not null)\n        {\n            temp = current.Previous;\n            current.Previous = current.Next;\n            current.Next = temp;\n            current = current.Previous;\n        }\n\n        Tail = Head;\n\n        // temp can be null on empty list\n        if (temp is not null)\n        {\n            Head = temp.Previous;\n        }\n    }\n\n    /// <summary>\n    ///     Looks for a node in the list that contains the value of the parameter.\n    /// </summary>\n    /// <param name=\"data\"> Value to be looked for in a node.</param>\n    /// <returns>The node in the list the has the paramater as a value or null if not found.</returns>\n    public DoublyLinkedListNode<T> Find(T data)\n    {\n        var current = Head;\n        while (current is not null)\n        {\n            if (current.Data is null && data is null || current.Data is not null && current.Data.Equals(data))\n            {\n                return current;\n            }\n\n            current = current.Next;\n        }\n\n        throw new ItemNotFoundException();\n    }\n\n    /// <summary>\n    ///     Looks for a node in the list that contains the value of the parameter.\n    /// </summary>\n    /// <param name=\"position\"> Position in the list.</param>\n    /// <returns>The node in the list the has the paramater as a value or null if not found.</returns>\n    /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when position is negative or out range of the list.</exception>\n    public DoublyLinkedListNode<T> GetAt(int position)\n    {\n        if (position < 0 || position >= Count)\n        {\n            throw new ArgumentOutOfRangeException($\"Max count is {Count}\");\n        }\n\n        var current = Head;\n        for (var i = 0; i < position; i++)\n        {\n            current = current!.Next;\n        }\n\n        return current ?? throw new ArgumentOutOfRangeException($\"{nameof(position)} must be an index in the list\");\n    }\n\n    /// <summary>\n    ///     Removes the Head and replaces it with the second node in the list.\n    /// </summary>\n    public void RemoveHead()\n    {\n        if (Head is null)\n        {\n            throw new InvalidOperationException();\n        }\n\n        Head = Head.Next;\n        if (Head is null)\n        {\n            Tail = null;\n            Count = 0;\n            return;\n        }\n\n        Head.Previous = null;\n        Count--;\n    }\n\n    /// <summary>\n    ///     Removes the last node in the list.\n    /// </summary>\n    public void Remove()\n    {\n        if (Tail is null)\n        {\n            throw new InvalidOperationException(\"Cannot prune empty list\");\n        }\n\n        Tail = Tail.Previous;\n        if (Tail is null)\n        {\n            Head = null;\n            Count = 0;\n            return;\n        }\n\n        Tail.Next = null;\n        Count--;\n    }\n\n    /// <summary>\n    ///     Removes specific node.\n    /// </summary>\n    /// <param name=\"node\"> Node to be removed.</param>\n    public void RemoveNode(DoublyLinkedListNode<T> node)\n    {\n        if (node == Head)\n        {\n            RemoveHead();\n            return;\n        }\n\n        if (node == Tail)\n        {\n            Remove();\n            return;\n        }\n\n        if (node.Previous is null || node.Next is null)\n        {\n            throw new ArgumentException(\n                $\"{nameof(node)} cannot have Previous or Next null if it's an internal node\");\n        }\n\n        node.Previous.Next = node.Next;\n        node.Next.Previous = node.Previous;\n        Count--;\n    }\n\n    /// <summary>\n    ///     Removes a node that contains the data from the parameter.\n    /// </summary>\n    /// <param name=\"data\"> Data to be removed form the list.</param>\n    public void Remove(T data)\n    {\n        var node = Find(data);\n        RemoveNode(node);\n    }\n\n    /// <summary>\n    ///     Looks for the index of the node with the parameter as data.\n    /// </summary>\n    /// <param name=\"data\"> Data to look for.</param>\n    /// <returns>Returns the index of the node if it is found or -1 if the node is not found.</returns>\n    public int IndexOf(T data)\n    {\n        var current = Head;\n        var index = 0;\n        while (current is not null)\n        {\n            if (current.Data is null && data is null || current.Data is not null && current.Data.Equals(data))\n            {\n                return index;\n            }\n\n            index++;\n            current = current.Next;\n        }\n\n        return -1;\n    }\n\n    /// <summary>\n    ///     List contains a node that has the parameter as data.\n    /// </summary>\n    /// <param name=\"data\"> Node to be removed.</param>\n    /// <returns>True if the node is found. False if it isn't.</returns>\n    public bool Contains(T data) => IndexOf(data) != -1;\n}\n"
  },
  {
    "path": "DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedListNode.cs",
    "content": "namespace DataStructures.LinkedList.DoublyLinkedList;\n\n/// <summary>\n///     Generic node class for Doubly Linked List.\n/// </summary>\n/// <typeparam name=\"T\">Generic type.</typeparam>\n/// <remarks>\n///     Initializes a new instance of the <see cref=\"DoublyLinkedListNode{T}\" /> class.\n/// </remarks>\n/// <param name=\"data\">Data to be stored in this node.</param>\npublic class DoublyLinkedListNode<T>(T data)\n{\n    /// <summary>\n    ///     Gets the data stored on this node.\n    /// </summary>\n    public T Data { get; } = data;\n\n    /// <summary>\n    ///     Gets or sets the reference to the next node in the Doubly Linked List.\n    /// </summary>\n    public DoublyLinkedListNode<T>? Next { get; set; }\n\n    /// <summary>\n    ///     Gets or sets the reference to the previous node in the Doubly Linked List.\n    /// </summary>\n    public DoublyLinkedListNode<T>? Previous { get; set; }\n}\n"
  },
  {
    "path": "DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs",
    "content": "namespace DataStructures.LinkedList.SinglyLinkedList;\n\npublic class SinglyLinkedList<T>\n{\n    // points to the start of the list\n    private SinglyLinkedListNode<T>? Head { get; set; }\n\n    /// <summary>\n    ///     Adds new node to the start of the list,\n    ///     time complexity: O(1),\n    ///     space complexity: O(1).\n    /// </summary>\n    /// <param name=\"data\">Contents of newly added node.</param>\n    /// <returns>Added list node.</returns>\n    public SinglyLinkedListNode<T> AddFirst(T data)\n    {\n        var newListElement = new SinglyLinkedListNode<T>(data)\n        {\n            Next = Head,\n        };\n\n        Head = newListElement;\n        return newListElement;\n    }\n\n    /// <summary>\n    ///     Adds new node to the end of the list,\n    ///     time complexity: O(n),\n    ///     space complexity: O(1),\n    ///     where n - number of nodes in the list.\n    /// </summary>\n    /// <param name=\"data\">Contents of newly added node.</param>\n    /// <returns>Added list node.</returns>\n    public SinglyLinkedListNode<T> AddLast(T data)\n    {\n        var newListElement = new SinglyLinkedListNode<T>(data);\n\n        // if head is null, the added element is the first, hence it is the head\n        if (Head is null)\n        {\n            Head = newListElement;\n            return newListElement;\n        }\n\n        // temp ListElement to avoid overwriting the original\n        var tempElement = Head;\n\n        // iterates through all elements\n        while (tempElement.Next is not null)\n        {\n            tempElement = tempElement.Next;\n        }\n\n        // adds the new element to the last one\n        tempElement.Next = newListElement;\n        return newListElement;\n    }\n\n    /// <summary>\n    ///     Returns element at index <paramref name=\"index\" /> in the list.\n    /// </summary>\n    /// <param name=\"index\">Index of an element to be returned.</param>\n    /// <returns>Element at index <paramref name=\"index\" />.</returns>\n    public T GetElementByIndex(int index)\n    {\n        if (index < 0)\n        {\n            throw new ArgumentOutOfRangeException(nameof(index));\n        }\n\n        var tempElement = Head;\n\n        for (var i = 0; tempElement is not null && i < index; i++)\n        {\n            tempElement = tempElement.Next;\n        }\n\n        if (tempElement is null)\n        {\n            throw new ArgumentOutOfRangeException(nameof(index));\n        }\n\n        return tempElement.Data;\n    }\n\n    public int Length()\n    {\n        // checks if there is a head\n        if (Head is null)\n        {\n            return 0;\n        }\n\n        var tempElement = Head;\n        var length = 1;\n\n        while (tempElement.Next is not null)\n        {\n            tempElement = tempElement.Next;\n            length++;\n        }\n\n        return length;\n    }\n\n    public IEnumerable<T> GetListData()\n    {\n        // temp ListElement to avoid overwriting the original\n        var tempElement = Head;\n\n        // all elements where a next attribute exists\n        while (tempElement is not null)\n        {\n            yield return tempElement.Data;\n            tempElement = tempElement.Next;\n        }\n    }\n\n    public bool DeleteElement(T element)\n    {\n        var currentElement = Head;\n        SinglyLinkedListNode<T>? previousElement = null;\n\n        // iterates through all elements\n        while (currentElement is not null)\n        {\n            // checks if the element, which should get deleted is in this list element\n            if (currentElement.Data is null && element is null ||\n                currentElement.Data is not null && currentElement.Data.Equals(element))\n            {\n                // if element is head just take the next one as head\n                if (currentElement.Equals(Head))\n                {\n                    Head = Head.Next;\n                    return true;\n                }\n\n                // else take the prev one and overwrite the next with the one behind the deleted\n                if (previousElement is not null)\n                {\n                    previousElement.Next = currentElement.Next;\n                    return true;\n                }\n            }\n\n            // iterating\n            previousElement = currentElement;\n            currentElement = currentElement.Next;\n        }\n\n        return false;\n    }\n\n    /// <summary>\n    /// Deletes the first element of the list.\n    /// </summary>\n    /// <returns> true if the operation is successul.</returns>\n    public bool DeleteFirst()\n    {\n        // checks if the List is empty\n        if (Head is null)\n        {\n            return false;\n        }\n\n        // if not, the head is overwritten with the next element and the old head is deleted\n        Head = Head.Next;\n        return true;\n    }\n\n    /// <summary>\n    /// Deletes the last element of the list.\n    /// </summary>\n    /// <returns> returns true if the operation is successful. </returns>\n    public bool DeleteLast()\n    {\n        // checks if the List is empty\n        if (Head is null)\n        {\n            return false;\n        }\n\n        // checks if the List has only one element\n        if (Head.Next is null)\n        {\n            Head = null;\n            return true;\n        }\n\n        // if not, iterates through the list to the second last element and deletes the last one\n        SinglyLinkedListNode<T>? secondlast = Head;\n        while (secondlast.Next?.Next is not null)\n        {\n            secondlast = secondlast.Next;\n        }\n\n        secondlast.Next = null;\n        return true;\n    }\n}\n"
  },
  {
    "path": "DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedListNode.cs",
    "content": "namespace DataStructures.LinkedList.SinglyLinkedList;\n\npublic class SinglyLinkedListNode<T>(T data)\n{\n    public T Data { get; } = data;\n\n    public SinglyLinkedListNode<T>? Next { get; set; }\n}\n"
  },
  {
    "path": "DataStructures/LinkedList/SkipList/SkipList.cs",
    "content": "using System.Diagnostics;\n\nnamespace DataStructures.LinkedList.SkipList;\n\n/// <summary>\n/// Skip list implementation that is based on the singly linked list,\n/// but offers O(log n) time complexity on most operations.\n/// </summary>\n/// <typeparam name=\"TValue\">The type of the values in the list.</typeparam>\n/// <remarks>\n/// Skip list nodes sorted by key.\n/// The \"skip lanes\" allow searching for a node in O(log n) time on average.\n/// The worst case performence is O(n) when the height of all nodes is 1 (very\n/// unluckily to happen on any decent list size).\n/// These two properties make the skip list an excellent data structure for\n/// implementing additional operations like finding min/max value in the list,\n/// finding values with the key in a given range, etc.\n///\n/// Sourses:\n/// - \"Skip Lists: A Probabilistic Alternative to Balanced Trees\" by William Pugh.\n/// - https://en.wikipedia.org/wiki/Skip_list\n/// - https://iq.opengenus.org/skip-list/\n/// - https://medium.com/simple-computer-science/data-structures-basics-skip-list-8b8c69f9a044\n/// - https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java\n///\n/// The key is hardcoded to be of type <c>int</c> to simplify the implementation,\n/// but it can be easily an any generic type that implements <c>IComparable</c>.\n/// </remarks>\n[DebuggerDisplay(\"Count = {Count}\")]\npublic class SkipList<TValue>\n{\n    private const double Probability = 0.5;\n    private readonly int maxLevels;\n    private readonly SkipListNode<TValue> head;\n    private readonly SkipListNode<TValue> tail;\n    private readonly Random random = new Random();\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"SkipList{TValue}\"/> class.\n    /// </summary>\n    /// <param name=\"capacity\">Expected number of elements the list might contain.</param>\n    public SkipList(int capacity = 255)\n    {\n        maxLevels = (int)Math.Log2(capacity) + 1;\n\n        head = new(int.MinValue, default(TValue), maxLevels);\n        tail = new(int.MaxValue, default(TValue), maxLevels);\n\n        for (int i = 0; i < maxLevels; i++)\n        {\n            head.Next[i] = tail;\n        }\n    }\n\n    /// <summary>\n    /// Gets the number of elements currently in the list.\n    /// </summary>\n    public int Count { get; private set; }\n\n    /// <summary>\n    /// Gets or sets the element with the specified key.\n    /// </summary>\n    /// <exception cref=\"KeyNotFoundException\">The key is not present in the list.</exception>\n    public TValue this[int key]\n    {\n        get\n        {\n            var previousNode = GetSkipNodes(key).First();\n            if (previousNode.Next[0].Key == key)\n            {\n                return previousNode.Next[0].Value!;\n            }\n            else\n            {\n                throw new KeyNotFoundException();\n            }\n        }\n\n        set => AddOrUpdate(key, value);\n    }\n\n    /// <summary>\n    /// Adds an element with the specified key and value to the list.\n    /// If an element with the same key already exists, updates its value.\n    /// </summary>\n    /// <param name=\"key\">The key of the element to add.</param>\n    /// <param name=\"value\">The value of the element to add.</param>\n    /// <remarks>\n    /// Time complexity: O(log n) where n is the number of elements in the list.\n    /// </remarks>\n    public void AddOrUpdate(int key, TValue value)\n    {\n        var skipNodes = GetSkipNodes(key);\n\n        var previousNode = skipNodes.First();\n        if (previousNode.Next[0].Key == key)\n        {\n            // Node with the given key already exists.\n            // Update its value.\n            previousNode.Next[0].Value = value;\n            return;\n        }\n\n        // Node with the given key does not exist.\n        // Insert the new one and update the skip nodes.\n        var newNode = new SkipListNode<TValue>(key, value, GetRandomHeight());\n        for (var level = 0; level < newNode.Height; level++)\n        {\n            newNode.Next[level] = skipNodes[level].Next[level];\n            skipNodes[level].Next[level] = newNode;\n        }\n\n        Count++;\n    }\n\n    /// <summary>\n    /// Returns whether a value with the given key exists in the list.\n    /// </summary>\n    /// <remarks>\n    /// Time complexity: O(log n) where n is the number of elements in the list.\n    /// </remarks>\n    public bool Contains(int key)\n    {\n        var previousNode = GetSkipNodes(key).First();\n        return previousNode.Next[0].Key == key;\n    }\n\n    /// <summary>\n    /// Removes the value with the given key from the list.\n    /// </summary>\n    /// <returns>\n    /// <c>true</c> if the value was removed; otherwise, <c>false</c>.\n    /// </returns>\n    /// <remarks>\n    /// Time complexity: O(log n) where n is the number of elements in the list.\n    /// </remarks>\n    public bool Remove(int key)\n    {\n        var skipNodes = GetSkipNodes(key);\n        var previousNode = skipNodes.First();\n        if (previousNode.Next[0].Key != key)\n        {\n            return false;\n        }\n\n        // Key exists in the list, remove it and update the skip nodes.\n        var nodeToRemove = previousNode.Next[0];\n        for (var level = 0; level < nodeToRemove.Height; level++)\n        {\n            skipNodes[level].Next[level] = nodeToRemove.Next[level];\n        }\n\n        Count--;\n\n        return true;\n    }\n\n    /// <summary>\n    /// Returns an enumerator that iterates through the list.\n    /// </summary>\n    /// <remarks>\n    /// Order of values is the ascending order of their keys.\n    /// Time complexity: O(n) where n is the number of elements in the list.\n    /// </remarks>\n    public IEnumerable<TValue> GetValues()\n    {\n        var current = head.Next[0];\n        while (current.Key != tail.Key)\n        {\n            yield return current.Value!;\n            current = current.Next[0];\n        }\n    }\n\n    /// <summary>\n    /// Builds a list of skip nodes on each level that\n    /// are closest, but smaller than the given key.\n    /// </summary>\n    /// <remarks>\n    /// The node on level 0 will point to the node with the given key, if it exists.\n    /// Time complexity: O(log n) where n is the number of elements in the list.\n    /// </remarks>\n    private SkipListNode<TValue>[] GetSkipNodes(int key)\n    {\n        var skipNodes = new SkipListNode<TValue>[maxLevels];\n        var current = head;\n        for (var level = head.Height - 1; level >= 0; level--)\n        {\n            while (current.Next[level].Key < key)\n            {\n                current = current.Next[level];\n            }\n\n            skipNodes[level] = current;\n        }\n\n        return skipNodes;\n    }\n\n    /// <summary>\n    /// Determines the height of skip levels for the new node.\n    /// </summary>\n    /// <remarks>\n    /// Probability of the next level is 1/(2^level).\n    /// </remarks>\n    private int GetRandomHeight()\n    {\n        int height = 1;\n        while (random.NextDouble() < Probability && height < maxLevels)\n        {\n            height++;\n        }\n\n        return height;\n    }\n}\n"
  },
  {
    "path": "DataStructures/LinkedList/SkipList/SkipListNode.cs",
    "content": "using System.Diagnostics;\n\nnamespace DataStructures.LinkedList.SkipList;\n\n[DebuggerDisplay(\"Key = {Key}, Height = {Height}, Value = {Value}\")]\ninternal class SkipListNode<TValue>(int key, TValue? value, int height)\n{\n    public int Key { get; } = key;\n\n    public TValue? Value { get; set; } = value;\n\n    public SkipListNode<TValue>[] Next { get; } = new SkipListNode<TValue>[height];\n\n    public int Height { get; } = height;\n}\n"
  },
  {
    "path": "DataStructures/Probabilistic/BloomFilter.cs",
    "content": "namespace DataStructures.Probabilistic;\n\npublic class BloomFilter<T> where T : notnull\n{\n    private const uint FnvPrime = 16777619;\n    private const uint FnvOffsetBasis = 2166136261;\n    private readonly byte[] filter;\n    private readonly int numHashes;\n    private readonly int sizeBits;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"BloomFilter{T}\"/> class. This constructor will create a Bloom Filter\n    /// of an optimal size with the optimal number of hashes to minimize the error rate.\n    /// </summary>\n    /// <param name=\"expectedNumElements\">Expected number of unique elements that could be added to the filter.</param>\n    public BloomFilter(int expectedNumElements)\n    {\n        numHashes = (int)Math.Ceiling(.693 * 8 * expectedNumElements / expectedNumElements); // compute optimal number of hashes\n        filter = new byte[expectedNumElements]; // set up filter with 8 times as many bits as elements\n        sizeBits = expectedNumElements * 8; // number of bit slots in the filter\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"BloomFilter{T}\"/> class.\n    /// This constructor let's you decide how large you want the filter to be as well as allowing you to specify\n    /// how many hashes it will use. Only use if you don't care to optimize false positivity.\n    /// </summary>\n    /// <param name=\"sizeBits\">size in bits you want the filter to be.</param>\n    /// <param name=\"numHashes\">number of hash functions to be used.</param>\n    public BloomFilter(int sizeBits, int numHashes)\n    {\n        filter = new byte[sizeBits / 8 + 1];\n        this.numHashes = numHashes;\n        this.sizeBits = sizeBits;\n    }\n\n    /// <summary>\n    /// Inserts an item into the bloom filter.\n    /// </summary>\n    /// <param name=\"item\">The item being inserted into the Bloom Filter.</param>\n    public void Insert(T item)\n    {\n        foreach (var slot in GetSlots(item))\n        {\n            filter[slot / 8] |= (byte)(1 << (slot % 8)); // set the filter at the decided slot to 1.\n        }\n    }\n\n    /// <summary>\n    /// Searches the Bloom Filter to determine if the item exists in the Bloom Filter.\n    /// </summary>\n    /// <param name=\"item\">The item being searched for in the Bloom Filter.</param>\n    /// <returns>true if the item has been added to the Bloom Filter, false otherwise.</returns>\n    public bool Search(T item)\n    {\n        foreach (var slot in GetSlots(item))\n        {\n            var @byte = filter[slot / 8]; // Extract the byte in the filter.\n            var mask = 1 << (slot % 8); // Build the mask for the slot number.\n            if ((@byte & mask) != mask)\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    /// Yields the appropriate slots for the given item.\n    /// </summary>\n    /// <param name=\"item\">The item to determine the slots for.</param>\n    /// <returns>The slots of the filter to flip or check.</returns>\n    private IEnumerable<int> GetSlots(T item)\n    {\n        var hash = item.GetHashCode();\n        for (var i = 0; i < numHashes; i++)\n        {\n            yield return Math.Abs((i + 1) * hash) % sizeBits;\n        }\n    }\n}\n"
  },
  {
    "path": "DataStructures/Probabilistic/CountMinSketch.cs",
    "content": "namespace DataStructures.Probabilistic;\n\npublic class CountMinSketch<T> where T : notnull\n{\n    private readonly int[][] sketch;\n    private readonly int numHashes;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CountMinSketch{T}\"/> class based off dimensions\n    /// passed by the user.\n    /// </summary>\n    /// <param name=\"width\">The width of the sketch.</param>\n    /// <param name=\"numHashes\">The number of hashes to use in the sketch.</param>\n    public CountMinSketch(int width, int numHashes)\n    {\n        sketch = new int[numHashes][];\n        for (var i = 0; i < numHashes; i++)\n        {\n            sketch[i] = new int[width];\n        }\n\n        this.numHashes = numHashes;\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CountMinSketch{T}\"/> class based off the optimizing error rate\n    /// and error probability formula width = e/errorRate numHashes = ln(1.0/errorProp).\n    /// </summary>\n    /// <param name=\"errorRate\">The amount of acceptable over counting for the sketch.</param>\n    /// <param name=\"errorProb\">The probability that an item will be over counted.</param>\n    public CountMinSketch(double errorRate, double errorProb)\n    {\n        var width = (int)Math.Ceiling(Math.E / errorRate);\n        numHashes = (int)Math.Ceiling(Math.Log(1.0 / errorProb));\n        sketch = new int[numHashes][];\n        for (var i = 0; i < numHashes; i++)\n        {\n            sketch[i] = new int[width];\n        }\n    }\n\n    /// <summary>\n    /// Inserts the provided item into the sketch.\n    /// </summary>\n    /// <param name=\"item\">Item to insert.</param>\n    public void Insert(T item)\n    {\n        var initialHash = item.GetHashCode();\n        for (int i = 0; i < numHashes; i++)\n        {\n            var slot = GetSlot(i, initialHash);\n            sketch[i][slot]++;\n        }\n    }\n\n    /// <summary>\n    /// Queries the count of the given item that have been inserted into the sketch.\n    /// </summary>\n    /// <param name=\"item\">item to insert into the sketch.</param>\n    /// <returns>the number of times the provided item has been inserted into the sketch.</returns>\n    public int Query(T item)\n    {\n        var initialHash = item.GetHashCode();\n        var min = int.MaxValue;\n        for (int i = 0; i < numHashes; i++)\n        {\n            var slot = GetSlot(i, initialHash);\n            min = Math.Min(sketch[i][slot], min);\n        }\n\n        return min;\n    }\n\n    private int GetSlot(int i, int initialHash) => Math.Abs((i + 1) * initialHash) % sketch[0].Length;\n}\n"
  },
  {
    "path": "DataStructures/Probabilistic/HyperLogLog.cs",
    "content": "namespace DataStructures.Probabilistic;\n\npublic class HyperLogLog<T> where T : notnull\n{\n    private const int P = 16;\n    private const double Alpha = .673;\n    private readonly int[] registers;\n    private readonly HashSet<int> setRegisters;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"HyperLogLog{T}\"/> class.\n    /// </summary>\n    public HyperLogLog()\n    {\n        var m = 1 << P;\n        registers = new int[m];\n        setRegisters = [];\n    }\n\n    /// <summary>\n    /// Merge's two HyperLogLog's together to form a union HLL.\n    /// </summary>\n    /// <param name=\"first\">the first HLL.</param>\n    /// <param name=\"second\">The second HLL.</param>\n    /// <returns>A HyperLogLog with the combined values of the two sets of registers.</returns>\n    public static HyperLogLog<T> Merge(HyperLogLog<T> first, HyperLogLog<T> second)\n    {\n        var output = new HyperLogLog<T>();\n        for (var i = 0; i < second.registers.Length; i++)\n        {\n            output.registers[i] = Math.Max(first.registers[i], second.registers[i]);\n        }\n\n        output.setRegisters.UnionWith(first.setRegisters);\n        output.setRegisters.UnionWith(second.setRegisters);\n        return output;\n    }\n\n    /// <summary>\n    /// Adds an item to the HyperLogLog.\n    /// </summary>\n    /// <param name=\"item\">The Item to be added.</param>\n    public void Add(T item)\n    {\n        var x = item.GetHashCode();\n        var binString = Convert.ToString(x, 2); // converts hash to binary\n        var j = Convert.ToInt32(binString.Substring(0, Math.Min(P, binString.Length)), 2); // convert first b bits to register index\n        var w = (int)Math.Log2(x ^ (x & (x - 1))); // find position of the right most 1.\n        registers[j] = Math.Max(registers[j], w); // set the appropriate register to the appropriate value.\n        setRegisters.Add(j);\n    }\n\n    /// <summary>\n    /// Determines the approximate cardinality of the HyperLogLog.\n    /// </summary>\n    /// <returns>the approximate cardinality.</returns>\n    public int Cardinality()\n    {\n        // calculate the bottom part of the harmonic mean of the registers\n        double z = setRegisters.Sum(index => Math.Pow(2, -1 * registers[index]));\n\n        // calculate the harmonic mean of the set registers\n        return (int)Math.Ceiling(Alpha * setRegisters.Count * (setRegisters.Count / z));\n    }\n}\n"
  },
  {
    "path": "DataStructures/Queue/ArrayBasedQueue.cs",
    "content": "namespace DataStructures.Queue;\n\n/// <summary>\n///     Implementation of an array based queue. FIFO style.\n/// </summary>\n/// <typeparam name=\"T\">Generic Type.</typeparam>\npublic class ArrayBasedQueue<T>\n{\n    private readonly T[] queue;\n    private int endIndex;\n    private bool isEmpty;\n    private bool isFull;\n    private int startIndex;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"ArrayBasedQueue{T}\" /> class.\n    /// </summary>\n    public ArrayBasedQueue(int capacity)\n    {\n        queue = new T[capacity];\n        Clear();\n    }\n\n    /// <summary>\n    ///     Clears the queue.\n    /// </summary>\n    public void Clear()\n    {\n        startIndex = 0;\n        endIndex = 0;\n        isEmpty = true;\n        isFull = false;\n    }\n\n    /// <summary>\n    ///     Returns the first item in the queue and removes it from the queue.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the queue is empty.</exception>\n    public T Dequeue()\n    {\n        if (IsEmpty())\n        {\n            throw new InvalidOperationException(\"There are no items in the queue.\");\n        }\n\n        var dequeueIndex = endIndex;\n        endIndex++;\n        if (endIndex >= queue.Length)\n        {\n            endIndex = 0;\n        }\n\n        isFull = false;\n        isEmpty = startIndex == endIndex;\n\n        return queue[dequeueIndex];\n    }\n\n    /// <summary>\n    ///     Returns a boolean indicating whether the queue is empty.\n    /// </summary>\n    public bool IsEmpty() => isEmpty;\n\n    /// <summary>\n    ///     Returns a boolean indicating whether the queue is full.\n    /// </summary>\n    public bool IsFull() => isFull;\n\n    /// <summary>\n    ///     Returns the first item in the queue and keeps it in the queue.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the queue is empty.</exception>\n    public T Peek()\n    {\n        if (IsEmpty())\n        {\n            throw new InvalidOperationException(\"There are no items in the queue.\");\n        }\n\n        return queue[endIndex];\n    }\n\n    /// <summary>\n    ///     Adds an item at the last position in the queue.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the queue is full.</exception>\n    public void Enqueue(T item)\n    {\n        if (IsFull())\n        {\n            throw new InvalidOperationException(\"The queue has reached its capacity.\");\n        }\n\n        queue[startIndex] = item;\n\n        startIndex++;\n        if (startIndex >= queue.Length)\n        {\n            startIndex = 0;\n        }\n\n        isEmpty = false;\n        isFull = startIndex == endIndex;\n    }\n}\n"
  },
  {
    "path": "DataStructures/Queue/ListBasedQueue.cs",
    "content": "namespace DataStructures.Queue;\n\n/// <summary>\n///     Implementation of a list based queue. FIFO style.\n/// </summary>\n/// <typeparam name=\"T\">Generic Type.</typeparam>\npublic class ListBasedQueue<T>\n{\n    private readonly LinkedList<T> queue;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"ListBasedQueue{T}\" /> class.\n    /// </summary>\n    public ListBasedQueue() => queue = new LinkedList<T>();\n\n    /// <summary>\n    ///     Clears the queue.\n    /// </summary>\n    public void Clear()\n    {\n        queue.Clear();\n    }\n\n    /// <summary>\n    ///     Returns the first item in the queue and removes it from the queue.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the queue is empty.</exception>\n    public T Dequeue()\n    {\n        if (queue.First is null)\n        {\n            throw new InvalidOperationException(\"There are no items in the queue.\");\n        }\n\n        var item = queue.First;\n        queue.RemoveFirst();\n        return item.Value;\n    }\n\n    /// <summary>\n    ///     Returns a boolean indicating whether the queue is empty.\n    /// </summary>\n    public bool IsEmpty() => !queue.Any();\n\n    /// <summary>\n    ///     Returns a boolean indicating whether the queue is full.\n    /// </summary>\n    public bool IsFull() => false;\n\n    /// <summary>\n    ///     Returns the first item in the queue and keeps it in the queue.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the queue is empty.</exception>\n    public T Peek()\n    {\n        if (queue.First is null)\n        {\n            throw new InvalidOperationException(\"There are no items in the queue.\");\n        }\n\n        return queue.First.Value;\n    }\n\n    /// <summary>\n    ///     Adds an item at the last position in the queue.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the queue is full.</exception>\n    public void Enqueue(T item)\n    {\n        queue.AddLast(item);\n    }\n}\n"
  },
  {
    "path": "DataStructures/Queue/StackBasedQueue.cs",
    "content": "namespace DataStructures.Queue;\n\n/// <summary>\n///     Implementation of a stack based queue. FIFO style.\n/// </summary>\n/// <remarks>\n///     Enqueue is O(1) and Dequeue is amortized O(1).\n/// </remarks>\n/// <typeparam name=\"T\">Generic Type.</typeparam>\npublic class StackBasedQueue<T>\n{\n    private readonly Stack<T> input;\n    private readonly Stack<T> output;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"StackBasedQueue{T}\" /> class.\n    /// </summary>\n    public StackBasedQueue()\n    {\n        input = new Stack<T>();\n        output = new Stack<T>();\n    }\n\n    /// <summary>\n    ///     Clears the queue.\n    /// </summary>\n    public void Clear()\n    {\n        input.Clear();\n        output.Clear();\n    }\n\n    /// <summary>\n    ///     Returns the first item in the queue and removes it from the queue.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the queue is empty.</exception>\n    public T Dequeue()\n    {\n        if (input.Count == 0 && output.Count == 0)\n        {\n            throw new InvalidOperationException(\"The queue contains no items.\");\n        }\n\n        if (output.Count == 0)\n        {\n            while (input.Count > 0)\n            {\n                var item = input.Pop();\n                output.Push(item);\n            }\n        }\n\n        return output.Pop();\n    }\n\n    /// <summary>\n    ///     Returns a boolean indicating whether the queue is empty.\n    /// </summary>\n    public bool IsEmpty() => input.Count == 0 && output.Count == 0;\n\n    /// <summary>\n    ///     Returns a boolean indicating whether the queue is full.\n    /// </summary>\n    public bool IsFull() => false;\n\n    /// <summary>\n    ///     Returns the first item in the queue and keeps it in the queue.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the queue is empty.</exception>\n    public T Peek()\n    {\n        if (input.Count == 0 && output.Count == 0)\n        {\n            throw new InvalidOperationException(\"The queue contains no items.\");\n        }\n\n        if (output.Count == 0)\n        {\n            while (input.Count > 0)\n            {\n                var item = input.Pop();\n                output.Push(item);\n            }\n        }\n\n        return output.Peek();\n    }\n\n    /// <summary>\n    ///     Adds an item at the last position in the queue.\n    /// </summary>\n    public void Enqueue(T item) => input.Push(item);\n}\n"
  },
  {
    "path": "DataStructures/RedBlackTree/RedBlackTree.cs",
    "content": "namespace DataStructures.RedBlackTree;\n\n/// <summary>\n///     A self-balancing bindary tree.\n/// </summary>\n/// <remarks>\n///     A red-black tree is a self-balancing binary search tree (BST) that\n///     stores a color with each node. A node's color can either be red or\n///     black. Several properties are maintained to ensure the tree remains\n///     balanced.\n///     <list type=\"number\">\n///         <item>\n///             <term>A red node does not have a red child.</term>\n///         </item>\n///         <item>\n///             <term>All null nodes are considered black.</term>\n///         </item>\n///         <item>\n///             <term>\n///                 Every path from a node to its descendant leaf nodes\n///             has the same number of black nodes.\n///             </term>\n///         </item>\n///         <item>\n///             <term>(Optional) The root is always black.</term>\n///         </item>\n///     </list>\n///     Red-black trees are generally slightly more unbalanced than an\n///     AVL tree, but insertion and deletion is generally faster.\n///     See https://en.wikipedia.org/wiki/Red%E2%80%93black_tree for more information.\n/// </remarks>\n/// <typeparam name=\"TKey\">Type of key for the tree.</typeparam>\npublic class RedBlackTree<TKey>\n{\n    /// <summary>\n    ///     Gets the number of nodes in the tree.\n    /// </summary>\n    public int Count { get; private set; }\n\n    /// <summary>\n    ///     Comparer to use when comparing key values.\n    /// </summary>\n    private readonly Comparer<TKey> comparer;\n\n    /// <summary>\n    ///     Reference to the root node.\n    /// </summary>\n    private RedBlackTreeNode<TKey>? root;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"RedBlackTree{TKey}\"/> class.\n    /// </summary>\n    public RedBlackTree()\n    {\n        comparer = Comparer<TKey>.Default;\n    }\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"RedBlackTree{TKey}\"/> class\n    ///     using the specified comparer.\n    /// </summary>\n    /// <param name=\"customComparer\">Comparer to use when comparing keys.</param>\n    public RedBlackTree(Comparer<TKey> customComparer)\n    {\n        comparer = customComparer;\n    }\n\n    /// <summary>\n    ///     Add a single node to the tree.\n    /// </summary>\n    /// <param name=\"key\">Key value to add.</param>\n    public void Add(TKey key)\n    {\n        if (root is null)\n        {\n            // Case 3\n            // New node is root\n            root = new RedBlackTreeNode<TKey>(key, null)\n            {\n                Color = NodeColor.Black,\n            };\n            Count++;\n            return;\n        }\n\n        // Regular binary tree insertion\n        var node = Add(root, key);\n\n        // Get which side child was added to\n        var childDir = comparer.Compare(node.Key, node.Parent!.Key);\n\n        // Set node to be new node's parent for easier handling\n        node = node.Parent;\n\n        // Return tree to valid state\n        int addCase;\n        do\n        {\n            addCase = GetAddCase(node);\n\n            switch (addCase)\n            {\n                case 1:\n                    break;\n                case 2:\n                    var oldParent = node.Parent;\n                    node = AddCase2(node);\n\n                    if (node is not null)\n                    {\n                        childDir = comparer.Compare(oldParent!.Key, oldParent.Parent!.Key);\n                    }\n\n                    break;\n                case 4:\n                    node.Color = NodeColor.Black;\n                    break;\n                case 56:\n                    AddCase56(node, comparer.Compare(node.Key, node.Parent!.Key), childDir);\n                    break;\n                default:\n                    throw new InvalidOperationException(\"It should not be possible to get here!\");\n            }\n        }\n        while (addCase == 2 && node is not null);\n\n        Count++;\n    }\n\n    /// <summary>\n    ///     Add multiple nodes to the tree.\n    /// </summary>\n    /// <param name=\"keys\">Key values to add.</param>\n    public void AddRange(IEnumerable<TKey> keys)\n    {\n        foreach (var key in keys)\n        {\n            Add(key);\n        }\n    }\n\n    /// <summary>\n    ///     Remove a node from the tree.\n    /// </summary>\n    /// <param name=\"key\">Key value to remove.</param>\n    public void Remove(TKey key)\n    {\n        // Search for node\n        var node = Remove(root, key);\n\n        // Simple cases\n        node = RemoveSimpleCases(node);\n\n        // Exit if deleted node was not non-root black leaf\n        if (node is null)\n        {\n            return;\n        }\n\n        // Delete node\n        DeleteLeaf(node.Parent!, comparer.Compare(node.Key, node.Parent!.Key));\n\n        // Recolor tree\n        do\n        {\n            node = RemoveRecolor(node);\n        }\n        while (node is not null && node.Parent is not null);    // Case 2: Reached root\n\n        Count--;\n    }\n\n    /// <summary>\n    ///     Check if given node is in the tree.\n    /// </summary>\n    /// <param name=\"key\">Key value to search for.</param>\n    /// <returns>Whether or not the node is in the tree.</returns>\n    public bool Contains(TKey key)\n    {\n        var node = root;\n        while (node is not null)\n        {\n            var compareResult = comparer.Compare(key, node.Key);\n            if (compareResult < 0)\n            {\n                node = node.Left;\n            }\n            else if (compareResult > 0)\n            {\n                node = node.Right;\n            }\n            else\n            {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /// <summary>\n    ///     Get the minimum value in the tree.\n    /// </summary>\n    /// <returns>Minimum value in tree.</returns>\n    public TKey GetMin()\n    {\n        if (root is null)\n        {\n            throw new InvalidOperationException(\"Tree is empty!\");\n        }\n\n        return GetMin(root).Key;\n    }\n\n    /// <summary>\n    ///     Get the maximum value in the tree.\n    /// </summary>\n    /// <returns>Maximum value in tree.</returns>\n    public TKey GetMax()\n    {\n        if (root is null)\n        {\n            throw new InvalidOperationException(\"Tree is empty!\");\n        }\n\n        return GetMax(root).Key;\n    }\n\n    /// <summary>\n    ///     Get keys in order from smallest to largest as defined by the comparer.\n    /// </summary>\n    /// <returns>Keys in tree in order from smallest to largest.</returns>\n    public IEnumerable<TKey> GetKeysInOrder()\n    {\n        var result = new List<TKey>();\n        InOrderWalk(root);\n        return result;\n\n        void InOrderWalk(RedBlackTreeNode<TKey>? node)\n        {\n            if (node is null)\n            {\n                return;\n            }\n\n            InOrderWalk(node.Left);\n            result.Add(node.Key);\n            InOrderWalk(node.Right);\n        }\n    }\n\n    /// <summary>\n    ///     Get keys in the pre-order order.\n    /// </summary>\n    /// <returns>Keys in pre-order order.</returns>\n    public IEnumerable<TKey> GetKeysPreOrder()\n    {\n        var result = new List<TKey>();\n        PreOrderWalk(root);\n        return result;\n\n        void PreOrderWalk(RedBlackTreeNode<TKey>? node)\n        {\n            if (node is null)\n            {\n                return;\n            }\n\n            result.Add(node.Key);\n            PreOrderWalk(node.Left);\n            PreOrderWalk(node.Right);\n        }\n    }\n\n    /// <summary>\n    ///     Get keys in the post-order order.\n    /// </summary>\n    /// <returns>Keys in the post-order order.</returns>\n    public IEnumerable<TKey> GetKeysPostOrder()\n    {\n        var result = new List<TKey>();\n        PostOrderWalk(root);\n        return result;\n\n        void PostOrderWalk(RedBlackTreeNode<TKey>? node)\n        {\n            if (node is null)\n            {\n                return;\n            }\n\n            PostOrderWalk(node.Left);\n            PostOrderWalk(node.Right);\n            result.Add(node.Key);\n        }\n    }\n\n    /// <summary>\n    ///     Perform binary tree insertion.\n    /// </summary>\n    /// <param name=\"node\">Root of subtree to search from.</param>\n    /// <param name=\"key\">Key value to insert.</param>\n    /// <returns>Node that was added.</returns>\n    private RedBlackTreeNode<TKey> Add(RedBlackTreeNode<TKey> node, TKey key)\n    {\n        int compareResult;\n        RedBlackTreeNode<TKey> newNode;\n        while (true)\n        {\n            compareResult = comparer.Compare(key, node!.Key);\n            if (compareResult < 0)\n            {\n                if (node.Left is null)\n                {\n                    newNode = new RedBlackTreeNode<TKey>(key, node);\n                    node.Left = newNode;\n                    break;\n                }\n                else\n                {\n                    node = node.Left;\n                }\n            }\n            else if (compareResult > 0)\n            {\n                if (node.Right is null)\n                {\n                    newNode = new RedBlackTreeNode<TKey>(key, node);\n                    node.Right = newNode;\n                    break;\n                }\n                else\n                {\n                    node = node.Right;\n                }\n            }\n            else\n            {\n                throw new ArgumentException($\"\"\"Key \"{key}\" already exists in tree!\"\"\");\n            }\n        }\n\n        return newNode;\n    }\n\n    /// <summary>\n    ///     Perform case 2 of insertion by pushing blackness down from parent.\n    /// </summary>\n    /// <param name=\"node\">Parent of inserted node.</param>\n    /// <returns>Grandparent of inserted node.</returns>\n    private RedBlackTreeNode<TKey>? AddCase2(RedBlackTreeNode<TKey> node)\n    {\n        var grandparent = node.Parent;\n        var parentDir = comparer.Compare(node.Key, node.Parent!.Key);\n        var uncle = parentDir < 0 ? grandparent!.Right : grandparent!.Left;\n\n        node.Color = NodeColor.Black;\n        uncle!.Color = NodeColor.Black;\n        grandparent.Color = NodeColor.Red;\n\n        // Keep root black\n        if (node.Parent.Parent is null)\n        {\n            node.Parent.Color = NodeColor.Black;\n        }\n\n        // Set current node as parent to move up tree\n        return node.Parent.Parent;\n    }\n\n    /// <summary>\n    ///     Perform rotations needed for cases 5 and 6 of insertion.\n    /// </summary>\n    /// <param name=\"node\">Parent of node just inserted.</param>\n    /// <param name=\"parentDir\">The side node is on of its parent.</param>\n    /// <param name=\"childDir\">The side the child node is on.</param>\n    private void AddCase56(RedBlackTreeNode<TKey> node, int parentDir, int childDir)\n    {\n        if (parentDir < 0)\n        {\n            // Case 5\n            if (childDir > 0)\n            {\n                node = RotateLeft(node);\n            }\n\n            // Case 6\n            node = RotateRight(node.Parent!);\n            node.Color = NodeColor.Black;\n            node.Right!.Color = NodeColor.Red;\n        }\n        else\n        {\n            // Case 5\n            if (childDir < 0)\n            {\n                node = RotateRight(node);\n            }\n\n            // Case 6\n            node = RotateLeft(node.Parent!);\n            node.Color = NodeColor.Black;\n            node.Left!.Color = NodeColor.Red;\n        }\n    }\n\n    /// <summary>\n    ///     Determine which add case applies to inserted node.\n    /// </summary>\n    /// <param name=\"node\">Parent of inserted node.</param>\n    /// <returns>Case number needed to get tree in valid state. Cases 5 and 6 are represented by 56.</returns>\n    private int GetAddCase(RedBlackTreeNode<TKey> node)\n    {\n        if (node.Color == NodeColor.Black)\n        {\n            return 1;\n        }\n        else if (node.Parent is null)\n        {\n            return 4;\n        }\n        else\n        {\n            // Remaining insert cases need uncle\n            var grandparent = node.Parent;\n            var parentDir = comparer.Compare(node.Key, node.Parent.Key);\n            var uncle = parentDir < 0 ? grandparent.Right : grandparent.Left;\n\n            // Case 5 & 6\n            if (uncle is null || uncle.Color == NodeColor.Black)\n            {\n                return 56;\n            }\n\n            return 2;\n        }\n    }\n\n    /// <summary>\n    ///     Search for the node to be deleted.\n    /// </summary>\n    /// <param name=\"node\">Node to start search from.</param>\n    /// <param name=\"key\">Key to search for.</param>\n    /// <returns>Node to be deleted.</returns>\n    private RedBlackTreeNode<TKey> Remove(RedBlackTreeNode<TKey>? node, TKey key)\n    {\n        if (node is null)\n        {\n            throw new InvalidOperationException(\"Tree is empty!\");\n        }\n        else if (!Contains(key))\n        {\n            throw new KeyNotFoundException($\"Key {key} is not in the tree!\");\n        }\n        else\n        {\n            // Find node\n            int dir;\n            while (true)\n            {\n                dir = comparer.Compare(key, node!.Key);\n                if (dir < 0)\n                {\n                    node = node.Left;\n                }\n                else if (dir > 0)\n                {\n                    node = node.Right;\n                }\n                else\n                {\n                    break;\n                }\n            }\n\n            return node;\n        }\n    }\n\n    /// <summary>\n    ///     Get the tree back into a valid state after removing non-root black leaf.\n    /// </summary>\n    /// <param name=\"node\">Non-root black leaf being removed.</param>\n    private RedBlackTreeNode<TKey>? RemoveRecolor(RedBlackTreeNode<TKey> node)\n    {\n        var removeCase = GetRemoveCase(node);\n\n        var dir = comparer.Compare(node.Key, node.Parent!.Key);\n\n        // Determine current node's sibling and nephews\n        var sibling = dir < 0 ? node.Parent.Right : node.Parent.Left;\n        var closeNewphew = dir < 0 ? sibling!.Left : sibling!.Right;\n        var distantNephew = dir < 0 ? sibling!.Right : sibling!.Left;\n\n        switch (removeCase)\n        {\n            case 1:\n                sibling.Color = NodeColor.Red;\n                return node.Parent;\n            case 3:\n                RemoveCase3(node, closeNewphew, dir);\n                break;\n            case 4:\n                RemoveCase4(sibling);\n                break;\n            case 5:\n                RemoveCase5(node, sibling, dir);\n                break;\n            case 6:\n                RemoveCase6(node, distantNephew!, dir);\n                break;\n            default:\n                throw new InvalidOperationException(\"It should not be possible to get here!\");\n        }\n\n        return null;\n    }\n\n    /// <summary>\n    ///     Simple removal cases where black height doesn't change.\n    /// </summary>\n    /// <param name=\"node\">Node to remove.</param>\n    /// <returns>Non-root black leaf node or null. Null indicates that removal was performed.</returns>\n    private RedBlackTreeNode<TKey>? RemoveSimpleCases(RedBlackTreeNode<TKey> node)\n    {\n        // Node to delete is root and has no children\n        if (node.Parent is null && node.Left is null && node.Right is null)\n        {\n            root = null;\n            Count--;\n            return null;\n        }\n\n        // Node has two children. Swap pointers\n        if (node.Left is not null && node.Right is not null)\n        {\n            var successor = GetMin(node.Right);\n            node.Key = successor.Key;\n            node = successor;\n        }\n\n        // At this point node should have at most one child\n        if (node.Color == NodeColor.Red)\n        {\n            // Node is red so it must have no children since it doesn't have two children\n            DeleteLeaf(node.Parent!, comparer.Compare(node.Key, node.Parent!.Key));\n\n            Count--;\n            return null;\n        }\n        else\n        {\n            // Node is black and may or may not be node\n            return RemoveBlackNode(node);\n        }\n    }\n\n    /// <summary>\n    ///     Node to delete is black. If it is a leaf then we need to recolor, otherwise remove it.\n    /// </summary>\n    /// <param name=\"node\">Black node to examine.</param>\n    /// <returns>Node to start recoloring from. Null if deletion occurred.</returns>\n    private RedBlackTreeNode<TKey>? RemoveBlackNode(RedBlackTreeNode<TKey> node)\n    {\n        // Node is black and has at most one child. If it has a child it must be red.\n        var child = node.Left ?? node.Right;\n\n        // Continue to recoloring if node is leaf\n        if (child is null)\n        {\n            return node;\n        }\n\n        // Recolor child\n        child.Color = NodeColor.Black;\n        child.Parent = node.Parent;\n\n        var childDir = node.Parent is null ? 0 : comparer.Compare(node.Key, node.Parent.Key);\n\n        // Replace node with child\n        Transplant(node.Parent, child, childDir);\n\n        Count--;\n        return null;\n    }\n\n    /// <summary>\n    ///     Perform case 3 of removal.\n    /// </summary>\n    /// <param name=\"node\">Node that was removed.</param>\n    /// <param name=\"closeNephew\">Close nephew of removed node.</param>\n    /// <param name=\"childDir\">Side of parent the removed node was.</param>\n    private void RemoveCase3(RedBlackTreeNode<TKey> node, RedBlackTreeNode<TKey>? closeNephew, int childDir)\n    {\n        // Rotate and recolor\n        var sibling = childDir < 0 ? RotateLeft(node.Parent!) : RotateRight(node.Parent!);\n        sibling.Color = NodeColor.Black;\n        if (childDir < 0)\n        {\n            sibling.Left!.Color = NodeColor.Red;\n        }\n        else\n        {\n            sibling.Right!.Color = NodeColor.Red;\n        }\n\n        // Get new distant newphew\n        sibling = closeNephew!;\n        var distantNephew = childDir < 0 ? sibling.Right : sibling.Left;\n\n        // Parent is red, sibling is black\n        if (distantNephew is not null && distantNephew.Color == NodeColor.Red)\n        {\n            RemoveCase6(node, distantNephew, childDir);\n            return;\n        }\n\n        // Get new close nephew\n        closeNephew = childDir < 0 ? sibling!.Left : sibling!.Right;\n\n        // Sibling is black, distant nephew is black\n        if (closeNephew is not null && closeNephew.Color == NodeColor.Red)\n        {\n            RemoveCase5(node, sibling!, childDir);\n            return;\n        }\n\n        // Final recoloring\n        RemoveCase4(sibling!);\n    }\n\n    /// <summary>\n    ///     Perform case 4 of removal.\n    /// </summary>\n    /// <param name=\"sibling\">Sibling of removed node.</param>\n    private void RemoveCase4(RedBlackTreeNode<TKey> sibling)\n    {\n        sibling.Color = NodeColor.Red;\n        sibling.Parent!.Color = NodeColor.Black;\n    }\n\n    /// <summary>\n    ///     Perform case 5 of removal.\n    /// </summary>\n    /// <param name=\"node\">Node that was removed.</param>\n    /// <param name=\"sibling\">Sibling of removed node.</param>\n    /// <param name=\"childDir\">Side of parent removed node was on.</param>\n    private void RemoveCase5(RedBlackTreeNode<TKey> node, RedBlackTreeNode<TKey> sibling, int childDir)\n    {\n        sibling = childDir < 0 ? RotateRight(sibling) : RotateLeft(sibling);\n        var distantNephew = childDir < 0 ? sibling.Right! : sibling.Left!;\n\n        sibling.Color = NodeColor.Black;\n        distantNephew.Color = NodeColor.Red;\n\n        RemoveCase6(node, distantNephew, childDir);\n    }\n\n    /// <summary>\n    ///     Perform case 6 of removal.\n    /// </summary>\n    /// <param name=\"node\">Node that was removed.</param>\n    /// <param name=\"distantNephew\">Distant nephew of removed node.</param>\n    /// <param name=\"childDir\">Side of parent removed node was on.</param>\n    private void RemoveCase6(RedBlackTreeNode<TKey> node, RedBlackTreeNode<TKey> distantNephew, int childDir)\n    {\n        var oldParent = node.Parent!;\n        node = childDir < 0 ? RotateLeft(oldParent) : RotateRight(oldParent);\n        node.Color = oldParent.Color;\n        oldParent.Color = NodeColor.Black;\n        distantNephew.Color = NodeColor.Black;\n    }\n\n    /// <summary>\n    ///     Determine which removal case is required.\n    /// </summary>\n    /// <param name=\"node\">Node being removed.</param>\n    /// <returns>Which removal case should be performed.</returns>\n    private int GetRemoveCase(RedBlackTreeNode<TKey> node)\n    {\n        var dir = comparer.Compare(node.Key, node.Parent!.Key);\n\n        // Determine current node's sibling and nephews\n        var sibling = dir < 0 ? node.Parent.Right : node.Parent.Left;\n        var closeNewphew = dir < 0 ? sibling!.Left : sibling!.Right;\n        var distantNephew = dir < 0 ? sibling!.Right : sibling!.Left;\n\n        if (sibling.Color == NodeColor.Red)\n        {\n            return 3;\n        }\n        else if (distantNephew is not null && distantNephew.Color == NodeColor.Red)\n        {\n            return 6;\n        }\n        else if (closeNewphew is not null && closeNewphew.Color == NodeColor.Red)\n        {\n            return 5;\n        }\n        else if (node.Parent.Color == NodeColor.Red)\n        {\n            return 4;\n        }\n        else\n        {\n            return 1;\n        }\n    }\n\n    /// <summary>\n    ///     Set child of node or delete leaf.\n    /// </summary>\n    /// <param name=\"node\">Node to set child of. Set to null for root.</param>\n    /// <param name=\"child\">Node to set as child.</param>\n    /// <param name=\"dir\">Which side of node to place child.</param>\n    private void Transplant(RedBlackTreeNode<TKey>? node, RedBlackTreeNode<TKey>? child, int dir)\n    {\n        if (node is null)\n        {\n            root = child;\n        }\n        else if (child is null)\n        {\n            DeleteLeaf(node, dir);\n        }\n        else if (dir < 0)\n        {\n            node.Left = child;\n        }\n        else\n        {\n            node.Right = child;\n        }\n    }\n\n    /// <summary>\n    ///     Delete leaf node.\n    /// </summary>\n    /// <param name=\"node\">Parent of leaf node to delete.</param>\n    /// <param name=\"dir\">Side of parent leaf is on.</param>\n    private void DeleteLeaf(RedBlackTreeNode<TKey> node, int dir)\n    {\n        if (dir < 0)\n        {\n            node.Left = null;\n        }\n        else\n        {\n            node.Right = null;\n        }\n    }\n\n    /// <summary>\n    ///     Perform a left (counter-clockwise) rotation.\n    /// </summary>\n    /// <param name=\"node\">Node to rotate about.</param>\n    /// <returns>New node with rotation applied.</returns>\n    private RedBlackTreeNode<TKey> RotateLeft(RedBlackTreeNode<TKey> node)\n    {\n        var temp1 = node;\n        var temp2 = node!.Right!.Left;\n\n        node = node.Right;\n        node.Parent = temp1.Parent;\n        if (node.Parent is not null)\n        {\n            var nodeDir = comparer.Compare(node.Key, node.Parent.Key);\n            if (nodeDir < 0)\n            {\n                node.Parent.Left = node;\n            }\n            else\n            {\n                node.Parent.Right = node;\n            }\n        }\n\n        node.Left = temp1;\n        node.Left.Parent = node;\n\n        node.Left.Right = temp2;\n        if (temp2 is not null)\n        {\n            node.Left.Right!.Parent = temp1;\n        }\n\n        if (node.Parent is null)\n        {\n            root = node;\n        }\n\n        return node;\n    }\n\n    /// <summary>\n    ///     Perform a right (clockwise) rotation.\n    /// </summary>\n    /// <param name=\"node\">Node to rotate about.</param>\n    /// <returns>New node with rotation applied.</returns>\n    private RedBlackTreeNode<TKey> RotateRight(RedBlackTreeNode<TKey> node)\n    {\n        var temp1 = node;\n        var temp2 = node!.Left!.Right;\n\n        node = node.Left;\n        node.Parent = temp1.Parent;\n        if (node.Parent is not null)\n        {\n            var nodeDir = comparer.Compare(node.Key, node.Parent.Key);\n            if (nodeDir < 0)\n            {\n                node.Parent.Left = node;\n            }\n            else\n            {\n                node.Parent.Right = node;\n            }\n        }\n\n        node.Right = temp1;\n        node.Right.Parent = node;\n\n        node.Right.Left = temp2;\n        if (temp2 is not null)\n        {\n            node.Right.Left!.Parent = temp1;\n        }\n\n        if (node.Parent is null)\n        {\n            root = node;\n        }\n\n        return node;\n    }\n\n    /// <summary>\n    ///     Helper function to get node instance with minimum key value\n    ///     in the specified subtree.\n    /// </summary>\n    /// <param name=\"node\">Node specifying root of subtree.</param>\n    /// <returns>Minimum value in node's subtree.</returns>\n    private RedBlackTreeNode<TKey> GetMin(RedBlackTreeNode<TKey> node)\n    {\n        while (node.Left is not null)\n        {\n            node = node.Left;\n        }\n\n        return node;\n    }\n\n    /// <summary>\n    ///     Helper function to get node instance with maximum key value\n    ///     in the specified subtree.\n    /// </summary>\n    /// <param name=\"node\">Node specifyng root of subtree.</param>\n    /// <returns>Maximum value in node's subtree.</returns>\n    private RedBlackTreeNode<TKey> GetMax(RedBlackTreeNode<TKey> node)\n    {\n        while (node.Right is not null)\n        {\n            node = node.Right;\n        }\n\n        return node;\n    }\n}\n"
  },
  {
    "path": "DataStructures/RedBlackTree/RedBlackTreeNode.cs",
    "content": "namespace DataStructures.RedBlackTree;\n\n/// <summary>\n///     Enum to represent node colors.\n/// </summary>\npublic enum NodeColor : byte\n{\n    /// <summary>\n    ///     Represents red node.\n    /// </summary>\n    Red,\n\n    /// <summary>\n    ///     Represents black node.\n    /// </summary>\n    Black,\n}\n\n/// <summary>\n///     Generic class to represent nodes in an <see cref=\"RedBlackTree{TKey}\"/> instance.\n/// </summary>\n/// <typeparam name=\"TKey\">The type of key for the node.</typeparam>\n/// <remarks>\n///  Initializes a new instance of the <see cref=\"RedBlackTreeNode{TKey}\"/> class.\n/// </remarks>\n/// <param name=\"key\">Key value for node.</param>\n/// <param name=\"parent\">Parent of node.</param>\npublic class RedBlackTreeNode<TKey>(TKey key, RedBlackTreeNode<TKey>? parent)\n{\n    /// <summary>\n    ///     Gets or sets key value of node.\n    /// </summary>\n    public TKey Key { get; set; } = key;\n\n    /// <summary>\n    ///     Gets or sets the color of the node.\n    /// </summary>\n    public NodeColor Color { get; set; }\n\n    /// <summary>\n    ///     Gets or sets the parent of the node.\n    /// </summary>\n    public RedBlackTreeNode<TKey>? Parent { get; set; } = parent;\n\n    /// <summary>\n    ///     Gets or sets left child of the node.\n    /// </summary>\n    public RedBlackTreeNode<TKey>? Left { get; set; }\n\n    /// <summary>\n    ///     Gets or sets the right child of the node.\n    /// </summary>\n    public RedBlackTreeNode<TKey>? Right { get; set; }\n}\n"
  },
  {
    "path": "DataStructures/ScapegoatTree/Extensions.cs",
    "content": "namespace DataStructures.ScapegoatTree;\n\npublic static class Extensions\n{\n    /// <summary>\n    /// Flattens scapegoat tree into a list of nodes.\n    /// </summary>\n    /// <param name=\"root\">Scapegoat tree provided as root node.</param>\n    /// <param name=\"list\">An empty list.</param>\n    /// <typeparam name=\"TKey\">Scapegoat tree node key type.</typeparam>\n    public static void FlattenTree<TKey>(Node<TKey> root, List<Node<TKey>> list) where TKey : IComparable\n    {\n        if (root.Left != null)\n        {\n            FlattenTree(root.Left, list);\n        }\n\n        list.Add(root);\n\n        if (root.Right != null)\n        {\n            FlattenTree(root.Right, list);\n        }\n    }\n\n    /// <summary>\n    /// Rebuilds a scapegoat tree from list of nodes.\n    /// Use with <see cref=\"FlattenTree{TKey}\"/> method.\n    /// </summary>\n    /// <param name=\"list\">Flattened tree.</param>\n    /// <param name=\"start\">Start index.</param>\n    /// <param name=\"end\">End index.</param>\n    /// <typeparam name=\"TKey\">Scapegoat tree node key type.</typeparam>\n    /// <returns>Scapegoat tree root node.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown if start index is invalid.</exception>\n    public static Node<TKey> RebuildFromList<TKey>(IList<Node<TKey>> list, int start, int end)\n        where TKey : IComparable\n    {\n        if (start > end)\n        {\n            throw new ArgumentException(\"The parameter's value is invalid.\", nameof(start));\n        }\n\n        var pivot = Convert.ToInt32(Math.Ceiling(start + (end - start) / 2.0));\n\n        return new Node<TKey>(list[pivot].Key)\n        {\n            Left = start > (pivot - 1) ? null : RebuildFromList(list, start, pivot - 1),\n            Right = (pivot + 1) > end ? null : RebuildFromList(list, pivot + 1, end),\n        };\n    }\n}\n"
  },
  {
    "path": "DataStructures/ScapegoatTree/Node.cs",
    "content": "namespace DataStructures.ScapegoatTree;\n\n/// <summary>\n/// Scapegoat tree node class.\n/// </summary>\n/// <typeparam name=\"TKey\">Scapegoat tree node key type.</typeparam>\npublic class Node<TKey>(TKey key) where TKey : IComparable\n{\n    private Node<TKey>? right;\n    private Node<TKey>? left;\n\n    public TKey Key { get; } = key;\n\n    public Node<TKey>? Right\n    {\n        get => right;\n        set\n        {\n            if (value != null && !value.IsGreaterThanOrSameAs(Key))\n            {\n                throw new ArgumentException(\"The value's key is smaller than or equal to node's right child's key.\", nameof(value));\n            }\n\n            right = value;\n        }\n    }\n\n    public Node<TKey>? Left\n    {\n        get => left;\n        set\n        {\n            if (value != null && value.IsGreaterThanOrSameAs(Key))\n            {\n                throw new ArgumentException(\"The value's key is greater than or equal to node's left child's key.\", nameof(value));\n            }\n\n            left = value;\n        }\n    }\n\n    public Node(TKey key, Node<TKey>? right, Node<TKey>? left)\n        : this(key)\n    {\n        Right = right;\n        Left = left;\n    }\n\n    /// <summary>\n    /// Returns number of elements in the tree.\n    /// </summary>\n    /// <returns>Number of elements in the tree.</returns>\n    public int GetSize() => (Left?.GetSize() ?? 0) + 1 + (Right?.GetSize() ?? 0);\n\n    /// <summary>\n    /// Gets alpha height of the current node.\n    /// </summary>\n    /// <param name=\"alpha\">Alpha value.</param>\n    /// <returns>Alpha height value.</returns>\n    public double GetAlphaHeight(double alpha) => Math.Floor(Math.Log(GetSize(), 1.0 / alpha));\n\n    public Node<TKey> GetSmallestKeyNode() => Left?.GetSmallestKeyNode() ?? this;\n\n    public Node<TKey> GetLargestKeyNode() => Right?.GetLargestKeyNode() ?? this;\n\n    /// <summary>\n    /// Checks if the current node is alpha weight balanced.\n    /// </summary>\n    /// <param name=\"a\">Alpha value.</param>\n    /// <returns>True - if node is alpha weight balanced. If not - false.</returns>\n    public bool IsAlphaWeightBalanced(double a)\n    {\n        var isLeftBalanced = (Left?.GetSize() ?? 0) <= a * GetSize();\n        var isRightBalanced = (Right?.GetSize() ?? 0) <= a * GetSize();\n\n        return isLeftBalanced && isRightBalanced;\n    }\n\n    private bool IsGreaterThanOrSameAs(TKey key)\n    {\n        return Key.CompareTo(key) >= 0;\n    }\n}\n"
  },
  {
    "path": "DataStructures/ScapegoatTree/ScapegoatTree.cs",
    "content": "namespace DataStructures.ScapegoatTree;\n\n/// <summary>\n/// A scapegoat implementation class.\n/// See https://en.wikipedia.org/wiki/Scapegoat_tree for more information about scapegoat tree.\n/// </summary>\n/// <typeparam name=\"TKey\">The scapegoat tree key type.</typeparam>\npublic class ScapegoatTree<TKey> where TKey : IComparable\n{\n    /// <summary>\n    /// Gets the α (alpha) value of the tree.\n    /// </summary>\n    public double Alpha { get; private set; }\n\n    /// <summary>\n    /// Gets the root node of the tree.\n    /// </summary>\n    public Node<TKey>? Root { get; private set; }\n\n    /// <summary>\n    /// Gets the number of nodes in the tree.\n    /// </summary>\n    public int Size { get; private set; }\n\n    /// <summary>\n    /// Gets the maximal value of the tree Size since the last time the tree was completely rebuilt.\n    /// </summary>\n    public int MaxSize { get; private set; }\n\n    /// <summary>\n    /// Gets an event handler which will fire when tree is being balanced.\n    /// </summary>\n    public event EventHandler? TreeIsUnbalanced;\n\n    public ScapegoatTree()\n        : this(alpha: 0.5, size: 0)\n    {\n    }\n\n    public ScapegoatTree(double alpha)\n        : this(alpha, size: 0)\n    {\n    }\n\n    public ScapegoatTree(Node<TKey> node, double alpha)\n        : this(alpha, size: node.GetSize())\n    {\n        Root = node;\n    }\n\n    public ScapegoatTree(TKey key, double alpha = 0.5)\n        : this(alpha, size: 1)\n    {\n        Root = new Node<TKey>(key);\n    }\n\n    private ScapegoatTree(double alpha, int size)\n    {\n        CheckAlpha(alpha);\n\n        Alpha = alpha;\n\n        Size = size;\n        MaxSize = size;\n    }\n\n    /// <summary>\n    /// Checks if current instance of the scapegoat tree is alpha weight balanced.\n    /// </summary>\n    /// <returns>True - if tree is alpha weight balanced. Otherwise, false.</returns>\n    public bool IsAlphaWeightBalanced()\n    {\n        return Root?.IsAlphaWeightBalanced(Alpha) ?? true;\n    }\n\n    /// <summary>\n    /// Check if any node in the tree has specified key value.\n    /// </summary>\n    /// <param name=\"key\">Key value.</param>\n    /// <returns>Returns true if node exists, false if not.</returns>\n    public bool Contains(TKey key)\n    {\n        return Search(key) != null;\n    }\n\n    /// <summary>\n    /// Searches current instance of the scapegoat tree for specified key.\n    /// </summary>\n    /// <param name=\"key\">Key value.</param>\n    /// <returns>Node with the specified key or null.</returns>\n    public Node<TKey>? Search(TKey key)\n    {\n        if (Root == null)\n        {\n            return null;\n        }\n\n        var current = Root;\n\n        while (true)\n        {\n            var result = current.Key.CompareTo(key);\n\n            switch (result)\n            {\n                case 0:\n                    return current;\n                case > 0 when current.Left != null:\n                    current = current.Left;\n                    break;\n                case < 0 when current.Right != null:\n                    current = current.Right;\n                    break;\n                default:\n                    return null;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Inserts a new key into current instance of the scapegoat tree. Rebuilds tree if it's unbalanced.\n    /// </summary>\n    /// <param name=\"key\">Key value.</param>\n    /// <returns>True - if insertion is successful, false - if the key is already present in the tree.</returns>\n    public bool Insert(TKey key)\n    {\n        var node = new Node<TKey>(key);\n\n        if (Root == null)\n        {\n            Root = node;\n\n            UpdateSizes();\n\n            return true;\n        }\n\n        var path = new Stack<Node<TKey>>();\n\n        var current = Root;\n\n        var found = false;\n\n        while (!found)\n        {\n            path.Push(current);\n\n            var result = current.Key.CompareTo(node.Key);\n\n            switch (result)\n            {\n                case < 0 when current.Right != null:\n                    current = current.Right;\n                    continue;\n                case < 0:\n                    current.Right = node;\n                    found = true;\n                    break;\n                case > 0 when current.Left != null:\n                    current = current.Left;\n                    continue;\n                case > 0:\n                    current.Left = node;\n                    found = true;\n                    break;\n                default:\n                    return false;\n            }\n        }\n\n        UpdateSizes();\n\n        if (path.Count > Root.GetAlphaHeight(Alpha))\n        {\n            TreeIsUnbalanced?.Invoke(this, EventArgs.Empty);\n\n            BalanceFromPath(path);\n\n            MaxSize = Math.Max(MaxSize, Size);\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    /// Removes the specified key from the current instance of the scapegoat tree. Rebuilds tree if it's unbalanced.\n    /// </summary>\n    /// <param name=\"key\">Key value.</param>\n    /// <returns>True - if key was successfully removed, false - if the key wasn't found in the tree.</returns>\n    public bool Delete(TKey key)\n    {\n        if (Root == null)\n        {\n            return false;\n        }\n\n        if (Remove(Root, Root, key))\n        {\n            Size--;\n\n            if (Root != null && Size < Alpha * MaxSize)\n            {\n                TreeIsUnbalanced?.Invoke(this, EventArgs.Empty);\n\n                var list = new List<Node<TKey>>();\n\n                Extensions.FlattenTree(Root, list);\n\n                Root = Extensions.RebuildFromList(list, 0, list.Count - 1);\n\n                MaxSize = Size;\n            }\n\n            return true;\n        }\n\n        return false;\n    }\n\n    /// <summary>\n    /// Clears the tree.\n    /// </summary>\n    public void Clear()\n    {\n        Size = 0;\n        MaxSize = 0;\n        Root = null;\n    }\n\n    /// <summary>\n    /// Changes <see cref=\"Alpha\"/> value to adjust balancing.\n    /// </summary>\n    /// <param name=\"value\">New alpha value.</param>\n    public void Tune(double value)\n    {\n        CheckAlpha(value);\n        Alpha = value;\n    }\n\n    /// <summary>\n    /// Searches for a scapegoat node in provided stack.\n    /// </summary>\n    /// <param name=\"path\">Stack instance with nodes, starting with root node.</param>\n    /// <returns>Scapegoat node with its parent node. Parent can be null if scapegoat node is root node.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown if path stack is empty.</exception>\n    /// <exception cref=\"InvalidOperationException\">Thrown if scapegoat wasn't found.</exception>\n    public (Node<TKey>? Parent, Node<TKey> Scapegoat) FindScapegoatInPath(Stack<Node<TKey>> path)\n    {\n        if (path.Count == 0)\n        {\n            throw new ArgumentException(\"The path collection should not be empty.\", nameof(path));\n        }\n\n        var depth = 1;\n\n        while (path.TryPop(out var next))\n        {\n            if (depth > next.GetAlphaHeight(Alpha))\n            {\n                return path.TryPop(out var parent) ? (parent, next) : (null, next);\n            }\n\n            depth++;\n        }\n\n        throw new InvalidOperationException(\"Scapegoat node wasn't found. The tree should be unbalanced.\");\n    }\n\n    private static void CheckAlpha(double alpha)\n    {\n        if (alpha is < 0.5 or > 1.0)\n        {\n            throw new ArgumentException(\"The alpha parameter's value should be in 0.5..1.0 range.\", nameof(alpha));\n        }\n    }\n\n    private bool Remove(Node<TKey>? parent, Node<TKey>? node, TKey key)\n    {\n        if (node is null || parent is null)\n        {\n            return false;\n        }\n\n        var compareResult = node.Key.CompareTo(key);\n\n        if (compareResult > 0)\n        {\n            return Remove(node, node.Left, key);\n        }\n\n        if (compareResult < 0)\n        {\n            return Remove(node, node.Right, key);\n        }\n\n        Node<TKey>? replacementNode;\n\n        // Case 0: Node has no children.\n        // Case 1: Node has one child.\n        if (node.Left is null || node.Right is null)\n        {\n            replacementNode = node.Left ?? node.Right;\n        }\n\n        // Case 2: Node has two children. (This implementation uses the in-order predecessor to replace node.)\n        else\n        {\n            var predecessorNode = node.Left.GetLargestKeyNode();\n            Remove(Root, Root, predecessorNode.Key);\n            replacementNode = new Node<TKey>(predecessorNode.Key)\n            {\n                Left = node.Left,\n                Right = node.Right,\n            };\n        }\n\n        // Replace the relevant node with a replacement found in the previous stages.\n        // Special case for replacing the root node.\n        if (node == Root)\n        {\n            Root = replacementNode;\n        }\n        else if (parent.Left == node)\n        {\n            parent.Left = replacementNode;\n        }\n        else\n        {\n            parent.Right = replacementNode;\n        }\n\n        return true;\n    }\n\n    private void BalanceFromPath(Stack<Node<TKey>> path)\n    {\n        var (parent, scapegoat) = FindScapegoatInPath(path);\n\n        var list = new List<Node<TKey>>();\n\n        Extensions.FlattenTree(scapegoat, list);\n\n        var tree = Extensions.RebuildFromList(list, 0, list.Count - 1);\n\n        if (parent == null)\n        {\n            Root = tree;\n        }\n        else\n        {\n            var result = parent.Key.CompareTo(tree.Key);\n\n            if (result < 0)\n            {\n                parent.Right = tree;\n            }\n            else\n            {\n                parent.Left = tree;\n            }\n        }\n    }\n\n    private void UpdateSizes()\n    {\n        Size += 1;\n        MaxSize = Math.Max(Size, MaxSize);\n    }\n}\n"
  },
  {
    "path": "DataStructures/SegmentTrees/SegmentTree.cs",
    "content": "namespace DataStructures.SegmentTrees;\n\n/// <summary>\n///     Goal:   Data structure with which you can quickly perform queries on an array (i.e. sum of subarray)\n///     and at the same time efficiently update an entry\n///     or apply a distributive operation to a subarray.\n///     Idea:   Preprocessing special queries\n///     Hint:   The query operation HAS to be associative (in this example addition).\n/// </summary>\npublic class SegmentTree\n{\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"SegmentTree\" /> class.\n    ///     Runtime complexity: O(n) where n equals the array-length.\n    /// </summary>\n    /// <param name=\"arr\">Array on which the queries should be made.</param>\n    public SegmentTree(int[] arr)\n    {\n        // Calculates next power of two\n        var pow = (int)Math.Pow(2, Math.Ceiling(Math.Log(arr.Length, 2)));\n        Tree = new int[2 * pow];\n\n        // Transfers the input array into the last half of the segment tree array\n        Array.Copy(arr, 0, Tree, pow, arr.Length);\n\n        // Calculates the first half\n        for (var i = pow - 1; i > 0; --i)\n        {\n            Tree[i] = Tree[Left(i)] + Tree[Right(i)];\n        }\n    }\n\n    /// <summary>Gets the segment tree array.</summary>\n    public int[] Tree { get; }\n\n    /// <summary>\n    ///     Starts a query.\n    ///     Runtime complexity: O(logN) where n equals the array-length.\n    /// </summary>\n    /// <param name=\"l\">Left border of the query.</param>\n    /// <param name=\"r\">Right border of the query.</param>\n    /// <returns>Sum of the subarray between <c>l</c> and <c>r</c> (including <c>l</c> and <c>r</c>).</returns>\n    // Editing of query start at node with 1.\n    // Node with index 1 includes the whole input subarray.\n    public int Query(int l, int r) =>\n        Query(++l, ++r, 1, Tree.Length / 2, 1);\n\n    /// <summary>\n    ///     Calculates the right child of a node.\n    /// </summary>\n    /// <param name=\"node\">Current node.</param>\n    /// <returns>Index of the right child.</returns>\n    protected int Right(int node) => 2 * node + 1;\n\n    /// <summary>\n    ///     Calculates the left child of a node.\n    /// </summary>\n    /// <param name=\"node\">Current node.</param>\n    /// <returns>Index of the left child.</returns>\n    protected int Left(int node) => 2 * node;\n\n    /// <summary>\n    ///     Calculates the parent of a node.\n    /// </summary>\n    /// <param name=\"node\">Current node.</param>\n    /// <returns>Index of the parent node.</returns>\n    protected int Parent(int node) => node / 2;\n\n    /// <summary>\n    ///     Edits a query.\n    /// </summary>\n    /// <param name=\"l\">Left border of the query.</param>\n    /// <param name=\"r\">Right border of the query.</param>\n    /// <param name=\"a\">Left end of the subarray enclosed by <c>i</c>.</param>\n    /// <param name=\"b\">Right end of the subarray enclosed by <c>i</c>.</param>\n    /// <param name=\"i\">Current node.</param>\n    /// <returns>Sum of a subarray between <c>l</c> and <c>r</c> (including <c>l</c> and <c>r</c>).</returns>\n    protected virtual int Query(int l, int r, int a, int b, int i)\n    {\n        // If a and b are in the (by l and r) specified subarray\n        if (l <= a && b <= r)\n        {\n            return Tree[i];\n        }\n\n        // If a or b are out of the by l and r specified subarray\n        if (r < a || b < l)\n        {\n            // Returns the neutral value of the operation\n            // (in this case 0, because x + 0 = x)\n            return 0;\n        }\n\n        // Calculates index m of the node that cuts the current subarray in half\n        var m = (a + b) / 2;\n\n        // Start query of new two subarrays a:m and m+1:b\n        // The right and left child cover this intervals\n        return Query(l, r, a, m, Left(i)) + Query(l, r, m + 1, b, Right(i));\n    }\n}\n"
  },
  {
    "path": "DataStructures/SegmentTrees/SegmentTreeApply.cs",
    "content": "namespace DataStructures.SegmentTrees;\n\n/// <summary>\n///     This is an extension of a segment tree, which allows applying distributive operations to a subarray\n///     (in this case multiplication).\n/// </summary>\npublic class SegmentTreeApply : SegmentTree\n{\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"SegmentTreeApply\" /> class.\n    ///     Runtime complexity: O(n) where n equals the array-length.\n    /// </summary>\n    /// <param name=\"arr\">Array on which the operations should be made.</param>\n    public SegmentTreeApply(int[] arr)\n        : base(arr)\n    {\n        // Initilizes and fills \"operand\" array with neutral element (in this case 1, because value * 1 = value)\n        Operand = new int[Tree.Length];\n        Array.Fill(Operand, 1);\n    }\n\n    /// <summary>\n    ///     Gets an array that stores for each node an operand,\n    ///     which must be applied to all direct and indirect child nodes of this node\n    ///     (but not to the node itself).\n    /// </summary>\n    public int[] Operand { get; }\n\n    /// <summary>\n    ///     Applies a distributive operation to a subarray defined by <c>l</c> and <c>r</c>\n    ///     (in this case multiplication by <c>value</c>).\n    ///     Runtime complexity: O(logN) where N equals the initial array-length.\n    /// </summary>\n    /// <param name=\"l\">Left border of the subarray.</param>\n    /// <param name=\"r\">Right border of the subarray.</param>\n    /// <param name=\"value\">Value with which each element of the interval is calculated.</param>\n    public void Apply(int l, int r, int value)\n    {\n        // The Application start at node with 1\n        // Node with index 1 includes the whole input subarray\n        Apply(++l, ++r, value, 1, Tree.Length / 2, 1);\n    }\n\n    /// <summary>\n    ///     Edits a query.\n    /// </summary>\n    /// <param name=\"l\">Left border of the query.</param>\n    /// <param name=\"r\">Right border of the query.</param>\n    /// <param name=\"a\">Left end of the subarray enclosed by <c>i</c>.</param>\n    /// <param name=\"b\">Right end of the subarray enclosed by <c>i</c>.</param>\n    /// <param name=\"i\">Current node.</param>\n    /// <returns>Sum of a subarray between <c>l</c> and <c>r</c> (including <c>l</c> and <c>r</c>).</returns>\n    protected override int Query(int l, int r, int a, int b, int i)\n    {\n        if (l <= a && b <= r)\n        {\n            return Tree[i];\n        }\n\n        if (r < a || b < l)\n        {\n            return 0;\n        }\n\n        var m = (a + b) / 2;\n\n        // Application of the saved operand to the direct and indrect child nodes\n        return Operand[i] * (Query(l, r, a, m, Left(i)) + Query(l, r, m + 1, b, Right(i)));\n    }\n\n    /// <summary>\n    ///     Applies the operation.\n    /// </summary>\n    /// <param name=\"l\">Left border of the Application.</param>\n    /// <param name=\"r\">Right border of the Application.</param>\n    /// <param name=\"value\">Multiplier by which the subarray is to be multiplied.</param>\n    /// <param name=\"a\">Left end of the subarray enclosed by <c>i</c>.</param>\n    /// <param name=\"b\">Right end of the subarray enclosed by <c>i</c>.</param>\n    /// <param name=\"i\">Current node.</param>\n    private void Apply(int l, int r, int value, int a, int b, int i)\n    {\n        // If a and b are in the (by l and r) specified subarray\n        if (l <= a && b <= r)\n        {\n            // Applies the operation to the current node and saves it for the direct and indirect child nodes\n            Operand[i] = value * Operand[i];\n            Tree[i] = value * Tree[i];\n            return;\n        }\n\n        // If a or b are out of the by l and r specified subarray stop application at this node\n        if (r < a || b < l)\n        {\n            return;\n        }\n\n        // Calculates index m of the node that cuts the current subarray in half\n        var m = (a + b) / 2;\n\n        // Applies the operation to both halfes\n        Apply(l, r, value, a, m, Left(i));\n        Apply(l, r, value, m + 1, b, Right(i));\n\n        // Recalculates the value of this node by its (possibly new) children.\n        Tree[i] = Operand[i] * (Tree[Left(i)] + Tree[Right(i)]);\n    }\n}\n"
  },
  {
    "path": "DataStructures/SegmentTrees/SegmentTreeUpdate.cs",
    "content": "namespace DataStructures.SegmentTrees;\n\n/// <summary>\n///     This is an extension of a segment tree, which allows the update of a single element.\n/// </summary>\n/// <remarks>\n///     Initializes a new instance of the <see cref=\"SegmentTreeUpdate\" /> class.\n///     Runtime complexity: O(n) where n equals the array-length.\n/// </remarks>\n/// <param name=\"arr\">Array on which the queries should be made.</param>\npublic class SegmentTreeUpdate(int[] arr) : SegmentTree(arr)\n{\n    /// <summary>\n    ///     Updates a single element of the input array.\n    ///     Changes the leaf first and updates its parents afterwards.\n    ///     Runtime complexity: O(logN) where N equals the initial array-length.\n    /// </summary>\n    /// <param name=\"node\">Index of the node that should be updated.</param>\n    /// <param name=\"value\">New Value of the element.</param>\n    public void Update(int node, int value)\n    {\n        Tree[node + Tree.Length / 2] = value;\n        Propagate(Parent(node + Tree.Length / 2));\n    }\n\n    /// <summary>\n    ///     Recalculates the value of node by its children.\n    ///     Calls its parent to do the same.\n    /// </summary>\n    /// <param name=\"node\">Index of current node.</param>\n    private void Propagate(int node)\n    {\n        if (node == 0)\n        {\n            // passed root\n            return;\n        }\n\n        Tree[node] = Tree[Left(node)] + Tree[Right(node)];\n        Propagate(Parent(node));\n    }\n}\n"
  },
  {
    "path": "DataStructures/SortedList.cs",
    "content": "using System.Collections;\n\nnamespace DataStructures;\n\n/// <summary>\n///     Implementation of SortedList using binary search.\n/// </summary>\n/// <typeparam name=\"T\">Generic Type.</typeparam>\n/// <remarks>\n///     Initializes a new instance of the <see cref=\"SortedList{T}\" /> class.\n/// </remarks>\n/// <param name=\"comparer\">Comparer user for binary search.</param>\npublic class SortedList<T>(IComparer<T> comparer) : IEnumerable<T>\n{\n    private readonly IComparer<T> comparer = comparer;\n    private readonly List<T> memory = [];\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"SortedList{T}\" /> class. Uses a Comparer.Default for type T.\n    /// </summary>\n    public SortedList()\n        : this(Comparer<T>.Default)\n    {\n    }\n\n    /// <summary>\n    ///     Gets the number of elements containing in <see cref=\"SortedList{T}\" />.\n    /// </summary>\n    public int Count => memory.Count;\n\n    /// <summary>\n    ///     Adds new item to <see cref=\"SortedList{T}\" /> instance, maintaining the order.\n    /// </summary>\n    /// <param name=\"item\">An element to insert.</param>\n    public void Add(T item)\n    {\n        var index = IndexFor(item, out _);\n        memory.Insert(index, item);\n    }\n\n    /// <summary>\n    ///     Gets an element of <see cref=\"SortedList{T}\" /> at specified index.\n    /// </summary>\n    /// <param name=\"i\">Index.</param>\n    public T this[int i] => memory[i];\n\n    /// <summary>\n    /// Removes all elements from <see cref=\"SortedList{T}\" />.\n    /// </summary>\n    public void Clear()\n        => memory.Clear();\n\n    /// <summary>\n    /// Indicates whether a <see cref=\"SortedList{T}\" /> contains a certain element.\n    /// </summary>\n    /// <param name=\"item\">An element to search.</param>\n    /// <returns>true - <see cref=\"SortedList{T}\" /> contains an element, otherwise - false.</returns>\n    public bool Contains(T item)\n    {\n        _ = IndexFor(item, out var found);\n        return found;\n    }\n\n    /// <summary>\n    /// Removes a certain element from <see cref=\"SortedList{T}\" />.\n    /// </summary>\n    /// <param name=\"item\">An element to remove.</param>\n    /// <returns>true - element is found and removed, otherwise false.</returns>\n    public bool TryRemove(T item)\n    {\n        var index = IndexFor(item, out var found);\n\n        if (found)\n        {\n            memory.RemoveAt(index);\n        }\n\n        return found;\n    }\n\n    /// <summary>\n    /// Returns an enumerator that iterates through the <see cref=\"SortedList{T}\" />.\n    /// </summary>\n    /// <returns>A Enumerator for the <see cref=\"SortedList{T}\" />.</returns>\n    public IEnumerator<T> GetEnumerator()\n        => memory.GetEnumerator();\n\n    /// <inheritdoc cref=\"IEnumerable.GetEnumerator\"/>\n    IEnumerator IEnumerable.GetEnumerator()\n        => GetEnumerator();\n\n    /// <summary>\n    /// Binary search algorithm for finding element index in <see cref=\"SortedList{T}\" />.\n    /// </summary>\n    /// <param name=\"item\">Element.</param>\n    /// <param name=\"found\">Indicates whether the equal value was found in <see cref=\"SortedList{T}\" />.</param>\n    /// <returns>Index for the Element.</returns>\n    private int IndexFor(T item, out bool found)\n    {\n        var left = 0;\n        var right = memory.Count;\n\n        while (right - left > 0)\n        {\n            var mid = (left + right) / 2;\n\n            switch (comparer.Compare(item, memory[mid]))\n            {\n                case > 0:\n                    left = mid + 1;\n                    break;\n                case < 0:\n                    right = mid;\n                    break;\n                default:\n                    found = true;\n                    return mid;\n            }\n        }\n\n        found = false;\n        return left;\n    }\n}\n"
  },
  {
    "path": "DataStructures/Stack/ArrayBasedStack.cs",
    "content": "namespace DataStructures.Stack;\n\n/// <summary>\n///     Implementation of an array-based stack. LIFO style.\n/// </summary>\n/// <typeparam name=\"T\">Generic Type.</typeparam>\npublic class ArrayBasedStack<T>\n{\n    private const int DefaultCapacity = 10;\n    private const string StackEmptyErrorMessage = \"Stack is empty\";\n\n    /// <summary>\n    ///     <see cref=\"Array\" /> based stack.\n    /// </summary>\n    private T[] stack;\n\n    /// <summary>\n    ///     How many items are in the stack right now.\n    /// </summary>\n    private int top;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"ArrayBasedStack{T}\" /> class.\n    /// </summary>\n    public ArrayBasedStack()\n    {\n        stack = new T[DefaultCapacity];\n        top = -1;\n    }\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"ArrayBasedStack{T}\" /> class.\n    /// </summary>\n    /// <param name=\"item\">Item to push onto the <see cref=\"ArrayBasedStack{T}\" />.</param>\n    public ArrayBasedStack(T item)\n        : this() => Push(item);\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"ArrayBasedStack{T}\" /> class.\n    /// </summary>\n    /// <param name=\"items\">Items to push onto the <see cref=\"ArrayBasedStack{T}\" />.</param>\n    public ArrayBasedStack(T[] items)\n    {\n        stack = items;\n        top = items.Length - 1;\n    }\n\n    /// <summary>\n    ///     Gets the number of elements on the <see cref=\"ArrayBasedStack{T}\" />.\n    /// </summary>\n    public int Top => top;\n\n    /// <summary>\n    ///     Gets or sets the Capacity of the <see cref=\"ArrayBasedStack{T}\" />.\n    /// </summary>\n    public int Capacity\n    {\n        get => stack.Length;\n        set => Array.Resize(ref stack, value);\n    }\n\n    /// <summary>\n    ///     Removes all items from the <see cref=\"ArrayBasedStack{T}\" />.\n    /// </summary>\n    public void Clear()\n    {\n        top = -1;\n        Capacity = DefaultCapacity;\n    }\n\n    /// <summary>\n    ///     Determines whether an element is in the <see cref=\"ArrayBasedStack{T}\" />.\n    /// </summary>\n    /// <param name=\"item\">The item to locate in the <see cref=\"ArrayBasedStack{T}\" />.</param>\n    /// <returns>True, if the item is in the stack.</returns>\n    public bool Contains(T item) => Array.IndexOf(stack, item, 0, top + 1) > -1;\n\n    /// <summary>\n    ///     Returns the item at the top of the <see cref=\"ArrayBasedStack{T}\" /> without removing it.\n    /// </summary>\n    /// <returns>The item at the top of the <see cref=\"ArrayBasedStack{T}\" />.</returns>\n    public T Peek()\n    {\n        if (top == -1)\n        {\n            throw new InvalidOperationException(StackEmptyErrorMessage);\n        }\n\n        return stack[top];\n    }\n\n    /// <summary>\n    ///     Removes and returns the item at the top of the <see cref=\"ArrayBasedStack{T}\" />.\n    /// </summary>\n    /// <returns>The item removed from the top of the <see cref=\"ArrayBasedStack{T}\" />.</returns>\n    public T Pop()\n    {\n        if (top == -1)\n        {\n            throw new InvalidOperationException(StackEmptyErrorMessage);\n        }\n\n        return stack[top--];\n    }\n\n    /// <summary>\n    ///     Inserts an item at the top of the <see cref=\"ArrayBasedStack{T}\" />.\n    /// </summary>\n    /// <param name=\"item\">The item to push onto the <see cref=\"ArrayBasedStack{T}\" />.</param>\n    public void Push(T item)\n    {\n        if (top == Capacity - 1)\n        {\n            Capacity *= 2;\n        }\n\n        stack[++top] = item;\n    }\n}\n"
  },
  {
    "path": "DataStructures/Stack/ListBasedStack.cs",
    "content": "namespace DataStructures.Stack;\n\n/// <summary>\n///     Implementation of a list based stack. FILO style.\n/// </summary>\n/// <typeparam name=\"T\">Generic Type.</typeparam>\npublic class ListBasedStack<T>\n{\n    /// <summary>\n    ///     <see cref=\"List{T}\" /> based stack.\n    /// </summary>\n    private readonly LinkedList<T> stack;\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"ListBasedStack{T}\" /> class.\n    /// </summary>\n    public ListBasedStack() => stack = new LinkedList<T>();\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"ListBasedStack{T}\" /> class.\n    /// </summary>\n    /// <param name=\"item\">Item to push onto the <see cref=\"ListBasedStack{T}\" />.</param>\n    public ListBasedStack(T item)\n        : this() => Push(item);\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"ListBasedStack{T}\" /> class.\n    /// </summary>\n    /// <param name=\"items\">Items to push onto the <see cref=\"ListBasedStack{T}\" />.</param>\n    public ListBasedStack(IEnumerable<T> items)\n        : this()\n    {\n        foreach (var item in items)\n        {\n            Push(item);\n        }\n    }\n\n    /// <summary>\n    ///     Gets the number of elements on the <see cref=\"ListBasedStack{T}\" />.\n    /// </summary>\n    public int Count => stack.Count;\n\n    /// <summary>\n    ///     Removes all items from the <see cref=\"ListBasedStack{T}\" />.\n    /// </summary>\n    public void Clear() => stack.Clear();\n\n    /// <summary>\n    ///     Determines whether an element is in the <see cref=\"ListBasedStack{T}\" />.\n    /// </summary>\n    /// <param name=\"item\">The item to locate in the <see cref=\"ListBasedStack{T}\" />.</param>\n    /// <returns>True, if the item is in the stack.</returns>\n    public bool Contains(T item) => stack.Contains(item);\n\n    /// <summary>\n    ///     Returns the item at the top of the <see cref=\"ListBasedStack{T}\" /> without removing it.\n    /// </summary>\n    /// <returns>The item at the top of the <see cref=\"ListBasedStack{T}\" />.</returns>\n    public T Peek()\n    {\n        if (stack.First is null)\n        {\n            throw new InvalidOperationException(\"Stack is empty\");\n        }\n\n        return stack.First.Value;\n    }\n\n    /// <summary>\n    ///     Removes and returns the item at the top of the <see cref=\"ListBasedStack{T}\" />.\n    /// </summary>\n    /// <returns>The item removed from the top of the <see cref=\"ListBasedStack{T}\" />.</returns>\n    public T Pop()\n    {\n        if (stack.First is null)\n        {\n            throw new InvalidOperationException(\"Stack is empty\");\n        }\n\n        var item = stack.First.Value;\n        stack.RemoveFirst();\n        return item;\n    }\n\n    /// <summary>\n    ///     Inserts an item at the top of the <see cref=\"ListBasedStack{T}\" />.\n    /// </summary>\n    /// <param name=\"item\">The item to push onto the <see cref=\"ListBasedStack{T}\" />.</param>\n    public void Push(T item) => stack.AddFirst(item);\n}\n"
  },
  {
    "path": "DataStructures/Stack/QueueBasedStack.cs",
    "content": "namespace DataStructures.Stack;\n\npublic class QueueBasedStack<T>\n{\n    private readonly Queue<T> queue;\n\n    public QueueBasedStack() => queue = new Queue<T>();\n\n    /// <summary>\n    ///     Clears the stack.\n    /// </summary>\n    public void Clear() => queue.Clear();\n\n    public bool IsEmpty() => queue.Count == 0;\n\n    /// <summary>\n    ///     Adds an item on top of the stack.\n    /// </summary>\n    /// <param name=\"item\">Item to be added on top of stack.</param>\n    public void Push(T item) => queue.Enqueue(item);\n\n    /// <summary>\n    ///     Removes an item from  top of the stack and returns it.\n    ///  </summary>\n    /// <returns>item on top of stack.</returns>\n    /// <exception cref=\"InvalidOperationException\">Throw if stack is empty.</exception>\n    public T Pop()\n    {\n        if (IsEmpty())\n        {\n            throw new InvalidOperationException(\"The stack contains no items.\");\n        }\n\n        for (int i = 0; i < queue.Count - 1; i++)\n        {\n            queue.Enqueue(queue.Dequeue());\n        }\n\n        return queue.Dequeue();\n    }\n\n    /// <summary>\n    ///     return an item from the top of the stack without removing it.\n    /// </summary>\n    /// <returns>item on top of the stack.</returns>\n    /// <exception cref=\"InvalidOperationException\">Throw if stack is empty.</exception>\n    public T Peek()\n    {\n        if (IsEmpty())\n        {\n            throw new InvalidOperationException(\"The stack contains no items.\");\n        }\n\n        for (int i = 0; i < queue.Count - 1; i++)\n        {\n            queue.Enqueue(queue.Dequeue());\n        }\n\n        var item = queue.Peek();\n        queue.Enqueue(queue.Dequeue());\n        return item;\n    }\n\n    /// <summary>\n    ///     returns the count of items on the stack.\n    /// </summary>\n    /// <returns>number of items on the stack.</returns>\n    public int Length() => queue.Count;\n}\n"
  },
  {
    "path": "DataStructures/Timeline.cs",
    "content": "/*\n    Author: Lorenzo Lotti\n    Name: Timeline (DataStructures.Timeline<TValue>)\n    Type: Data structure (class)\n    Description: A collection of dates/times and values sorted by dates/times easy to query.\n    Usage:\n        this data structure can be used to represent an ordered series of dates or times with which to associate values.\n        An example is a chronology of events:\n            306: Constantine is the new emperor,\n            312: Battle of the Milvian Bridge,\n            313: Edict of Milan,\n            330: Constantine move the capital to Constantinople.\n*/\n\nusing System.Collections;\n\nnamespace DataStructures;\n\n/// <summary>\n///     A collection of <see cref=\"DateTime\" /> and <see cref=\"TValue\" />\n///     sorted by <see cref=\"DateTime\" /> field.\n/// </summary>\n/// <typeparam name=\"TValue\">Value associated with a <see cref=\"DateTime\" />.</typeparam>\npublic class Timeline<TValue> : ICollection<(DateTime Time, TValue Value)>, IEquatable<Timeline<TValue>>\n{\n    /// <summary>\n    ///     Inner collection storing the timeline events as key-tuples.\n    /// </summary>\n    private readonly List<(DateTime Time, TValue Value)> timeline = [];\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"Timeline{TValue}\"/> class.\n    /// </summary>\n    public Timeline()\n    {\n    }\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"Timeline{TValue}\"/> class populated with an initial event.\n    /// </summary>\n    /// <param name=\"time\">The time at which the given event occurred.</param>\n    /// <param name=\"value\">The event's content.</param>\n    public Timeline(DateTime time, TValue value)\n        => timeline =\n        [\n            (time, value),\n        ];\n\n    /// <summary>\n    ///     Initializes a new instance of the <see cref=\"Timeline{TValue}\"/> class containing the provided events\n    ///     ordered chronologically.\n    /// </summary>\n    /// <param name=\"timeline\">The timeline to represent.</param>\n    public Timeline(params (DateTime, TValue)[] timeline)\n        => this.timeline = timeline\n            .OrderBy(pair => pair.Item1)\n            .ToList();\n\n    /// <summary>\n    /// Gets he number of unique times within this timeline.\n    /// </summary>\n    public int TimesCount\n        => GetAllTimes().Length;\n\n    /// <summary>\n    ///     Gets all events that has occurred in this timeline.\n    /// </summary>\n    public int ValuesCount\n        => GetAllValues().Length;\n\n    /// <summary>\n    ///     Get all values associated with <paramref name=\"time\" />.\n    /// </summary>\n    /// <param name=\"time\">Time to get values for.</param>\n    /// <returns>Values associated with <paramref name=\"time\" />.</returns>\n    public TValue[] this[DateTime time]\n    {\n        get => GetValuesByTime(time);\n        set\n        {\n            timeline.RemoveAll(@event => @event.Time == time);\n            foreach (var v in value)\n            {\n                Add(time, v);\n            }\n        }\n    }\n\n    /// <inheritdoc />\n    bool ICollection<(DateTime Time, TValue Value)>.IsReadOnly\n        => false;\n\n    /// <summary>\n    ///     Gets the count of pairs.\n    /// </summary>\n    public int Count\n        => timeline.Count;\n\n    /// <summary>\n    ///     Clear the timeline, removing all events.\n    /// </summary>\n    public void Clear()\n        => timeline.Clear();\n\n    /// <summary>\n    ///     Copy a value to an array.\n    /// </summary>\n    /// <param name=\"array\">Destination array.</param>\n    /// <param name=\"arrayIndex\">The start index.</param>\n    public void CopyTo((DateTime, TValue)[] array, int arrayIndex)\n        => timeline.CopyTo(array, arrayIndex);\n\n    /// <summary>\n    ///     Add an event at a given time.\n    /// </summary>\n    /// <param name=\"item\">The tuple containing the event date and value.</param>\n    void ICollection<(DateTime Time, TValue Value)>.Add((DateTime Time, TValue Value) item)\n        => Add(item.Time, item.Value);\n\n    /// <summary>\n    ///     Check whether or not a event exists at a specific date in the timeline.\n    /// </summary>\n    /// <param name=\"item\">The tuple containing the event date and value.</param>\n    /// <returns>True if this event exists at the given date, false otherwise.</returns>\n    bool ICollection<(DateTime Time, TValue Value)>.Contains((DateTime Time, TValue Value) item)\n        => Contains(item.Time, item.Value);\n\n    /// <summary>\n    ///     Remove an event at a specific date.\n    /// </summary>\n    /// <param name=\"item\">The tuple containing the event date and value.</param>\n    /// <returns>True if the event was removed, false otherwise.</returns>\n    bool ICollection<(DateTime Time, TValue Value)>.Remove((DateTime Time, TValue Value) item)\n        => Remove(item.Time, item.Value);\n\n    /// <inheritdoc />\n    IEnumerator IEnumerable.GetEnumerator()\n        => timeline.GetEnumerator();\n\n    /// <inheritdoc />\n    IEnumerator<(DateTime Time, TValue Value)> IEnumerable<(DateTime Time, TValue Value)>.GetEnumerator()\n        => timeline.GetEnumerator();\n\n    /// <inheritdoc />\n    public bool Equals(Timeline<TValue>? other)\n        => other is not null && this == other;\n\n    /// <summary>\n    ///     Checks whether or not two <see cref=\"Timeline{TValue}\"/> are equals.\n    /// </summary>\n    /// <param name=\"left\">The first timeline.</param>\n    /// <param name=\"right\">The other timeline to be checked against the <paramref name=\"left\"/> one.</param>\n    /// <returns>True if both timelines are similar, false otherwise.</returns>\n    public static bool operator ==(Timeline<TValue> left, Timeline<TValue> right)\n    {\n        var leftArray = left.ToArray();\n        var rightArray = right.ToArray();\n\n        if (left.Count != rightArray.Length)\n        {\n            return false;\n        }\n\n        for (var i = 0; i < leftArray.Length; i++)\n        {\n            if (leftArray[i].Time != rightArray[i].Time\n                && !leftArray[i].Value!.Equals(rightArray[i].Value))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    ///     Checks whether or not two <see cref=\"Timeline{TValue}\"/> are not equals.\n    /// </summary>\n    /// <param name=\"left\">The first timeline.</param>\n    /// <param name=\"right\">The other timeline to be checked against the <paramref name=\"left\"/> one.</param>\n    /// <returns>False if both timelines are similar, true otherwise.</returns>\n    public static bool operator !=(Timeline<TValue> left, Timeline<TValue> right)\n        => !(left == right);\n\n    /// <summary>\n    ///     Get all <see cref=\"DateTime\" /> of the timeline.\n    /// </summary>\n    public DateTime[] GetAllTimes()\n        => timeline.Select(t => t.Time)\n            .Distinct()\n            .ToArray();\n\n    /// <summary>\n    ///     Get <see cref=\"DateTime\" /> values of the timeline that have this <paramref name=\"value\" />.\n    /// </summary>\n    public DateTime[] GetTimesByValue(TValue value)\n        => timeline.Where(pair => pair.Value!.Equals(value))\n            .Select(pair => pair.Time)\n            .ToArray();\n\n    /// <summary>\n    ///     Get all <see cref=\"DateTime\" /> before <paramref name=\"time\" />.\n    /// </summary>\n    public DateTime[] GetTimesBefore(DateTime time)\n        => GetAllTimes()\n            .Where(t => t < time)\n            .OrderBy(t => t)\n            .ToArray();\n\n    /// <summary>\n    ///     Get all <see cref=\"DateTime\" /> after <paramref name=\"time\" />.\n    /// </summary>\n    public DateTime[] GetTimesAfter(DateTime time)\n        => GetAllTimes()\n            .Where(t => t > time)\n            .OrderBy(t => t)\n            .ToArray();\n\n    /// <summary>\n    ///     Get all <see cref=\"TValue\" /> of the timeline.\n    /// </summary>\n    public TValue[] GetAllValues()\n        => timeline.Select(pair => pair.Value)\n            .ToArray();\n\n    /// <summary>\n    ///     Get all <see cref=\"TValue\" /> associated with <paramref name=\"time\" />.\n    /// </summary>\n    public TValue[] GetValuesByTime(DateTime time)\n        => timeline.Where(pair => pair.Time == time)\n            .Select(pair => pair.Value)\n            .ToArray();\n\n    /// <summary>\n    ///     Get all <see cref=\"TValue\" /> before <paramref name=\"time\" />.\n    /// </summary>\n    public Timeline<TValue> GetValuesBefore(DateTime time)\n        => new(this.Where(pair => pair.Time < time).ToArray());\n\n    /// <summary>\n    ///     Get all <see cref=\"TValue\" /> before <paramref name=\"time\" />.\n    /// </summary>\n    public Timeline<TValue> GetValuesAfter(DateTime time)\n        => new(this.Where(pair => pair.Time > time).ToArray());\n\n    /// <summary>\n    ///     Gets all values that happened at specified millisecond.\n    /// </summary>\n    /// <param name=\"millisecond\">Value to look for.</param>\n    /// <returns>Array of values.</returns>\n    public Timeline<TValue> GetValuesByMillisecond(int millisecond)\n        => new(timeline.Where(pair => pair.Time.Millisecond == millisecond).ToArray());\n\n    /// <summary>\n    ///     Gets all values that happened at specified second.\n    /// </summary>\n    /// <param name=\"second\">Value to look for.</param>\n    /// <returns>Array of values.</returns>\n    public Timeline<TValue> GetValuesBySecond(int second)\n        => new(timeline.Where(pair => pair.Time.Second == second).ToArray());\n\n    /// <summary>\n    ///     Gets all values that happened at specified minute.\n    /// </summary>\n    /// <param name=\"minute\">Value to look for.</param>\n    /// <returns>Array of values.</returns>\n    public Timeline<TValue> GetValuesByMinute(int minute)\n        => new(timeline.Where(pair => pair.Time.Minute == minute).ToArray());\n\n    /// <summary>\n    ///     Gets all values that happened at specified hour.\n    /// </summary>\n    /// <param name=\"hour\">Value to look for.</param>\n    /// <returns>Array of values.</returns>\n    public Timeline<TValue> GetValuesByHour(int hour)\n        => new(timeline.Where(pair => pair.Time.Hour == hour).ToArray());\n\n    /// <summary>\n    ///     Gets all values that happened at specified day.\n    /// </summary>\n    /// <param name=\"day\">Value to look for.</param>\n    /// <returns>Array of values.</returns>\n    public Timeline<TValue> GetValuesByDay(int day)\n        => new(timeline.Where(pair => pair.Time.Day == day).ToArray());\n\n    /// <summary>\n    ///     Gets all values that happened at specified time of the day.\n    /// </summary>\n    /// <param name=\"timeOfDay\">Value to look for.</param>\n    /// <returns>Array of values.</returns>\n    public Timeline<TValue> GetValuesByTimeOfDay(TimeSpan timeOfDay)\n        => new(timeline.Where(pair => pair.Time.TimeOfDay == timeOfDay).ToArray());\n\n    /// <summary>\n    ///     Gets all values that happened at specified day of the week.\n    /// </summary>\n    /// <param name=\"dayOfWeek\">Value to look for.</param>\n    /// <returns>Array of values.</returns>\n    public Timeline<TValue> GetValuesByDayOfWeek(DayOfWeek dayOfWeek)\n        => new(timeline.Where(pair => pair.Time.DayOfWeek == dayOfWeek).ToArray());\n\n    /// <summary>\n    ///     Gets all values that happened at specified day of the year.\n    /// </summary>\n    /// <param name=\"dayOfYear\">Value to look for.</param>\n    /// <returns>Array of values.</returns>\n    public Timeline<TValue> GetValuesByDayOfYear(int dayOfYear)\n        => new(timeline.Where(pair => pair.Time.DayOfYear == dayOfYear).ToArray());\n\n    /// <summary>\n    ///     Gets all values that happened at specified month.\n    /// </summary>\n    /// <param name=\"month\">Value to look for.</param>\n    /// <returns>Array of values.</returns>\n    public Timeline<TValue> GetValuesByMonth(int month)\n        => new(timeline.Where(pair => pair.Time.Month == month).ToArray());\n\n    /// <summary>\n    ///     Gets all values that happened at specified year.\n    /// </summary>\n    /// <param name=\"year\">Value to look for.</param>\n    /// <returns>Array of values.</returns>\n    public Timeline<TValue> GetValuesByYear(int year)\n        => new(timeline.Where(pair => pair.Time.Year == year).ToArray());\n\n    /// <summary>\n    ///     Add an event at a given <paramref name=\"time\"/>.\n    /// </summary>\n    /// <param name=\"time\">The date at which the event occurred.</param>\n    /// <param name=\"value\">The event value.</param>\n    public void Add(DateTime time, TValue value)\n    {\n        timeline.Add((time, value));\n    }\n\n    /// <summary>\n    ///     Add a set of <see cref=\"DateTime\" /> and <see cref=\"TValue\" /> to the timeline.\n    /// </summary>\n    public void Add(params (DateTime, TValue)[] timeline)\n    {\n        this.timeline.AddRange(timeline);\n    }\n\n    /// <summary>\n    ///     Append an existing timeline to this one.\n    /// </summary>\n    public void Add(Timeline<TValue> timeline)\n        => Add(timeline.ToArray());\n\n    /// <summary>\n    ///     Add a <paramref name=\"value\" /> associated with <see cref=\"DateTime.Now\" /> to the timeline.\n    /// </summary>\n    public void AddNow(params TValue[] value)\n    {\n        var now = DateTime.Now;\n        foreach (var v in value)\n        {\n            Add(now, v);\n        }\n    }\n\n    /// <summary>\n    ///     Check whether or not a event exists at a specific date in the timeline.\n    /// </summary>\n    /// <param name=\"time\">The date at which the event occurred.</param>\n    /// <param name=\"value\">The event value.</param>\n    /// <returns>True if this event exists at the given date, false otherwise.</returns>\n    public bool Contains(DateTime time, TValue value)\n        => timeline.Contains((time, value));\n\n    /// <summary>\n    ///     Check if timeline contains this set of value pairs.\n    /// </summary>\n    /// <param name=\"timeline\">The events to checks.</param>\n    /// <returns>True if any of the events has occurred in the timeline.</returns>\n    public bool Contains(params (DateTime, TValue)[] timeline)\n        => timeline.Any(@event => Contains(@event.Item1, @event.Item2));\n\n    /// <summary>\n    ///     Check if timeline contains any of the event of the provided <paramref name=\"timeline\"/>.\n    /// </summary>\n    /// <param name=\"timeline\">The events to checks.</param>\n    /// <returns>True if any of the events has occurred in the timeline.</returns>\n    public bool Contains(Timeline<TValue> timeline)\n        => Contains(timeline.ToArray());\n\n    /// <summary>\n    ///     Check if timeline contains any of the time of the provided <paramref name=\"times\"/>.\n    /// </summary>\n    /// <param name=\"times\">The times to checks.</param>\n    /// <returns>True if any of the times is stored in the timeline.</returns>\n    public bool ContainsTime(params DateTime[] times)\n    {\n        var storedTimes = GetAllTimes();\n        return times.Any(value => storedTimes.Contains(value));\n    }\n\n    /// <summary>\n    ///     Check if timeline contains any of the event of the provided <paramref name=\"values\"/>.\n    /// </summary>\n    /// <param name=\"values\">The events to checks.</param>\n    /// <returns>True if any of the events has occurred in the timeline.</returns>\n    public bool ContainsValue(params TValue[] values)\n    {\n        var storedValues = GetAllValues();\n        return values.Any(value => storedValues.Contains(value));\n    }\n\n    /// <summary>\n    ///     Remove an event at a specific date.\n    /// </summary>\n    /// <param name=\"time\">The date at which the event occurred.</param>\n    /// <param name=\"value\">The event value.</param>\n    /// <returns>True if the event was removed, false otherwise.</returns>\n    public bool Remove(DateTime time, TValue value)\n        => timeline.Remove((time, value));\n\n    /// <summary>\n    ///     Remove a set of value pairs from the timeline.\n    /// </summary>\n    /// <param name=\"timeline\">An collection of all events to remove.</param>\n    /// <returns>Returns true if the operation completed successfully.</returns>\n    public bool Remove(params (DateTime, TValue)[] timeline)\n    {\n        var result = false;\n        foreach (var (time, value) in timeline)\n        {\n            result |= this.timeline.Remove((time, value));\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Remove an existing timeline from this timeline.\n    /// </summary>\n    /// <param name=\"timeline\">An collection of all events to remove.</param>\n    /// <returns>Returns true if the operation completed successfully.</returns>\n    public bool Remove(Timeline<TValue> timeline)\n        => Remove(timeline.ToArray());\n\n    /// <summary>\n    ///     Remove a value pair from the timeline if the time is equal to <paramref name=\"times\" />.\n    /// </summary>\n    /// <returns>Returns true if the operation completed successfully.</returns>\n    public bool RemoveTimes(params DateTime[] times)\n    {\n        var isTimeContainedInTheTimeline = times.Any(time => GetAllTimes().Contains(time));\n\n        if (!isTimeContainedInTheTimeline)\n        {\n            return false;\n        }\n\n        var eventsToRemove = times.SelectMany(time =>\n            timeline.Where(@event => @event.Time == time))\n            .ToList();\n\n        foreach (var @event in eventsToRemove)\n        {\n            timeline.Remove(@event);\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    ///     Remove a value pair from the timeline if the value is equal to <paramref name=\"values\" />.\n    /// </summary>\n    /// <returns>Returns true if the operation completed successfully.</returns>\n    public bool RemoveValues(params TValue[] values)\n    {\n        var isValueContainedInTheTimeline = values.Any(v => GetAllValues().Contains(v));\n\n        if (!isValueContainedInTheTimeline)\n        {\n            return false;\n        }\n\n        var eventsToRemove = values.SelectMany(value =>\n            timeline.Where(@event => EqualityComparer<TValue>.Default.Equals(@event.Value, value)))\n            .ToList();\n\n        foreach (var @event in eventsToRemove)\n        {\n            timeline.Remove(@event);\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    ///     Convert the timeline to an array.\n    /// </summary>\n    /// <returns>\n    /// The timeline as an array of tuples of (<see cref=\"DateTime\"/>, <typeparamref name=\"TValue\"/>).\n    /// </returns>\n    public (DateTime Time, TValue Value)[] ToArray()\n        => timeline.ToArray();\n\n    /// <summary>\n    ///     Convert the timeline to a list.\n    /// </summary>\n    /// <returns>\n    /// The timeline as a list of tuples of (<see cref=\"DateTime\"/>, <typeparamref name=\"TValue\"/>).\n    /// </returns>\n    public IList<(DateTime Time, TValue Value)> ToList()\n        => timeline;\n\n    /// <summary>\n    ///     Convert the timeline to a dictionary.\n    /// </summary>\n    /// <returns>\n    /// The timeline as an dictionary of <typeparamref name=\"TValue\"/> by <see cref=\"DateTime\"/>.\n    /// </returns>\n    public IDictionary<DateTime, TValue> ToDictionary()\n        => timeline.ToDictionary(@event => @event.Time, @event => @event.Value);\n\n    /// <inheritdoc />\n    public override bool Equals(object? obj)\n        => obj is Timeline<TValue> otherTimeline\n           && this == otherTimeline;\n\n    /// <inheritdoc />\n    public override int GetHashCode()\n        => timeline.GetHashCode();\n}\n"
  },
  {
    "path": "DataStructures/Tries/Trie.cs",
    "content": "namespace DataStructures.Tries;\n\n/// <summary>\n/// A Trie is a data structure (particular case of m-ary tree) used to efficiently represent strings with common prefixes.\n/// Originally posed by E. Fredkin in 1960.\n///     Fredkin, Edward (Sept. 1960), \"Trie Memory\", Communications of the ACM 3 (9): 490-499.\n/// Its name is due to retrieval because its main application is in the field of \"Information Retrieval\" (information retrieval).\n/// </summary>\npublic class Trie\n{\n    /// <summary>\n    /// This character marks the end of a string.\n    /// </summary>\n    private const char Mark = '$';\n\n    /// <summary>\n    /// This property represents the root node of the trie.\n    /// </summary>\n    private readonly TrieNode root;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"Trie\"/> class. This instances was created without text strings, generating the root node of the trie, without children.\n    /// </summary>\n    public Trie()\n    {\n        root = new TrieNode(Mark);\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"Trie\"/> class. Given a set of text strings, each of those strings inserts them into the trie using the Insert (string) method.\n    /// </summary>\n    /// <param name=\"words\">The array with text strings to insert in the trie.</param>\n    public Trie(IEnumerable<string> words)\n        : this()\n    {\n        foreach (string s in words)\n        {\n            Insert(s);\n        }\n    }\n\n    /// <summary>\n    /// Insert a string s to the trie. The $ mark is added to the end of the chain and then it is added, this in order to indicate the end of the chain in the trie.\n    /// </summary>\n    /// <param name=\"s\">The string to insert into the trie.</param>\n    public void Insert(string s)\n    {\n        s += Mark;\n\n        int index = 0;\n        TrieNode match = PrefixQuery(s, ref index);\n\n        for (int i = index; i < s.Length; i++)\n        {\n            TrieNode t = new(s[i], match);\n            match[s[i]] = t;\n            match = t;\n        }\n    }\n\n    /// <summary>\n    /// Remove a text string from the trie.\n    /// </summary>\n    /// <param name=\"s\">The text string to be removed from the trie.</param>\n    public void Remove(string s)\n    {\n        s += Mark;\n        int index = 0;\n        TrieNode match = PrefixQuery(s, ref index);\n        while (match.IsLeaf())\n        {\n            char c = match.Value;\n            if (match.Parent == null)\n            {\n                break;\n            }\n\n            match = match.Parent;\n            match.Children.Remove(c);\n        }\n    }\n\n    /// <summary>\n    /// Know if a text string is in the trie.\n    /// </summary>\n    /// <param name=\"s\">The string s that you want to know if it is in the trie.</param>\n    /// <returns>If the string is found, it returns true, otherwise false.</returns>\n    public bool Find(string s)\n    {\n        int index = 0;\n        return PrefixQuery(s + Mark, ref index).IsLeaf();\n    }\n\n    /// <summary>\n    /// This method analyzes which is the longest common prefix of a string s in the trie. If the string is in the trie then it is equivalent to doing Find (s).\n    /// </summary>\n    /// <param name=\"s\">The string for which you want to know the longest common prefix.</param>\n    /// <param name=\"index\">The index to which the longest common prefix goes.</param>\n    /// <returns>\n    /// Returns the longest common prefix node found in the trie with the string s.\n    /// </returns>\n    private TrieNode PrefixQuery(string s, ref int index)\n    {\n        TrieNode current = root;\n        for (int i = 0; i < s.Length && current != null; i++)\n        {\n            if (current[s[i]] != null)\n            {\n                current = current[s[i]] ?? throw new NullReferenceException();\n                index = i + 1;\n            }\n            else\n            {\n                break;\n            }\n        }\n\n        return current ?? throw new NullReferenceException();\n    }\n}\n"
  },
  {
    "path": "DataStructures/Tries/TrieNode.cs",
    "content": "namespace DataStructures.Tries;\n\n/// <summary>\n/// This class represents the nodes of a trie.\n/// </summary>\ninternal class TrieNode\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"TrieNode\"/> class. This instance was created with a character from the alphabet, and its parent will be null.\n    /// </summary>\n    /// <param name=\"value\">Character of the alphabet that represents the node.</param>\n    internal TrieNode(char value)\n        : this(value, null)\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"TrieNode\"/> class. This instance was created with a character from the alphabet, and its parent.\n    /// </summary>\n    /// <param name=\"value\">Character of the alphabet that represents the node.</param>\n    /// <param name=\"parent\">The parent or ancestor of the node in the trie structure.</param>\n    internal TrieNode(char value, TrieNode? parent)\n    {\n        Children = [];\n        Parent = parent;\n        Value = value;\n    }\n\n    /// <summary>\n    /// Gets all the descendants of the current node.\n    /// </summary>\n    /// <value>A sorted set with all the descendants.</value>\n    internal SortedList<char, TrieNode> Children { get; private set; }\n\n    /// <summary>\n    /// Gets the parent or ancestor of the node in the trie structure.\n    /// </summary>\n    /// <value>A TrieNode that represent a parent.</value>\n    internal TrieNode? Parent { get; private set; }\n\n    /// <summary>\n    /// Gets the character of the alphabet that represents the node.\n    /// </summary>\n    /// <value>A character of the alphabet.</value>\n    internal char Value { get; private set; }\n\n    /// <summary>\n    /// Index the descendants of the current node given an alphabet character.\n    /// </summary>\n    /// <value>A TrieNode with the character c in Children.</value>\n    public TrieNode? this[char c]\n    {\n        get => Children.ContainsKey(c) ? Children[c] : null;\n        set => Children[c] = value ?? throw new NullReferenceException();\n    }\n\n    /// <summary>\n    /// Method that checks if the current node is a trie leaf.\n    /// </summary>\n    /// <returns>Returns true if the current node has no children, false otherwise.</returns>\n    public bool IsLeaf()\n    {\n        return Children.Count == 0;\n    }\n}\n"
  },
  {
    "path": "DataStructures/UnrolledList/UnrolledLinkedList.cs",
    "content": "namespace DataStructures.UnrolledList;\n\n/// <summary>\n/// Unrolled linked list is a linked list of small arrays,\n/// all of the same size where each is so small that the insertion\n/// or deletion is fast and quick, but large enough to fill the cache line.\n/// </summary>\n/// <remarks>\n/// Initializes a new instance of the <see cref=\"UnrolledLinkedList\"/> class.\n/// Create a unrolled list with start chunk size.\n/// </remarks>\n/// <param name=\"chunkSize\">The size of signe chunk.</param>\npublic class UnrolledLinkedList(int chunkSize)\n{\n    private readonly int sizeNode = chunkSize + 1;\n\n    private UnrolledLinkedListNode start = null!;\n    private UnrolledLinkedListNode end = null!;\n\n    /// <summary>\n    /// Add value to list [O(n)].\n    /// </summary>\n    /// <param name=\"value\">The entered value.</param>\n    public void Insert(int value)\n    {\n        if (start == null)\n        {\n            start = new UnrolledLinkedListNode(sizeNode);\n            start.Set(0, value);\n\n            end = start;\n            return;\n        }\n\n        if (end.Count + 1 < sizeNode)\n        {\n            end.Set(end.Count, value);\n        }\n        else\n        {\n            var pointer = new UnrolledLinkedListNode(sizeNode);\n            var j = 0;\n            for (var pos = end.Count / 2 + 1; pos < end.Count; pos++)\n            {\n                pointer.Set(j++, end.Get(pos));\n            }\n\n            pointer.Set(j++, value);\n            pointer.Count = j;\n\n            end.Count = end.Count / 2 + 1;\n            end.Next = pointer;\n            end = pointer;\n        }\n    }\n\n    /// <summary>\n    /// Help method. Get all list inside to check the state.\n    /// </summary>\n    /// <returns>Items from all nodes.</returns>\n    public IEnumerable<int> GetRolledItems()\n    {\n        UnrolledLinkedListNode pointer = start;\n        List<int> result = [];\n\n        while (pointer != null)\n        {\n            for (var i = 0; i < pointer.Count; i++)\n            {\n                result.Add(pointer.Get(i));\n            }\n\n            pointer = pointer.Next;\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "DataStructures/UnrolledList/UnrolledLinkedListNode.cs",
    "content": "namespace DataStructures.UnrolledList;\n\n/// <summary>\n/// Single node with array buffer for unrolled list.\n/// </summary>\npublic class UnrolledLinkedListNode(int nodeSize)\n{\n    private readonly int[] array = new int[nodeSize];\n\n    public UnrolledLinkedListNode Next { get; set; } = null!;\n\n    public int Count { get; set; }\n\n    /// <summary>\n    /// Set new item in array buffer.\n    /// </summary>\n    /// <param name=\"pos\">Index in array.</param>\n    /// <param name=\"val\">The entered value.</param>\n    /// <exception cref=\"ArgumentException\">Index is out of scope.</exception>\n    public void Set(int pos, int val)\n    {\n        if (pos < 0 || pos > array.Length - 1)\n        {\n            throw new ArgumentException(\"Position is out of size\", nameof(pos));\n        }\n\n        array[pos] = val;\n        Count++;\n    }\n\n    /// <summary>\n    /// Get item from array buffer.\n    /// </summary>\n    /// <param name=\"pos\">Index in array.</param>\n    /// <exception cref=\"ArgumentException\">Index is out of scope.</exception>\n    public int Get(int pos)\n    {\n        if (pos < 0 || pos > array.Length - 1)\n        {\n            throw new ArgumentException(\"Position is out of size\", nameof(pos));\n        }\n\n        return array[pos];\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/AATreeTests.cs",
    "content": "using DataStructures.AATree;\n\nnamespace DataStructures.Tests;\n\ninternal class AaTreeTests\n{\n    [Test]\n    public void Constructor_UseCustomComparer_FormsCorrectTree()\n    {\n        var tree = new AaTree<int>(Comparer<int>.Create((x, y) => y.CompareTo(x)));\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.GetMax().Should().Be(1);\n        tree.GetMin().Should().Be(10);\n        tree.GetKeysInOrder().SequenceEqual(new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }).Should().BeTrue();\n        Validate(tree.Root);\n    }\n\n    [Test]\n    public void Add_MultipleKeys_FormsCorrectTree()\n    {\n        var tree = new AaTree<int>();\n\n        foreach (var elem in new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 })\n        {\n            tree.Add(elem);\n            tree.Count.Should().Be(elem);\n            tree.Contains(elem).Should().BeTrue();\n        }\n\n        tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue();\n        tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 10, 9, 8, 6, 4 }).Should().BeTrue();\n        Validate(tree.Root);\n    }\n\n    [Test]\n    public void Add_KeyAlreadyInTree_ThrowsException()\n    {\n        var tree = new AaTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        Assert.Throws<ArgumentException>(() => tree.Add(1));\n    }\n\n    [Test]\n    public void AddRange_MultipleKeys_FormsCorrectTree()\n    {\n        var tree = new AaTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.Count.Should().Be(10);\n        tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue();\n        tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 10, 9, 8, 6, 4 }).Should().BeTrue();\n        Validate(tree.Root);\n    }\n\n    [Test]\n    public void Remove_MultipleKeys_TreeStillValid()\n    {\n        var tree = new AaTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n\n        Remove(4).Should().NotThrow();\n        tree.Contains(4).Should().BeFalse();\n        tree.Count.Should().Be(9);\n\n        Remove(8).Should().NotThrow();\n        tree.Contains(8).Should().BeFalse();\n        tree.Count.Should().Be(8);\n\n        Remove(1).Should().NotThrow();\n        tree.Contains(1).Should().BeFalse();\n        tree.Count.Should().Be(7);\n\n        Validate(tree.Root);\n\n        Action Remove(int x) => () => tree.Remove(x);\n    }\n\n    [Test]\n    public void Remove_KeyNotInTree_Throws()\n    {\n        var tree = new AaTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n\n        Action act = () => tree.Remove(999);\n        act.Should().Throw<InvalidOperationException>();\n    }\n\n    [Test]\n    public void Remove_EmptyTree_Throws()\n    {\n        var tree = new AaTree<int>();\n\n        Action act = () => tree.Remove(999);\n        act.Should().Throw<InvalidOperationException>();\n    }\n\n    [Test]\n    public void Contains_NonEmptyTree_ReturnsCorrectAnswer()\n    {\n        var tree = new AaTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.Contains(6).Should().BeTrue();\n        tree.Contains(999).Should().BeFalse();\n    }\n\n    [Test]\n    public void Contains_EmptyTree_ReturnsFalse()\n    {\n        var tree = new AaTree<int>();\n        tree.Contains(999).Should().BeFalse();\n    }\n\n    [Test]\n    public void GetMax_NonEmptyTree_ReturnsCorrectAnswer()\n    {\n        var tree = new AaTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.GetMax().Should().Be(10);\n    }\n\n    [Test]\n    public void GetMax_EmptyTree_ThrowsCorrectException()\n    {\n        var tree = new AaTree<int>();\n        Assert.Throws<InvalidOperationException>(() => tree.GetMax());\n    }\n\n    [Test]\n    public void GetMin_NonEmptyTree_ReturnsCorrectAnswer()\n    {\n        var tree = new AaTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.GetMin().Should().Be(1);\n    }\n\n    [Test]\n    public void GetMin_EmptyTree_ThrowsCorrectException()\n    {\n        var tree = new AaTree<int>();\n        Assert.Throws<InvalidOperationException>(() => tree.GetMin());\n    }\n\n    [Test]\n    public void GetKeysInOrder_NonEmptyTree_ReturnsCorrectAnswer()\n    {\n        var tree = new AaTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void GetKeysInOrder_EmptyTree_ReturnsCorrectAnswer()\n    {\n        var tree = new AaTree<int>();\n        tree.GetKeysInOrder().ToList().Count.Should().Be(0);\n    }\n\n    [Test]\n    public void GetKeysPreOrder_NonEmptyTree_ReturnsCorrectAnswer()\n    {\n        var tree = new AaTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 4, 2, 1, 3, 6, 5, 8, 7, 9, 10 })\n            .Should().BeTrue();\n    }\n\n    [Test]\n    public void GetKeysPreOrder_EmptyTree_ReturnsCorrectAnswer()\n    {\n        var tree = new AaTree<int>();\n        tree.GetKeysPreOrder().ToList().Count.Should().Be(0);\n    }\n\n    [Test]\n    public void GetKeysPostOrder_NonEmptyTree_ReturnsCorrectAnswer()\n    {\n        var tree = new AaTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 10, 9, 8, 6, 4 })\n            .Should().BeTrue();\n    }\n\n    [Test]\n    public void GetKeysPostOrder_EmptyTree_ReturnsCorrectAnswer()\n    {\n        var tree = new AaTree<int>();\n        tree.GetKeysPostOrder().ToList().Count.Should().Be(0);\n    }\n\n    /// <summary>\n    ///     Checks various properties to determine if the tree is a valid AA Tree.\n    ///     Throws exceptions if properties are violated.\n    ///     Useful for debugging.\n    /// </summary>\n    /// <remarks>\n    ///     The properties that are checked are:\n    ///     <list type=\"number\">\n    ///         <item>The level of every leaf node is one.</item>\n    ///         <item>The level of every left child is exactly one less than that of its parent.</item>\n    ///         <item>The level of every right child is equal to or one less than that of its parent.</item>\n    ///         <item>The level of every right grandchild is strictly less than that of its grandparent.</item>\n    ///         <item>Every node of level greater than one has two children.</item>\n    ///     </list>\n    ///     More information: https://en.wikipedia.org/wiki/AA_tree .\n    /// </remarks>\n    /// <param name=\"node\">The node to check from.</param>\n    /// <returns>true if node passes all checks, false otherwise.</returns>\n    private static bool Validate<T>(AaTreeNode<T>? node)\n    {\n        if (node is null)\n        {\n            return true;\n        }\n\n        // Check level == 1 if node if a leaf node.\n        var leafNodeCheck = CheckLeafNode(node);\n\n        // Check level of left child is exactly one less than parent.\n        var leftCheck = CheckLeftSubtree(node);\n\n        // Check level of right child is equal or one less than parent.\n        var rightCheck = CheckRightSubtree(node);\n\n        // Check right grandchild level is less than node.\n        var grandchildCheck = CheckRightGrandChild(node);\n\n        // Check if node has two children if not leaf.\n        var nonLeafChildrenCheck = CheckNonLeafChildren(node);\n\n        var thisNodeResult = leafNodeCheck && leftCheck && rightCheck;\n        thisNodeResult = thisNodeResult && grandchildCheck && nonLeafChildrenCheck;\n\n        return thisNodeResult && Validate(node.Left) && Validate(node.Right);\n    }\n\n    /// <summary>\n    ///     Checks if node is a leaf, and if so if its level is 1.\n    /// </summary>\n    /// <param name=\"node\">The node to check.</param>\n    /// <returns>true if node passes check, false otherwise.</returns>\n    private static bool CheckLeafNode<T>(AaTreeNode<T> node)\n    {\n        var condition = node.Left is null && node.Right is null && node.Level != 1;\n        return !condition;\n    }\n\n    /// <summary>\n    ///     Checks if left node's level is exactly one less than node's level.\n    /// </summary>\n    /// <param name=\"node\">The node to check.</param>\n    /// <returns>true if node passes check, false otherwise.</returns>\n    private static bool CheckLeftSubtree<T>(AaTreeNode<T> node)\n    {\n        var condition = node.Left is not null && node.Level - node.Left.Level != 1;\n        return !condition;\n    }\n\n    /// <summary>\n    ///     Checks if right node's level is either equal to or one less than node's level.\n    /// </summary>\n    /// <param name=\"node\">The node to check.</param>\n    /// <returns>true if node passes check, false otherwise.</returns>\n    private static bool CheckRightSubtree<T>(AaTreeNode<T> node)\n    {\n        var condition = node.Right is not null &&\n                        node.Level - node.Right.Level != 1 &&\n                        node.Level != node.Right.Level;\n        return !condition;\n    }\n\n    /// <summary>\n    ///     Checks if right grandchild's (right node's right node) level is less than node.\n    /// </summary>\n    /// <param name=\"node\">The node to check.</param>\n    /// <returns>true if node passes check, false otherwise.</returns>\n    private static bool CheckRightGrandChild<T>(AaTreeNode<T> node)\n    {\n        var condition = node.Right?.Right is not null && node.Right.Level < node.Right.Right.Level;\n        return !condition;\n    }\n\n    /// <summary>\n    ///     Checks if node is not a leaf, and if so if it has two children.\n    /// </summary>\n    /// <param name=\"node\">The node to check.</param>\n    /// <returns>true if node passes check, false otherwise.</returns>\n    private static bool CheckNonLeafChildren<T>(AaTreeNode<T> node)\n    {\n        var condition = node.Level > 1 && (node.Left is null || node.Right is null);\n        return !condition;\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/AVLTreeTests.cs",
    "content": "using DataStructures.AVLTree;\nusing static FluentAssertions.FluentActions;\n\nnamespace DataStructures.Tests;\n\ninternal class AvlTreeTests\n{\n    private static readonly int[] Data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n    private static readonly int[] PreOrder = [4, 2, 1, 3, 8, 6, 5, 7, 9, 10];\n    private static readonly int[] PostOrder = [1, 3, 2, 5, 7, 6, 10, 9, 8, 4];\n\n    [Test]\n    public void Constructor_UseCustomComparer_FormsCorrectTree()\n    {\n        var tree = new AvlTree<int>(Comparer<int>.Create((x, y) => y.CompareTo(x)));\n\n        tree.AddRange(Data);\n\n        tree.GetMin().Should().Be(10);\n\n        tree.GetMax().Should().Be(1);\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                Data.Reverse(),\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Add_MultipleKeys_FormsCorrectTree()\n    {\n        var tree = new AvlTree<int>();\n\n        for (var i = 0; i < Data.Length; ++i)\n        {\n            tree.Add(Data[i]);\n            tree.Count.Should().Be(i + 1);\n        }\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                Data,\n                config => config.WithStrictOrdering());\n\n        tree.GetKeysPreOrder()\n            .Should()\n            .BeEquivalentTo(\n                PreOrder,\n                config => config.WithStrictOrdering());\n\n        tree.GetKeysPostOrder()\n            .Should()\n            .BeEquivalentTo(\n                PostOrder,\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Add_KeyAlreadyInTree_ThrowsException()\n    {\n        var tree = new AvlTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5 });\n\n        Invoking(() => tree.Add(1)).Should().ThrowExactly<ArgumentException>();\n    }\n\n    [Test]\n    public void AddRange_MultipleKeys_FormsCorrectTree()\n    {\n        var tree = new AvlTree<char>();\n        tree.AddRange(new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' });\n\n        tree.Count.Should().Be(7);\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' },\n                config => config.WithStrictOrdering());\n\n        tree.GetKeysPreOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 'd', 'b', 'a', 'c', 'f', 'e', 'g' },\n                config => config.WithStrictOrdering());\n\n        tree.GetKeysPostOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 'a', 'c', 'b', 'e', 'g', 'f', 'd' },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Remove_MultipleKeys_TreeStillValid()\n    {\n        var tree = new AvlTree<int>();\n        tree.AddRange(Data);\n\n        tree.Remove(7);\n\n        tree.Count.Should().Be(9);\n        tree.Contains(7).Should().BeFalse();\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 1, 2, 3, 4, 5, 6, 8, 9, 10 },\n                config => config.WithStrictOrdering());\n\n        tree.GetKeysPreOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 4, 2, 1, 3, 8, 6, 5, 9, 10 },\n                config => config.WithStrictOrdering());\n\n        tree.GetKeysPostOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 1, 3, 2, 5, 6, 10, 9, 8, 4 },\n                config => config.WithStrictOrdering());\n\n        tree.Remove(2);\n\n        tree.Count.Should().Be(8);\n        tree.Contains(2).Should().BeFalse();\n\n        tree.Remove(1);\n\n        tree.Count.Should().Be(7);\n        tree.Contains(1).Should().BeFalse();\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 3, 4, 5, 6, 8, 9, 10 },\n                config => config.WithStrictOrdering());\n\n        tree.GetKeysPreOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 8, 4, 3, 6, 5, 9, 10 },\n                config => config.WithStrictOrdering());\n\n        tree.GetKeysPostOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 3, 5, 6, 4, 10, 9, 8 },\n                config => config.WithStrictOrdering());\n\n        tree.Remove(9);\n\n        tree.Count.Should().Be(6);\n        tree.Contains(9).Should().BeFalse();\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 3, 4, 5, 6, 8, 10 },\n                config => config.WithStrictOrdering());\n\n        tree.GetKeysPreOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 6, 4, 3, 5, 8, 10 },\n                config => config.WithStrictOrdering());\n\n        tree.GetKeysPostOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 3, 5, 4, 10, 8, 6 },\n                config => config.WithStrictOrdering());\n\n        tree.Remove(3);\n        tree.Remove(4);\n        tree.Remove(5);\n        tree.Remove(6);\n        tree.Remove(8);\n        tree.Remove(10);\n\n        tree.Count.Should().Be(0);\n        tree.GetKeysInOrder().Should().BeEmpty();\n    }\n\n    [Test]\n    public void Remove_MultipleKeys_TreeStillValid_Variant2()\n    {\n        var tree = new AvlTree<int>();\n        tree.AddRange(Data);\n\n        tree.Remove(10);\n\n        tree.Count.Should().Be(9);\n        tree.Contains(10).Should().BeFalse();\n\n        tree.Remove(5);\n\n        tree.Count.Should().Be(8);\n        tree.Contains(5).Should().BeFalse();\n\n        tree.Remove(7);\n\n        tree.Count.Should().Be(7);\n        tree.Contains(7).Should().BeFalse();\n\n        tree.Remove(9);\n\n        tree.Count.Should().Be(6);\n        tree.Contains(9).Should().BeFalse();\n\n        tree.Remove(1);\n\n        tree.Count.Should().Be(5);\n        tree.Contains(1).Should().BeFalse();\n\n        tree.Remove(3);\n\n        tree.Count.Should().Be(4);\n        tree.Contains(3).Should().BeFalse();\n\n        tree.Remove(2);\n\n        tree.Count.Should().Be(3);\n        tree.Contains(2).Should().BeFalse();\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 4, 6, 8 },\n                config => config.WithStrictOrdering());\n\n        tree.GetKeysPreOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 6, 4, 8 },\n                config => config.WithStrictOrdering());\n\n        tree.GetKeysPostOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 4, 8, 6 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Remove_EmptyTree_ThrowsException()\n    {\n        var tree = new AvlTree<int>();\n\n        Invoking(() => tree.Remove(1)).Should().ThrowExactly<KeyNotFoundException>();\n    }\n\n    [Test]\n    public void Remove_KeyNotInTree_ThrowsException()\n    {\n        var tree = new AvlTree<int>();\n        tree.AddRange(Data);\n\n        Invoking(() => tree.Remove(24)).Should().ThrowExactly<KeyNotFoundException>();\n    }\n\n    [Test]\n    public void Contains_CorrectReturn()\n    {\n        var tree = new AvlTree<int>();\n\n        tree.AddRange(Data);\n\n        tree.Contains(3).Should().BeTrue();\n        tree.Contains(7).Should().BeTrue();\n        tree.Contains(24).Should().BeFalse();\n        tree.Contains(-1).Should().BeFalse();\n    }\n\n    [Test]\n    public void Contains_EmptyTree_ReturnsFalse()\n    {\n        var tree = new AvlTree<int>();\n\n        tree.Contains(5).Should().BeFalse();\n        tree.Contains(-12).Should().BeFalse();\n    }\n\n    [Test]\n    public void GetMin_CorrectReturn()\n    {\n        var tree = new AvlTree<int>();\n        tree.AddRange(Data);\n\n        tree.GetMin().Should().Be(1);\n    }\n\n    [Test]\n    public void GetMin_EmptyTree_ThrowsException()\n    {\n        var tree = new AvlTree<int>();\n\n        Invoking(() => tree.GetMin()).Should().ThrowExactly<InvalidOperationException>();\n    }\n\n    [Test]\n    public void GetMax_CorrectReturn()\n    {\n        var tree = new AvlTree<int>();\n        tree.AddRange(Data);\n\n        tree.GetMax().Should().Be(10);\n    }\n\n    [Test]\n    public void GetMax_EmptyTree_ThrowsException()\n    {\n        var tree = new AvlTree<int>();\n\n        Invoking(() => tree.GetMax()).Should().ThrowExactly<InvalidOperationException>();\n    }\n\n    [Test]\n    public void GetKeysInOrder_CorrectReturn()\n    {\n        var tree = new AvlTree<int>();\n        tree.AddRange(Data);\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                Data,\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void GetKeysInOrder_EmptyTree_CorrectReturn()\n    {\n        var tree = new AvlTree<int>();\n\n        tree.GetKeysInOrder().Should().BeEmpty();\n    }\n\n    [Test]\n    public void GetKeysPreOrder_CorrectReturn()\n    {\n        var tree = new AvlTree<int>();\n\n        tree.AddRange(Data);\n\n        tree.GetKeysPreOrder()\n            .Should()\n            .BeEquivalentTo(\n                PreOrder,\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void GetKeysPreOrder_EmptyTree_CorrectReturn()\n    {\n        var tree = new AvlTree<int>();\n\n        tree.GetKeysPreOrder().Should().BeEmpty();\n    }\n\n    [Test]\n    public void GetKeysPostOrder_CorrectReturn()\n    {\n        var tree = new AvlTree<int>();\n        tree.AddRange(Data);\n\n        tree.GetKeysPostOrder()\n            .Should()\n            .BeEquivalentTo(\n                PostOrder,\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void GetKeysPostOrder_EmptyTree_CorrectReturn()\n    {\n        var tree = new AvlTree<int>();\n\n        tree.GetKeysPostOrder().Should().BeEmpty();\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/BTreeTests.cs",
    "content": "using DataStructures.BTree;\nusing static FluentAssertions.FluentActions;\n\nnamespace DataStructures.Tests;\n\ninternal class BTreeTests\n{\n    private static readonly int[] Data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];\n\n    [Test]\n    public void Constructor_DefaultMinimumDegree_CreatesEmptyTree()\n    {\n        var tree = new BTree<int>();\n\n        tree.Count.Should().Be(0);\n        tree.MinimumDegree.Should().Be(2);\n    }\n\n    [Test]\n    public void Constructor_CustomMinimumDegree_SetsCorrectDegree()\n    {\n        var tree = new BTree<int>(3);\n\n        tree.MinimumDegree.Should().Be(3);\n        tree.Count.Should().Be(0);\n    }\n\n    [Test]\n    public void Constructor_MinimumDegreeLessThan2_ThrowsException()\n    {\n        Invoking(() => new BTree<int>(1))\n            .Should()\n            .ThrowExactly<ArgumentException>()\n            .WithMessage(\"Minimum degree must be at least 2.*\");\n    }\n\n    [Test]\n    public void Constructor_CustomComparerMinimumDegreeLessThan2_ThrowsException()\n    {\n        var comparer = Comparer<int>.Create((x, y) => y.CompareTo(x));\n\n        Invoking(() => new BTree<int>(1, comparer))\n            .Should()\n            .ThrowExactly<ArgumentException>()\n            .WithMessage(\"Minimum degree must be at least 2.*\");\n    }\n\n    [Test]\n    public void Constructor_UseCustomComparer_FormsCorrectTree()\n    {\n        var tree = new BTree<int>(2, Comparer<int>.Create((x, y) => y.CompareTo(x)));\n\n        tree.AddRange(new[] { 1, 2, 3, 4, 5 });\n\n        tree.GetMin().Should().Be(5);\n        tree.GetMax().Should().Be(1);\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 5, 4, 3, 2, 1 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Add_SingleKey_IncreasesCount()\n    {\n        var tree = new BTree<int>();\n\n        tree.Add(5);\n\n        tree.Count.Should().Be(1);\n        tree.Contains(5).Should().BeTrue();\n    }\n\n    [Test]\n    public void Add_MultipleKeys_FormsCorrectTree()\n    {\n        var tree = new BTree<int>(2);\n\n        for (var i = 0; i < Data.Length; i++)\n        {\n            tree.Add(Data[i]);\n            tree.Count.Should().Be(i + 1);\n        }\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                Data,\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Add_DuplicateKey_ThrowsException()\n    {\n        var tree = new BTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5 });\n\n        Invoking(() => tree.Add(3))\n            .Should()\n            .ThrowExactly<ArgumentException>()\n            .WithMessage(\"\"\"Key \"3\" already exists in B-Tree.\"\"\");\n    }\n\n    [Test]\n    public void Add_DuplicateKeyInLeaf_ThrowsException()\n    {\n        var tree = new BTree<int>(3);\n        tree.AddRange(new[] { 10, 20 });\n\n        Invoking(() => tree.Add(10))\n            .Should()\n            .ThrowExactly<ArgumentException>()\n            .WithMessage(\"\"\"Key \"10\" already exists in B-Tree.\"\"\");\n    }\n\n    [Test]\n    public void Add_CausesNodeSplit_TreeStillValid()\n    {\n        var tree = new BTree<int>(2);\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7 });\n\n        tree.Count.Should().Be(7);\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 1, 2, 3, 4, 5, 6, 7 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Add_LargeNumberOfKeys_TreeStillValid()\n    {\n        var tree = new BTree<int>(3);\n        var keys = Enumerable.Range(1, 100).ToArray();\n\n        tree.AddRange(keys);\n\n        tree.Count.Should().Be(100);\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                keys,\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void AddRange_MultipleKeys_FormsCorrectTree()\n    {\n        var tree = new BTree<char>(2);\n        tree.AddRange(new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' });\n\n        tree.Count.Should().Be(7);\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void AddRange_EmptyCollection_TreeRemainsEmpty()\n    {\n        var tree = new BTree<int>();\n        tree.AddRange(Array.Empty<int>());\n\n        tree.Count.Should().Be(0);\n        tree.GetKeysInOrder().Should().BeEmpty();\n    }\n\n    [Test]\n    public void Contains_KeyExists_ReturnsTrue()\n    {\n        var tree = new BTree<int>();\n        tree.AddRange(Data);\n\n        tree.Contains(5).Should().BeTrue();\n        tree.Contains(1).Should().BeTrue();\n        tree.Contains(15).Should().BeTrue();\n    }\n\n    [Test]\n    public void Contains_KeyDoesNotExist_ReturnsFalse()\n    {\n        var tree = new BTree<int>();\n        tree.AddRange(Data);\n\n        tree.Contains(100).Should().BeFalse();\n        tree.Contains(-5).Should().BeFalse();\n        tree.Contains(0).Should().BeFalse();\n    }\n\n    [Test]\n    public void Contains_EmptyTree_ReturnsFalse()\n    {\n        var tree = new BTree<int>();\n\n        tree.Contains(5).Should().BeFalse();\n        tree.Contains(-12).Should().BeFalse();\n    }\n\n    [Test]\n    public void Remove_SingleKey_DecreasesCount()\n    {\n        var tree = new BTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5 });\n\n        tree.Remove(3);\n\n        tree.Count.Should().Be(4);\n        tree.Contains(3).Should().BeFalse();\n    }\n\n    [Test]\n    public void Remove_FromLeafNode_TreeStillValid()\n    {\n        var tree = new BTree<int>(2);\n        tree.AddRange(Data);\n\n        tree.Remove(1);\n\n        tree.Count.Should().Be(14);\n        tree.Contains(1).Should().BeFalse();\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Remove_FromNonLeafNode_TreeStillValid()\n    {\n        var tree = new BTree<int>(2);\n        tree.AddRange(Data);\n\n        tree.Remove(8);\n\n        tree.Count.Should().Be(14);\n        tree.Contains(8).Should().BeFalse();\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Remove_CausesMerge_TreeStillValid()\n    {\n        var tree = new BTree<int>(2);\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7 });\n\n        tree.Remove(4);\n\n        tree.Count.Should().Be(6);\n        tree.Contains(4).Should().BeFalse();\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 1, 2, 3, 5, 6, 7 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Remove_MultipleKeys_TreeStillValid()\n    {\n        var tree = new BTree<int>(2);\n        tree.AddRange(Data);\n\n        tree.Remove(5);\n        tree.Remove(10);\n        tree.Remove(15);\n\n        tree.Count.Should().Be(12);\n        tree.Contains(5).Should().BeFalse();\n        tree.Contains(10).Should().BeFalse();\n        tree.Contains(15).Should().BeFalse();\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Remove_AllKeys_TreeBecomesEmpty()\n    {\n        var tree = new BTree<int>(2);\n        tree.AddRange(new[] { 1, 2, 3, 4, 5 });\n\n        tree.Remove(1);\n        tree.Remove(2);\n        tree.Remove(3);\n        tree.Remove(4);\n        tree.Remove(5);\n\n        tree.Count.Should().Be(0);\n        tree.GetKeysInOrder().Should().BeEmpty();\n    }\n\n    [Test]\n    public void Remove_EmptyTree_ThrowsException()\n    {\n        var tree = new BTree<int>();\n\n        Invoking(() => tree.Remove(1))\n            .Should()\n            .ThrowExactly<KeyNotFoundException>()\n            .WithMessage(\"\"\"Key \"1\" is not in the B-Tree.\"\"\");\n    }\n\n    [Test]\n    public void Remove_KeyNotInTree_ThrowsException()\n    {\n        var tree = new BTree<int>();\n        tree.AddRange(Data);\n\n        Invoking(() => tree.Remove(100))\n            .Should()\n            .ThrowExactly<KeyNotFoundException>()\n            .WithMessage(\"\"\"Key \"100\" is not in the B-Tree.\"\"\");\n    }\n\n    [Test]\n    public void GetMin_NonEmptyTree_ReturnsMinimum()\n    {\n        var tree = new BTree<int>();\n        tree.AddRange(new[] { 5, 2, 8, 1, 9, 3 });\n\n        tree.GetMin().Should().Be(1);\n    }\n\n    [Test]\n    public void GetMin_SingleElement_ReturnsElement()\n    {\n        var tree = new BTree<int>();\n        tree.Add(42);\n\n        tree.GetMin().Should().Be(42);\n    }\n\n    [Test]\n    public void GetMin_EmptyTree_ThrowsException()\n    {\n        var tree = new BTree<int>();\n\n        Invoking(() => tree.GetMin())\n            .Should()\n            .ThrowExactly<InvalidOperationException>()\n            .WithMessage(\"B-Tree is empty.\");\n    }\n\n    [Test]\n    public void GetMax_NonEmptyTree_ReturnsMaximum()\n    {\n        var tree = new BTree<int>();\n        tree.AddRange(new[] { 5, 2, 8, 1, 9, 3 });\n\n        tree.GetMax().Should().Be(9);\n    }\n\n    [Test]\n    public void GetMax_SingleElement_ReturnsElement()\n    {\n        var tree = new BTree<int>();\n        tree.Add(42);\n\n        tree.GetMax().Should().Be(42);\n    }\n\n    [Test]\n    public void GetMax_EmptyTree_ThrowsException()\n    {\n        var tree = new BTree<int>();\n\n        Invoking(() => tree.GetMax())\n            .Should()\n            .ThrowExactly<InvalidOperationException>()\n            .WithMessage(\"B-Tree is empty.\");\n    }\n\n    [Test]\n    public void GetKeysInOrder_NonEmptyTree_ReturnsCorrectOrder()\n    {\n        var tree = new BTree<int>(2);\n        tree.AddRange(new[] { 5, 2, 8, 1, 9, 3, 7, 4, 6 });\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void GetKeysInOrder_EmptyTree_ReturnsEmpty()\n    {\n        var tree = new BTree<int>();\n\n        tree.GetKeysInOrder().Should().BeEmpty();\n    }\n\n    [Test]\n    public void GetKeysInOrder_AfterRemoval_ReturnsCorrectOrder()\n    {\n        var tree = new BTree<int>(2);\n        tree.AddRange(Data);\n        tree.Remove(5);\n        tree.Remove(10);\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 15 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void GetKeysPreOrder_NonEmptyTree_ReturnsCorrectOrder()\n    {\n        var tree = new BTree<int>(2);\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7 });\n\n        var preOrder = tree.GetKeysPreOrder().ToArray();\n\n        preOrder.Should().HaveCount(7);\n        preOrder.Should().Contain(new[] { 1, 2, 3, 4, 5, 6, 7 });\n    }\n\n    [Test]\n    public void GetKeysPreOrder_EmptyTree_ReturnsEmpty()\n    {\n        var tree = new BTree<int>();\n\n        tree.GetKeysPreOrder().Should().BeEmpty();\n    }\n\n    [Test]\n    public void GetKeysPostOrder_NonEmptyTree_ReturnsCorrectOrder()\n    {\n        var tree = new BTree<int>(2);\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7 });\n\n        var postOrder = tree.GetKeysPostOrder().ToArray();\n\n        postOrder.Should().HaveCount(7);\n        postOrder.Should().Contain(new[] { 1, 2, 3, 4, 5, 6, 7 });\n    }\n\n    [Test]\n    public void GetKeysPostOrder_EmptyTree_ReturnsEmpty()\n    {\n        var tree = new BTree<int>();\n\n        tree.GetKeysPostOrder().Should().BeEmpty();\n    }\n\n    [Test]\n    public void BTree_LargeDataSet_MaintainsCorrectness()\n    {\n        var tree = new BTree<int>(5);\n        var keys = Enumerable.Range(1, 1000).ToArray();\n\n        tree.AddRange(keys);\n\n        tree.Count.Should().Be(1000);\n        tree.GetMin().Should().Be(1);\n        tree.GetMax().Should().Be(1000);\n\n        var inOrder = tree.GetKeysInOrder().ToArray();\n        inOrder.Should().BeEquivalentTo(keys, config => config.WithStrictOrdering());\n\n        for (var i = 1; i <= 1000; i++)\n        {\n            tree.Contains(i).Should().BeTrue();\n        }\n    }\n\n    [Test]\n    public void BTree_RandomInsertion_MaintainsCorrectness()\n    {\n        var tree = new BTree<int>(3);\n        var random = new Random(42);\n        var keys = Enumerable.Range(1, 100)\n            .OrderBy(_ => random.Next())\n            .ToArray();\n\n        tree.AddRange(keys);\n\n        tree.Count.Should().Be(100);\n\n        var inOrder = tree.GetKeysInOrder().ToArray();\n        inOrder.Should().BeEquivalentTo(\n            Enumerable.Range(1, 100),\n            config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void BTree_RandomDeletion_MaintainsCorrectness()\n    {\n        var tree = new BTree<int>(3);\n        tree.AddRange(Enumerable.Range(1, 50));\n\n        var random = new Random(42);\n        var keysToRemove = Enumerable.Range(1, 50)\n            .OrderBy(_ => random.Next())\n            .Take(25)\n            .ToArray();\n\n        foreach (var key in keysToRemove)\n        {\n            tree.Remove(key);\n        }\n\n        tree.Count.Should().Be(25);\n\n        var remainingKeys = Enumerable.Range(1, 50)\n            .Except(keysToRemove)\n            .OrderBy(x => x)\n            .ToArray();\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                remainingKeys,\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void BTree_StringKeys_WorksCorrectly()\n    {\n        var tree = new BTree<string>(2);\n        var keys = new[] { \"apple\", \"banana\", \"cherry\", \"date\", \"elderberry\", \"fig\", \"grape\" };\n\n        tree.AddRange(keys);\n\n        tree.Count.Should().Be(7);\n        tree.GetMin().Should().Be(\"apple\");\n        tree.GetMax().Should().Be(\"grape\");\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                keys.OrderBy(x => x),\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void BTree_DifferentMinimumDegrees_AllWorkCorrectly()\n    {\n        for (var degree = 2; degree <= 10; degree++)\n        {\n            var tree = new BTree<int>(degree);\n            tree.AddRange(Enumerable.Range(1, 50));\n\n            tree.Count.Should().Be(50);\n            tree.GetKeysInOrder()\n                .Should()\n                .BeEquivalentTo(\n                    Enumerable.Range(1, 50),\n                    config => config.WithStrictOrdering());\n        }\n    }\n\n    [Test]\n    public void BTree_InsertRemoveInsert_WorksCorrectly()\n    {\n        var tree = new BTree<int>(2);\n\n        tree.AddRange(new[] { 1, 2, 3, 4, 5 });\n        tree.Remove(3);\n        tree.Add(3);\n\n        tree.Count.Should().Be(5);\n        tree.Contains(3).Should().BeTrue();\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 1, 2, 3, 4, 5 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Remove_BorrowFromPreviousSibling_TreeStillValid()\n    {\n        var tree = new BTree<int>(3);\n\n        tree.AddRange(new[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 });\n\n        tree.Remove(100);\n\n        tree.Count.Should().Be(9);\n        tree.Contains(100).Should().BeFalse();\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 10, 20, 30, 40, 50, 60, 70, 80, 90 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Remove_BorrowFromNextSibling_TreeStillValid()\n    {\n        var tree = new BTree<int>(3);\n\n        tree.AddRange(new[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 });\n\n        tree.Remove(10);\n\n        tree.Count.Should().Be(9);\n        tree.Contains(10).Should().BeFalse();\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 20, 30, 40, 50, 60, 70, 80, 90, 100 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Remove_UsesPredecessor_TreeStillValid()\n    {\n        var tree = new BTree<int>(3);\n\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 });\n\n        var rootKeys = tree.GetKeysPreOrder().Take(3).ToArray();\n        var keyToRemove = rootKeys[0];\n\n        tree.Remove(keyToRemove);\n\n        tree.Contains(keyToRemove).Should().BeFalse();\n        tree.Count.Should().Be(14);\n\n        var inOrder = tree.GetKeysInOrder().ToArray();\n        inOrder.Should().HaveCount(14);\n        inOrder.Should().BeInAscendingOrder();\n    }\n\n    [Test]\n    public void Remove_UsesSuccessor_TreeStillValid()\n    {\n        var tree = new BTree<int>(2);\n\n        tree.AddRange(new[] { 10, 20, 30, 40, 50, 60, 70 });\n\n        tree.Remove(40);\n\n        tree.Contains(40).Should().BeFalse();\n        tree.Count.Should().Be(6);\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 10, 20, 30, 50, 60, 70 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Remove_MergeWithSibling_TreeStillValid()\n    {\n        var tree = new BTree<int>(2);\n\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });\n\n        tree.Remove(9);\n        tree.Remove(8);\n        tree.Remove(7);\n\n        tree.Count.Should().Be(6);\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 1, 2, 3, 4, 5, 6 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Remove_ComplexRebalancing_TreeStillValid()\n    {\n        var tree = new BTree<int>(3);\n\n        tree.AddRange(Enumerable.Range(1, 30));\n\n        var keysToRemove = new[] { 5, 15, 25, 10, 20, 30, 1, 29 };\n\n        foreach (var key in keysToRemove)\n        {\n            tree.Remove(key);\n            tree.Contains(key).Should().BeFalse();\n        }\n\n        tree.Count.Should().Be(22);\n\n        var expected = Enumerable.Range(1, 30).Except(keysToRemove).OrderBy(x => x);\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                expected,\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void Remove_FromMinimumDegree3_AllRebalancingPaths()\n    {\n        var tree = new BTree<int>(3);\n\n        tree.AddRange(Enumerable.Range(1, 50));\n        var keysToRemove = new[] { 25, 12, 37, 6, 44, 18, 31, 3, 47, 15 };\n\n        foreach (var key in keysToRemove)\n        {\n            var countBefore = tree.Count;\n            tree.Remove(key);\n\n            tree.Count.Should().Be(countBefore - 1);\n            tree.Contains(key).Should().BeFalse();\n\n            var inOrder = tree.GetKeysInOrder().ToArray();\n            inOrder.Should().BeInAscendingOrder();\n        }\n\n        tree.Count.Should().Be(40);\n    }\n\n    [Test]\n    public void Remove_SequentialFromLargeTree_MaintainsStructure()\n    {\n        var tree = new BTree<int>(4);\n\n        tree.AddRange(Enumerable.Range(1, 100));\n        for (var i = 3; i <= 99; i += 3)\n        {\n            tree.Remove(i);\n        }\n\n        tree.Count.Should().Be(67);\n\n        var inOrder = tree.GetKeysInOrder().ToArray();\n        inOrder.Should().HaveCount(67);\n        inOrder.Should().BeInAscendingOrder();\n\n        tree.Contains(3).Should().BeFalse();\n        tree.Contains(6).Should().BeFalse();\n        tree.Contains(99).Should().BeFalse();\n        tree.Contains(1).Should().BeTrue();\n        tree.Contains(2).Should().BeTrue();\n        tree.Contains(100).Should().BeTrue();\n    }\n\n    [Test]\n    public void BTree_DegreeThree_CompleteInsertDeleteCycle()\n    {\n        var tree = new BTree<int>(3);\n\n        var keys = Enumerable.Range(1, 40).ToArray();\n        tree.AddRange(keys);\n        tree.Count.Should().Be(40);\n\n        for (var i = 2; i <= 40; i += 2)\n        {\n            tree.Remove(i);\n        }\n\n        tree.Count.Should().Be(20);\n\n        var remaining = tree.GetKeysInOrder().ToArray();\n        remaining.Should().BeEquivalentTo(\n            Enumerable.Range(1, 40).Where(x => x % 2 != 0),\n            config => config.WithStrictOrdering());\n\n        tree.Add(2);\n        tree.Add(4);\n        tree.Count.Should().Be(22);\n\n        tree.Contains(2).Should().BeTrue();\n        tree.Contains(4).Should().BeTrue();\n    }\n\n    [Test]\n    public void Remove_RootWithMultipleChildren_HandledCorrectly()\n    {\n        var tree = new BTree<int>(2);\n\n        tree.AddRange(new[] { 1, 2, 3, 4, 5 });\n        tree.Remove(3);\n        tree.Count.Should().Be(4);\n\n        tree.GetKeysInOrder()\n            .Should()\n            .BeEquivalentTo(\n                new[] { 1, 2, 4, 5 },\n                config => config.WithStrictOrdering());\n    }\n\n    [Test]\n    public void BTree_HighDegree_StressTest()\n    {\n        var tree = new BTree<int>(10);\n\n        tree.AddRange(Enumerable.Range(1, 200));\n        tree.Count.Should().Be(200);\n\n        for (var i = 10; i <= 200; i += 10)\n        {\n            tree.Remove(i);\n        }\n\n        tree.Count.Should().Be(180);\n\n        var inOrder = tree.GetKeysInOrder().ToArray();\n        inOrder.Should().HaveCount(180);\n        inOrder.Should().BeInAscendingOrder();\n\n        tree.Contains(10).Should().BeFalse();\n        tree.Contains(100).Should().BeFalse();\n        tree.Contains(200).Should().BeFalse();\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/BagTests.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing DataStructures.Bag;\nusing FluentAssertions;\nusing NUnit.Framework;\n\nnamespace DataStructures.Tests;\n\ninternal class BagTests\n{\n    [Test]\n    public void Add_ShouldIncreaseCount()\n    {\n        // Arrange & Act\n        var bag = new Bag<int>\n        {\n            1,\n            2,\n            1\n        };\n\n        // Assert\n        bag.Count.Should().Be(3);\n    }\n\n    [Test]\n    public void Add_ShouldHandleDuplicates()\n    {\n        // Arrange & Act\n        var bag = new Bag<string>\n        {\n            \"apple\",\n            \"apple\"\n        };\n\n        // Assert\n        bag.Count.Should().Be(2);\n        bag.Should().Contain(\"apple\");\n    }\n\n    [Test]\n    public void Clear_ShouldEmptyTheBag()\n    {\n        // Arrange\n        var bag = new Bag<int>\n        {\n            1,\n            2\n        };\n\n        // Act\n        bag.Clear();\n\n        // Assert\n        bag.IsEmpty().Should().BeTrue();\n        bag.Count.Should().Be(0);\n    }\n\n    [Test]\n    public void IsEmpty_ShouldReturnTrueForEmptyBag()\n    {\n        // Arrange\n        var bag = new Bag<int>();\n\n        // Act & Assert\n        bag.IsEmpty().Should().BeTrue();\n    }\n\n    [Test]\n    public void IsEmpty_ShouldReturnFalseForNonEmptyBag()\n    {\n        // Arrange\n        var bag = new Bag<int>\n        {\n            1\n        };\n\n        // Act & Assert\n        bag.IsEmpty().Should().BeFalse();\n    }\n\n    [Test]\n    public void GetEnumerator_ShouldIterateAllItems()\n    {\n        // Arrange\n        var bag = new Bag<int>\n        {\n            1,\n            2,\n            1\n        };\n\n        // Act\n        var items = bag.ToList();\n\n        // Assert\n        items.Count.Should().Be(3);\n        items.Should().Contain(1);\n        items.Should().Contain(2);\n    }\n\n    [Test]\n    public void Count_ShouldReturnZeroForEmptyBag()\n    {\n        // Arrange\n        var bag = new Bag<int>();\n\n        // Act & Assert\n        bag.Count.Should().Be(0);\n    }\n\n    [Test]\n    public void Count_ShouldReturnCorrectCount()\n    {\n        // Arrange\n        var bag = new Bag<int>\n        {\n            1,\n            2,\n            1\n        };\n\n        // Act & Assert\n        bag.Count.Should().Be(3);\n    }\n\n    [Test]\n    public void IEnumerableGetEnumerator_YieldsAllItemsWithCorrectMultiplicity()\n    {\n        // Arrange\n        var bag = new Bag<string>\n        {\n            \"apple\",\n            \"banana\",\n            \"apple\"\n        };\n        var genericBag = bag as System.Collections.IEnumerable;\n\n        // Act\n        var enumerator = genericBag.GetEnumerator();\n        var items = new List<object>();\n        while (enumerator.MoveNext())\n        {\n            items.Add(enumerator.Current!);\n        }\n\n        // Assert\n        items.Count(i => (string)i == \"apple\").Should().Be(2);\n        items.Count(i => (string)i == \"banana\").Should().Be(1);\n        items.Count.Should().Be(3);\n        items.Should().BeEquivalentTo([\"apple\", \"apple\", \"banana\"]);\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/BinarySearchTreeTests.cs",
    "content": "using DataStructures.BinarySearchTree;\n\nnamespace DataStructures.Tests;\n\npublic static class BinarySearchTreeTests\n{\n    [Test]\n    public static void Constructor_UseCustomComparer_FormsCorrectTree()\n    {\n        var cmpFunc = Comparer<string>.Create((x, y) => x.Length - y.Length);\n        var tree = new BinarySearchTree<string>(cmpFunc);\n        var elems = new[] { \"z\", \"yy\", \"vvv\", \"bbbb\", \"fffff\", \"pppppp\" };\n        tree.AddRange(elems);\n\n        Assert.That(tree.Search(\"vvv\"), Is.Not.Null);\n        Assert.That(tree.Search(\"vvv\")!.Right, Is.Not.Null);\n        Assert.That(tree.Search(\"vvv\")!.Right!.Key, Is.EqualTo(\"bbbb\"));\n    }\n\n    [Test]\n    public static void Add_MultipleKeys_FormsCorrectBST()\n    {\n        var tree = new BinarySearchTree<int>();\n\n        tree.Add(5);\n        Assert.That(tree.Count, Is.EqualTo(1));\n\n        tree.Add(3);\n        Assert.That(tree.Count, Is.EqualTo(2));\n\n        tree.Add(4);\n        Assert.That(tree.Count, Is.EqualTo(3));\n\n        tree.Add(2);\n        Assert.That(tree.Count, Is.EqualTo(4));\n\n        var rootNode = tree.Search(5);\n        Assert.That(rootNode!.Key, Is.EqualTo(5));\n        Assert.That(rootNode!.Left!.Key, Is.EqualTo(3));\n        Assert.That(rootNode!.Right, Is.Null);\n\n        var threeNode = tree.Search(3);\n        Assert.That(threeNode!.Key, Is.EqualTo(3));\n        Assert.That(threeNode!.Left!.Key, Is.EqualTo(2));\n        Assert.That(threeNode!.Right!.Key, Is.EqualTo(4));\n\n        var twoNode = tree.Search(2);\n        Assert.That(twoNode!.Left, Is.Null);\n        Assert.That(twoNode!.Right, Is.Null);\n\n        var fourNode = tree.Search(4);\n        Assert.That(fourNode!.Left, Is.Null);\n        Assert.That(fourNode!.Right, Is.Null);\n    }\n\n    [Test]\n    public static void Add_KeyAlreadyInTree_ThrowsCorrectException()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2 });\n\n        _ = Assert.Throws<ArgumentException>(() => tree.Add(5));\n    }\n\n    [Test]\n    public static void AddRange_MultipleKeys_FormsCorrectBST()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2 });\n\n        var rootNode = tree.Search(5);\n        Assert.That(rootNode!.Key, Is.EqualTo(5));\n        Assert.That(rootNode!.Left!.Key, Is.EqualTo(3));\n        Assert.That(rootNode!.Right, Is.Null);\n\n        var threeNode = tree.Search(3);\n        Assert.That(threeNode!.Key, Is.EqualTo(3));\n        Assert.That(threeNode!.Left!.Key, Is.EqualTo(2));\n        Assert.That(threeNode!.Right!.Key, Is.EqualTo(4));\n\n        var twoNode = tree.Search(2);\n        Assert.That(twoNode!.Left, Is.Null);\n        Assert.That(twoNode!.Right, Is.Null);\n\n        var fourNode = tree.Search(4);\n        Assert.That(fourNode!.Left, Is.Null);\n        Assert.That(fourNode!.Right, Is.Null);\n    }\n\n    [Test]\n    public static void Search_MultipleKeys_FindsAllKeys()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2, 7, 6, 8 });\n\n        Assert.That(tree.Search(2)!.Key, Is.EqualTo(2));\n        Assert.That(tree.Search(3)!.Key, Is.EqualTo(3));\n        Assert.That(tree.Search(4)!.Key, Is.EqualTo(4));\n        Assert.That(tree.Search(5)!.Key, Is.EqualTo(5));\n        Assert.That(tree.Search(6)!.Key, Is.EqualTo(6));\n        Assert.That(tree.Search(7)!.Key, Is.EqualTo(7));\n        Assert.That(tree.Search(8)!.Key, Is.EqualTo(8));\n    }\n\n    [Test]\n    public static void Contains_MultipleKeys_FindsAllKeys()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2, 7, 6, 8 });\n\n        Assert.That(tree.Contains(2), Is.True);\n        Assert.That(tree.Contains(3), Is.True);\n        Assert.That(tree.Contains(4), Is.True);\n        Assert.That(tree.Contains(5), Is.True);\n        Assert.That(tree.Contains(6), Is.True);\n        Assert.That(tree.Contains(7), Is.True);\n        Assert.That(tree.Contains(8), Is.True);\n    }\n\n    [Test]\n    public static void Remove_LeafNodes_CorrectlyRemovesNodes()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2, 7, 6, 8 });\n\n        var twoRemoveResult = tree.Remove(2);\n        Assert.That(twoRemoveResult, Is.True);\n        Assert.That(tree.Search(2), Is.Null);\n        Assert.That(tree.Search(3)!.Left, Is.Null);\n        Assert.That(tree.Search(3)!.Right, Is.Not.Null);\n        Assert.That(tree.Count, Is.EqualTo(6));\n\n        var fourRemoveResult = tree.Remove(4);\n        Assert.That(fourRemoveResult, Is.True);\n        Assert.That(tree.Search(4), Is.Null);\n        Assert.That(tree.Search(3)!.Left, Is.Null);\n        Assert.That(tree.Search(3)!.Right, Is.Null);\n        Assert.That(tree.Count, Is.EqualTo(5));\n    }\n\n    [Test]\n    public static void Remove_NodesWithOneChild_CorrectlyRemovesNodes()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2, 7, 6, 8 });\n\n        tree.Remove(4);\n        var threeRemoveResult = tree.Remove(3);\n        Assert.That(threeRemoveResult, Is.True);\n        Assert.That(tree.Search(3), Is.Null);\n        Assert.That(tree.Search(2)!.Left, Is.Null);\n        Assert.That(tree.Search(2)!.Right, Is.Null);\n        Assert.That(tree.Count, Is.EqualTo(5));\n\n        tree.Remove(6);\n        var sevenRemoveResult = tree.Remove(7);\n        Assert.That(sevenRemoveResult, Is.True);\n        Assert.That(tree.Search(7), Is.Null);\n        Assert.That(tree.Search(8)!.Left, Is.Null);\n        Assert.That(tree.Search(8)!.Right, Is.Null);\n        Assert.That(tree.Count, Is.EqualTo(3));\n    }\n\n    [Test]\n    public static void Remove_NodesWithTwoChildren_CorrectlyRemovesNodes()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2, 7, 6, 8 });\n\n        var sevenRemoveResult = tree.Remove(7);\n        Assert.That(sevenRemoveResult, Is.True);\n        Assert.That(tree.Search(7), Is.Null);\n        Assert.That(tree.Search(6)!.Left, Is.Null);\n        Assert.That(tree.Search(6)!.Right, Is.Not.Null);\n        Assert.That(tree.Count, Is.EqualTo(6));\n    }\n\n    [Test]\n    public static void Remove_NonExistentElement_ReturnsFalse()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2, 7, 6, 8 });\n\n        Assert.That(tree.Remove(999), Is.False);\n        Assert.That(tree.Count, Is.EqualTo(7));\n    }\n\n    [Test]\n    public static void Remove_EmptyTree_ReturnsFalse()\n    {\n        var tree = new BinarySearchTree<int>();\n        Assert.That(tree.Remove(8), Is.False);\n        Assert.That(tree.Count, Is.EqualTo(0));\n    }\n\n    [Test]\n    public static void Remove_RemoveRoot_CorrectlyRemovesRoot()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.Add(5);\n        tree.Remove(5);\n\n        Assert.That(tree.Count, Is.EqualTo(0));\n        Assert.That(tree.Search(5), Is.Null);\n\n        tree.AddRange(new List<int> { 5, 4, 6 });\n        tree.Remove(5);\n\n        Assert.That(tree.Count, Is.EqualTo(2));\n        Assert.That(tree.Search(5), Is.Null);\n        Assert.That(tree.Search(4), Is.Not.Null);\n        Assert.That(tree.Search(6), Is.Not.Null);\n        Assert.That(tree.Search(4)!.Right!.Key, Is.EqualTo(6));\n    }\n\n    [Test]\n    public static void GetMax_NonEmptyTree_ReturnsCorrectValue()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2, 7, 6, 8 });\n\n        Assert.That(tree.GetMax()!.Key, Is.EqualTo(8));\n    }\n\n    [Test]\n    public static void GetMax_EmptyTree_ReturnsDefaultValue()\n    {\n        var tree = new BinarySearchTree<int>();\n        Assert.That(tree.GetMax(), Is.Null);\n    }\n\n    [Test]\n    public static void GetMin_NonEmptyTree_ReturnsCorrectValue()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2, 7, 6, 8 });\n\n        Assert.That(tree.GetMin()!.Key, Is.EqualTo(2));\n    }\n\n    [Test]\n    public static void GetMin_EmptyTree_ReturnsDefaultValue()\n    {\n        var tree = new BinarySearchTree<int>();\n        Assert.That(tree.GetMin(), Is.Null);\n    }\n\n    [Test]\n    public static void GetKeysInOrder_MultipleKeys_ReturnsAllKeysInCorrectOrder()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2, 7, 6, 8 });\n\n        var keys = tree.GetKeysInOrder();\n        var expected = new List<int> { 2, 3, 4, 5, 6, 7, 8 };\n        Assert.That(keys.SequenceEqual(expected), Is.True);\n    }\n\n    [Test]\n    public static void GetKeysPreOrder_MultipleKeys_ReturnsAllKeysInCorrectOrder()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2, 7, 6, 8 });\n\n        var keys = tree.GetKeysPreOrder();\n        var expected = new List<int> { 5, 3, 2, 4, 7, 6, 8 };\n        Assert.That(keys.SequenceEqual(expected), Is.True);\n    }\n\n    [Test]\n    public static void GetKeysPostOrder_MultipleKeys_ReturnsAllKeysInCorrectOrder()\n    {\n        var tree = new BinarySearchTree<int>();\n        tree.AddRange(new List<int> { 5, 3, 4, 2, 7, 6, 8 });\n\n        var keys = tree.GetKeysPostOrder();\n        var expected = new List<int> { 2, 4, 3, 6, 8, 7, 5 };\n        Assert.That(keys.SequenceEqual(expected), Is.True);\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/BitArrayTests.cs",
    "content": "namespace DataStructures.Tests;\n\n/// <summary>\n///     This class contains some tests for the class BitArray.\n/// </summary>\npublic static class BitArrayTests\n{\n    [Test]\n    public static void TestIndexer()\n    {\n        // Arrange\n        var testObj = new BitArray(5);\n\n        // Act\n        testObj.Compile(24);\n\n        // Assert\n        Assert.That(testObj[0], Is.True);\n        Assert.That(testObj[1], Is.True);\n        Assert.That(testObj[3], Is.False);\n    }\n\n    [TestCase(19, 3)]\n    public static void TestNumberOfOneBits(int number, int expected)\n    {\n        // Arrange\n        var testObj = new BitArray(5);\n\n        // Act\n        testObj.Compile(number);\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(testObj.NumberOfOneBits()));\n    }\n\n    [TestCase(26, 2)]\n    public static void TestNumberOfZeroBits(int number, int expected)\n    {\n        // Arrange\n        var testObj = new BitArray(5);\n\n        // Act\n        testObj.Compile(number);\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(testObj.NumberOfZeroBits()));\n    }\n\n    [TestCase(33, 33)]\n    public static void TestToInt64(int number, int expected)\n    {\n        // Arrange\n        var testObj = new BitArray(6);\n\n        // Act\n        testObj.Compile(number);\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(testObj.ToInt64()));\n    }\n\n    [Test]\n    public static void TestToInt32MaxValue()\n    {\n        // Arrange\n        var testObj = new BitArray(33);\n\n        // Act\n\n        // Assert\n        _ = Assert.Throws<InvalidOperationException>(() => testObj.ToInt32());\n    }\n\n    [Test]\n    public static void TestToInt64MaxValue()\n    {\n        // Arrange\n        var testObj = new BitArray(65);\n\n        // Act\n\n        // Assert\n        _ = Assert.Throws<InvalidOperationException>(() => testObj.ToInt64());\n    }\n\n    [TestCase(\"110\")]\n    public static void TestResetField(string sequence)\n    {\n        // Arrange\n        var testObj = new BitArray(sequence);\n\n        // Act\n        testObj.ResetField();\n\n        // Assert\n        Assert.That(0, Is.EqualTo(testObj.ToInt64()));\n    }\n\n    [TestCase(\"101001\", 63)]\n    public static void TestSetAll(string sequence, int expected)\n    {\n        // Arrange\n        var testObj = new BitArray(sequence);\n\n        // Act\n        testObj.SetAll(true);\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(testObj.ToInt64()));\n    }\n\n    [Test]\n    public static void TestCloneEquals()\n    {\n        // Arrange\n        var testObj1 = new BitArray(\"110\");\n\n        // Act\n        var testObj2 = (BitArray)testObj1.Clone();\n\n        // Assert\n        Assert.That(testObj1.Equals(testObj2), Is.True);\n    }\n\n    [Test]\n    public static void TestCloneNotEquals()\n    {\n        // Arrange\n        var testObj1 = new BitArray(\"101\");\n        var testObj2 = new BitArray(15);\n        var testObj3 = new BitArray(3);\n\n        // Act\n        testObj3.Reset();\n\n        // Assert\n        testObj1.Equals(testObj2).Should().BeFalse();\n        testObj1.Equals(testObj3).Should().BeFalse();\n    }\n\n    [Test]\n    public static void TestHasCode()\n    {\n        // Arrange\n        const int num = 5;\n        var testObj = new BitArray(3);\n\n        // Act\n        testObj.Compile(num);\n        var result = testObj.GetHashCode();\n\n        // Assert\n        Assert.That(result, Is.Not.Null);\n        Assert.That(5, Is.EqualTo(result));\n    }\n\n    [Test]\n    public static void TestMoveNextCurrent()\n    {\n        var testObj1 = new BitArray(\"1111010\");\n\n        var counterOnes = 0;\n        var counterZeros = 0;\n\n        foreach (var bit in testObj1)\n        {\n            if (bit)\n            {\n                counterOnes++;\n            }\n            else\n            {\n                counterZeros++;\n            }\n        }\n\n        Assert.That(counterOnes, Is.EqualTo(5));\n        Assert.That(counterZeros, Is.EqualTo(2));\n    }\n\n    [Test]\n    public static void IEnumerable_IterationWorks()\n    {\n        var arr = new BitArray(\"010101010101010101\");\n        var current = 0;\n        foreach (var b in arr)\n        {\n            b.Should().Be(arr[current]);\n            current++;\n        }\n    }\n\n    [Test]\n    public static void Equals_NullIsNotEqualToNotNull()\n    {\n        var arr1 = new BitArray(\"010101010101010101\");\n        BitArray? arr2 = null;\n        arr1.Equals(arr2).Should().BeFalse();\n    }\n\n    #region COMPILE TESTS\n\n    [TestCase(\"00100\", \"00100\")]\n    [TestCase(\"01101\", \"01101\")]\n    [TestCase(\"100\", \"00100\")]\n    public static void TestCompileToString(string sequence, string expectedSequence)\n    {\n        // Arrange\n        var testObj = new BitArray(5);\n\n        // Act\n        testObj.Compile(sequence);\n\n        // Assert\n        Assert.That(expectedSequence, Is.EqualTo(testObj.ToString()));\n    }\n\n    [TestCase(\"klgml\", 5)]\n    [TestCase(\"klgml\", 3)]\n    public static void TestCompileToStringThorwsException(string sequence, int arrLen)\n    {\n        // Arrange\n        var testObj = new BitArray(arrLen);\n\n        // Act\n        void Act() => testObj.Compile(sequence);\n\n        // Assert\n        Assert.Throws<ArgumentException>(Act);\n    }\n\n    [TestCase(15, \"01111\")]\n    [TestCase(17, \"10001\")]\n    [TestCase(4, \"00100\")]\n    public static void TestCompileLong(int number, string expected)\n    {\n        // Arrange\n        var testObj = new BitArray(5);\n\n        // Act\n        testObj.Compile((long)number);\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(testObj.ToString()));\n    }\n\n    [TestCase(46, 3)]\n    [TestCase(-46, 5)]\n    public static void TestCompileLongThrowsException(int number, int arrLen)\n    {\n        // Arrange\n        var testObj = new BitArray(arrLen);\n\n        // Act\n        void Act() => testObj.Compile((long)number);\n\n        // Assert\n        Assert.Throws<ArgumentException>(Act);\n    }\n\n    [TestCase(17, \"10001\")]\n    [TestCase(25, \"11001\")]\n    [TestCase(4, \"00100\")]\n    public static void TestCompileInteger(int number, string expected)\n    {\n        // Arrange\n        var testObj = new BitArray(5);\n\n        // Act\n        testObj.Compile(number);\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(testObj.ToString()));\n    }\n\n    [TestCase(-8, 5)]\n    [TestCase(18, 3)]\n    public static void TestCompileIntegerThrowsException(int number, int arrayLength)\n    {\n        // Arrange\n        var testObj = new BitArray(arrayLength);\n\n        // Act\n        void Act() => testObj.Compile(number);\n\n        // Assert\n        Assert.Throws<ArgumentException>(Act);\n    }\n\n    #endregion COMPILE TESTS\n\n    #region CONSTRUCTOR TESTS\n\n    [TestCase(\"00100\", 4)]\n    public static void TestConstructor(string sequence, int expected)\n    {\n        // Arrange\n        var testObj1 = new BitArray(sequence);\n\n        // Act\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(testObj1.ToInt64()));\n    }\n\n    [TestCase(new[] { true, false, true }, 5)]\n    public static void TestConstructorBoolArray(bool[] sequence, int expected)\n    {\n        // Arrange\n        var testObj3 = new BitArray(sequence);\n\n        // Act\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(testObj3.ToInt64()));\n    }\n\n    [TestCase(\"000120\")]\n    [TestCase(\"\")]\n    public static void TestConstructorThrowsException(string sequence)\n    {\n        // Arrange\n\n        // Act\n        Action act = () => new BitArray(sequence);\n\n        // Assert\n        act.Should().Throw<ArgumentException>();\n    }\n\n    #endregion CONSTRUCTOR TESTS\n\n    #region OPERATOR TESTS\n\n    [TestCase(17, 17, \"10001\")]\n    [TestCase(25, 31, \"11001\")]\n    public static void TestOperatorAnd(int tObj1, int tObj2, string expected)\n    {\n        // Arrange\n        var testObj1 = new BitArray(5);\n        var testObj2 = new BitArray(5);\n\n        // Act\n        testObj1.Compile(tObj1);\n        testObj2.Compile(tObj2);\n\n        var result = testObj1 & testObj2;\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(result.ToString()));\n    }\n\n    [TestCase(1, 1, 1, 1, \"0\")]\n    [TestCase(5, 3, 8, 4, \"1101\")]\n    [TestCase(9, 4, 4, 3, \"1101\")]\n    public static void TestOperatorXorAndDiffSizes(int t1, int s1, int t2, int s2, string expected)\n    {\n        // Arrange\n        var testObj1 = new BitArray(s1);\n        var testObj2 = new BitArray(s2);\n\n        // Act\n        testObj1.Compile(t1);\n        testObj2.Compile(t2);\n        var result = testObj1 ^ testObj2;\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(result.ToString()));\n    }\n\n    [TestCase(9, 4, 4, 3, \"1101\")]\n    [TestCase(1, 1, 1, 1, \"1\")]\n    [TestCase(5, 3, 8, 4, \"1101\")]\n    public static void TestOperatorOrAndDiffSizes(int t1, int s1, int t2, int s2, string expected)\n    {\n        // Arrange\n        var testObj1 = new BitArray(s1);\n        var testObj2 = new BitArray(s2);\n\n        // Act\n        testObj1.Compile(t1);\n        testObj2.Compile(t2);\n        var result = testObj1 | testObj2;\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(result.ToString()));\n    }\n\n    [TestCase(1, 1, 1, 1, \"1\")]\n    [TestCase(5, 3, 8, 4, \"0000\")]\n    [TestCase(9, 4, 4, 3, \"0000\")]\n    public static void TestOperatorAndAndDiffSizes(int t1, int s1, int t2, int s2, string expected)\n    {\n        // Arrange\n        var testObj1 = new BitArray(s1);\n        var testObj2 = new BitArray(s2);\n\n        // Act\n        testObj1.Compile(t1);\n        testObj2.Compile(t2);\n        var result = testObj1 & testObj2;\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(result.ToString()));\n    }\n\n    [TestCase(25, 30, \"11111\")]\n    public static void TestOperatorOr(int tObj1, int tObj2, string expected)\n    {\n        // Arrange\n        var testObj1 = new BitArray(5);\n        var testObj2 = new BitArray(5);\n\n        // Act\n        testObj1.Compile(tObj1);\n        testObj2.Compile(tObj2);\n\n        var result = testObj1 | testObj2;\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(result.ToString()));\n    }\n\n    [TestCase(16, \"01111\")]\n    public static void TestOperatorNot(int number, string expected)\n    {\n        // Arrange\n        var testObj = new BitArray(5);\n\n        // Act\n        testObj.Compile(number);\n        testObj = ~testObj;\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(testObj.ToString()));\n    }\n\n    [TestCase(25, 30, 7)]\n    public static void TestOperatorXor(int testNum, int testNum2, int expected)\n    {\n        // Arrange\n        var testObj1 = new BitArray(5);\n        var testObj2 = new BitArray(5);\n\n        // Act\n        testObj1.Compile(testNum);\n        testObj2.Compile(testNum2);\n\n        var result = testObj1 ^ testObj2;\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(result.ToInt32()));\n    }\n\n    [TestCase(16, \"10000000\")]\n    public static void TestOperatorShiftLeft(int number, string expected)\n    {\n        // Arrange\n        var testObj = new BitArray(5);\n\n        // Act\n        testObj.Compile(number);\n        testObj <<= 3;\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(testObj.ToString()));\n    }\n\n    [TestCase(24, \"110\")]\n    public static void TestOperatorShiftRight(int number, string expected)\n    {\n        // Arrange\n        var testObj = new BitArray(5);\n\n        // Act\n        testObj.Compile(number);\n        testObj >>= 2;\n\n        // Assert\n        Assert.That(expected, Is.EqualTo(testObj.ToString()));\n    }\n\n    #endregion OPERATOR TESTS\n\n    #region COMPARE TESTS\n\n    [Test]\n    public static void TestParity()\n    {\n        // Arrange\n        var testObj = new BitArray(5);\n\n        // Act\n        testObj.Compile(26);\n\n        // Assert\n        Assert.That(testObj.EvenParity(), Is.False);\n        Assert.That(testObj.OddParity(), Is.True);\n    }\n\n    [Test]\n    public static void TestCompare()\n    {\n        // Arrange\n        var testObj1 = new BitArray(\"110\");\n        var testObj2 = new BitArray(\"110\");\n        var testObj3 = new BitArray(\"100\");\n\n        // Act\n\n        // Assert\n        Assert.That(testObj1 == testObj2, Is.True);\n        Assert.That(testObj1 != testObj3, Is.True);\n    }\n\n    [Test]\n    public static void ArraysOfDifferentLengthsAreNotEqual()\n    {\n        // Arrange\n        var testObj1 = new BitArray(\"110\");\n        var testObj2 = new BitArray(\"10101\");\n\n        // Act\n\n        // Assert\n        Assert.That(testObj1 == testObj2, Is.False);\n    }\n\n    #endregion COMPARE TESTS\n}\n"
  },
  {
    "path": "DataStructures.Tests/Cache/LfuCacheTests.cs",
    "content": "using DataStructures.Cache;\n\nnamespace DataStructures.Tests.Cache;\n\npublic static class LfuCacheTests\n{\n    [Test]\n    public static void TestPutGet()\n    {\n        var cache = new LfuCache<int, string>();\n        cache.Put(1, \"one\");\n\n        cache.Contains(1).Should().BeTrue();\n        cache.Get(1).Should().Be(\"one\");\n    }\n\n    [Test]\n    public static void TestCacheMiss()\n    {\n        var cache = new LfuCache<int, string>();\n        cache.Put(1, \"one\");\n\n        cache.Contains(5).Should().BeFalse();\n        cache.Get(5).Should().BeNull();\n    }\n\n    [Test]\n    public static void Evict_ItemWasNotUsed()\n    {\n        var cache = new LfuCache<int, string>(capacity: 1);\n        cache.Put(1, \"one\");\n\n        // Add to the full cache, 1 will be removed\n        cache.Put(2, \"two\");\n\n        cache.Get(1).Should().BeNull();\n        cache.Get(2).Should().Be(\"two\");\n    }\n\n    [Test]\n    public static void Evict_OneItemWasUsed()\n    {\n        var cache = new LfuCache<int, string>(capacity: 2);\n        cache.Put(1, \"one\");\n        cache.Put(2, \"two\");\n\n        cache.Put(1, \"ONE\");\n\n        // Add to the full cache, 2 will be removed\n        cache.Put(3, \"three\");\n\n        cache.Get(1).Should().Be(\"ONE\");\n        cache.Get(2).Should().BeNull();\n        cache.Get(3).Should().Be(\"three\");\n    }\n\n    [Test]\n    public static void Evict_LruOrder()\n    {\n        var cache = new LfuCache<int, string>(capacity: 2);\n        cache.Put(1, \"one\");\n        cache.Put(2, \"two\");\n\n        cache.Put(1, \"ONE\");\n        cache.Put(2, \"TWO\");\n\n        // Add to the full cache, 1 will be removed\n        cache.Put(3, \"three\");\n\n        cache.Get(1).Should().BeNull();\n        cache.Get(2).Should().Be(\"TWO\");\n        cache.Get(3).Should().Be(\"three\");\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Cache/LruCacheTests.cs",
    "content": "using DataStructures.Cache;\n\nnamespace DataStructures.Tests.Cache;\n\npublic static class LruCacheTests\n{\n    [Test]\n    public static void TestPutGet()\n    {\n        var cache = new LruCache<int, string>();\n        cache.Put(1, \"one\");\n\n        cache.Contains(1).Should().BeTrue();\n        cache.Get(1).Should().Be(\"one\");\n    }\n\n    [Test]\n    public static void TestCacheMiss()\n    {\n        var cache = new LruCache<int, string>();\n        cache.Put(1, \"one\");\n\n        cache.Contains(5).Should().BeFalse();\n        cache.Get(5).Should().BeNull();\n    }\n\n    [Test]\n    public static void TestCacheUpdate()\n    {\n        var cache = new LruCache<int, string>();\n        cache.Put(1, \"one\");\n        cache.Put(1, \"ONE\");\n\n        cache.Get(1).Should().Be(\"ONE\");\n    }\n\n    [Test]\n    public static void RemoveOldestItem_ItemWasNotUsed()\n    {\n        var cache = new LruCache<int, string>(capacity: 2);\n        cache.Put(1, \"one\");\n        cache.Put(2, \"two\");\n\n        // Add to the full cache, 1 will be removed\n        cache.Put(3, \"three\");\n\n        cache.Get(1).Should().BeNull();\n        cache.Get(2).Should().Be(\"two\");\n        cache.Get(3).Should().Be(\"three\");\n    }\n\n    [Test]\n    public static void RemoveOldestItem_ItemWasRecentlyUsed()\n    {\n        var cache = new LruCache<int, string>(capacity: 2);\n        cache.Put(1, \"one\");\n        cache.Put(2, \"two\");\n        cache.Get(1);\n\n        // Add to the full cache, 1 was used, 2 should be removed\n        cache.Put(3, \"three\");\n\n        cache.Get(1).Should().Be(\"one\");\n        cache.Get(2).Should().BeNull();\n        cache.Get(3).Should().Be(\"three\");\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/DataStructures.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <IsPackable>false</IsPackable>\n    <CodeAnalysisRuleSet>..\\stylecop.ruleset</CodeAnalysisRuleSet>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <AdditionalFiles Include=\"..\\stylecop.json\" />\n    <ProjectReference Include=\"..\\DataStructures\\DataStructures.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.0\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"FluentAssertions\" Version=\"6.12.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.8.0\" />\n    <PackageReference Include=\"nunit\" Version=\"4.0.1\" />\n    <PackageReference Include=\"NUnit3TestAdapter\" Version=\"4.5.0\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "DataStructures.Tests/Deque/DequeTests.cs",
    "content": "using DataStructures.Deque;\nusing NUnit.Framework;\nusing System;\nusing System.Linq;\n\nnamespace DataStructures.Tests.Deque;\n\n/// <summary>\n///     Comprehensive test suite for the Deque (Double-Ended Queue) data structure.\n///     Tests cover:\n///     - Constructor validation and initialization\n///     - Basic operations (AddFront, AddRear, RemoveFront, RemoveRear)\n///     - Peek operations (non-destructive reads)\n///     - Edge cases (empty deque, single element, capacity overflow)\n///     - Type flexibility (int, string, tuples)\n///     - Circular array behavior and automatic resizing\n///     - Mixed operations maintaining correct order\n/// </summary>\npublic static class DequeTests\n{\n    [Test]\n    public static void Constructor_WithDefaultCapacity_CreatesEmptyDeque()\n    {\n        // Arrange & Act: Create deque with default capacity (16)\n        var deque = new Deque<int>();\n\n        // Assert: Should be empty initially\n        Assert.That(deque.Count, Is.EqualTo(0));\n        Assert.That(deque.IsEmpty, Is.True);\n    }\n\n    [Test]\n    public static void Constructor_WithSpecifiedCapacity_CreatesEmptyDeque()\n    {\n        // Arrange & Act\n        var deque = new Deque<int>(10);\n\n        // Assert\n        Assert.That(deque.Count, Is.EqualTo(0));\n        Assert.That(deque.IsEmpty, Is.True);\n    }\n\n    [Test]\n    public static void Constructor_WithInvalidCapacity_ThrowsArgumentException()\n    {\n        // Arrange, Act & Assert: Capacity must be at least 1\n        // Zero capacity should throw\n        Assert.Throws<ArgumentException>(() => new Deque<int>(0));\n        // Negative capacity should throw\n        Assert.Throws<ArgumentException>(() => new Deque<int>(-1));\n    }\n\n    [Test]\n    public static void AddFront_AddsElementToFront()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n\n        // Act: Add elements to front (each becomes new front)\n        deque.AddFront(1);  // Deque: [1]\n        deque.AddFront(2);  // Deque: [2, 1]\n        deque.AddFront(3);  // Deque: [3, 2, 1]\n\n        // Assert: Most recently added element should be at front\n        Assert.That(deque.Count, Is.EqualTo(3));\n        Assert.That(deque.PeekFront(), Is.EqualTo(3));\n    }\n\n    [Test]\n    public static void AddRear_AddsElementToRear()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n\n        // Act\n        deque.AddRear(1);\n        deque.AddRear(2);\n        deque.AddRear(3);\n\n        // Assert\n        Assert.That(deque.Count, Is.EqualTo(3));\n        Assert.That(deque.PeekRear(), Is.EqualTo(3));\n    }\n\n    [Test]\n    public static void RemoveFront_RemovesAndReturnsElementFromFront()\n    {\n        // Arrange: Build deque [1, 2, 3]\n        var deque = new Deque<int>();\n        deque.AddRear(1);\n        deque.AddRear(2);\n        deque.AddRear(3);\n\n        // Act: Remove front element\n        int result = deque.RemoveFront();\n\n        // Assert: Should return 1 and deque becomes [2, 3]\n        Assert.That(result, Is.EqualTo(1));\n        Assert.That(deque.Count, Is.EqualTo(2));\n        Assert.That(deque.PeekFront(), Is.EqualTo(2));\n    }\n\n    [Test]\n    public static void RemoveRear_RemovesAndReturnsElementFromRear()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n        deque.AddRear(1);\n        deque.AddRear(2);\n        deque.AddRear(3);\n\n        // Act\n        int result = deque.RemoveRear();\n\n        // Assert\n        Assert.That(result, Is.EqualTo(3));\n        Assert.That(deque.Count, Is.EqualTo(2));\n        Assert.That(deque.PeekRear(), Is.EqualTo(2));\n    }\n\n    [Test]\n    public static void RemoveFront_OnEmptyDeque_ThrowsInvalidOperationException()\n    {\n        // Arrange: Create empty deque\n        var deque = new Deque<int>();\n\n        // Act & Assert: Cannot remove from empty deque\n        Assert.Throws<InvalidOperationException>(() => deque.RemoveFront());\n    }\n\n    [Test]\n    public static void RemoveRear_OnEmptyDeque_ThrowsInvalidOperationException()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n\n        // Act & Assert\n        Assert.Throws<InvalidOperationException>(() => deque.RemoveRear());\n    }\n\n    [Test]\n    public static void PeekFront_ReturnsElementWithoutRemoving()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n        deque.AddRear(1);\n        deque.AddRear(2);\n\n        // Act\n        int result = deque.PeekFront();\n\n        // Assert\n        Assert.That(result, Is.EqualTo(1));\n        Assert.That(deque.Count, Is.EqualTo(2));\n    }\n\n    [Test]\n    public static void PeekRear_ReturnsElementWithoutRemoving()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n        deque.AddRear(1);\n        deque.AddRear(2);\n\n        // Act\n        int result = deque.PeekRear();\n\n        // Assert\n        Assert.That(result, Is.EqualTo(2));\n        Assert.That(deque.Count, Is.EqualTo(2));\n    }\n\n    [Test]\n    public static void PeekFront_OnEmptyDeque_ThrowsInvalidOperationException()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n\n        // Act & Assert\n        Assert.Throws<InvalidOperationException>(() => deque.PeekFront());\n    }\n\n    [Test]\n    public static void PeekRear_OnEmptyDeque_ThrowsInvalidOperationException()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n\n        // Act & Assert\n        Assert.Throws<InvalidOperationException>(() => deque.PeekRear());\n    }\n\n    [Test]\n    public static void Clear_RemovesAllElements()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n        deque.AddRear(1);\n        deque.AddRear(2);\n        deque.AddRear(3);\n\n        // Act\n        deque.Clear();\n\n        // Assert\n        Assert.That(deque.Count, Is.EqualTo(0));\n        Assert.That(deque.IsEmpty, Is.True);\n    }\n\n    [Test]\n    public static void ToArray_ReturnsElementsInCorrectOrder()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n        deque.AddRear(1);\n        deque.AddRear(2);\n        deque.AddRear(3);\n\n        // Act\n        int[] result = deque.ToArray();\n\n        // Assert\n        Assert.That(result, Is.EqualTo(new[] { 1, 2, 3 }));\n    }\n\n    [Test]\n    public static void ToArray_WithMixedOperations_ReturnsCorrectOrder()\n    {\n        // Arrange: Build deque using both front and rear operations\n        var deque = new Deque<int>();\n        deque.AddFront(2);  // Deque: [2]\n        deque.AddFront(1);  // Deque: [1, 2]\n        deque.AddRear(3);   // Deque: [1, 2, 3]\n        deque.AddRear(4);   // Deque: [1, 2, 3, 4]\n\n        // Act\n        int[] result = deque.ToArray();\n\n        // Assert: Array should maintain front-to-rear order\n        Assert.That(result, Is.EqualTo(new[] { 1, 2, 3, 4 }));\n    }\n\n    [Test]\n    public static void Contains_WithExistingElement_ReturnsTrue()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n        deque.AddRear(1);\n        deque.AddRear(2);\n        deque.AddRear(3);\n\n        // Act\n        bool result = deque.Contains(2);\n\n        // Assert\n        Assert.That(result, Is.True);\n    }\n\n    [Test]\n    public static void Contains_WithNonExistingElement_ReturnsFalse()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n        deque.AddRear(1);\n        deque.AddRear(2);\n        deque.AddRear(3);\n\n        // Act\n        bool result = deque.Contains(5);\n\n        // Assert\n        Assert.That(result, Is.False);\n    }\n\n    [Test]\n    public static void Deque_WithStringType_WorksCorrectly()\n    {\n        // Arrange\n        var deque = new Deque<string>();\n\n        // Act\n        deque.AddRear(\"Hello\");\n        deque.AddFront(\"World\");\n        deque.AddRear(\"!\");\n\n        // Assert\n        Assert.That(deque.Count, Is.EqualTo(3));\n        Assert.That(deque.PeekFront(), Is.EqualTo(\"World\"));\n        Assert.That(deque.PeekRear(), Is.EqualTo(\"!\"));\n    }\n\n    [Test]\n    public static void Deque_AutomaticallyResizes_WhenCapacityExceeded()\n    {\n        // Arrange: Create deque with small capacity of 2\n        var deque = new Deque<int>(2);\n\n        // Act: Add more elements than initial capacity\n        deque.AddRear(1);  // Capacity: 2, Count: 1\n        deque.AddRear(2);  // Capacity: 2, Count: 2 (full)\n        deque.AddRear(3);  // Should trigger resize to capacity 4, Count: 3\n        deque.AddRear(4);  // Capacity: 4, Count: 4\n\n        // Assert: All elements should be present in correct order\n        Assert.That(deque.Count, Is.EqualTo(4));\n        Assert.That(deque.ToArray(), Is.EqualTo(new[] { 1, 2, 3, 4 }));\n    }\n\n    [Test]\n    public static void Deque_MixedOperations_MaintainsCorrectOrder()\n    {\n        // Arrange\n        var deque = new Deque<int>();\n\n        // Act: Perform complex sequence of operations\n        deque.AddRear(3);      // Deque: [3]\n        deque.AddFront(2);     // Deque: [2, 3]\n        deque.AddFront(1);     // Deque: [1, 2, 3]\n        deque.AddRear(4);      // Deque: [1, 2, 3, 4]\n        deque.RemoveFront();   // Deque: [2, 3, 4] (removed 1)\n        deque.RemoveRear();    // Deque: [2, 3] (removed 4)\n        deque.AddRear(5);      // Deque: [2, 3, 5]\n\n        // Assert: Final order should be correct after all operations\n        Assert.That(deque.ToArray(), Is.EqualTo(new[] { 2, 3, 5 }));\n    }\n\n    [Test]\n    public static void Deque_WithComplexType_WorksCorrectly()\n    {\n        // Arrange\n        var deque = new Deque<(int, string)>();\n\n        // Act\n        deque.AddRear((1, \"One\"));\n        deque.AddRear((2, \"Two\"));\n        deque.AddFront((0, \"Zero\"));\n\n        // Assert\n        Assert.That(deque.Count, Is.EqualTo(3));\n        Assert.That(deque.PeekFront(), Is.EqualTo((0, \"Zero\")));\n        Assert.That(deque.PeekRear(), Is.EqualTo((2, \"Two\")));\n    }\n\n    [Test]\n    public static void Deque_AfterMultipleResizes_MaintainsIntegrity()\n    {\n        // Arrange: Start with very small capacity\n        var deque = new Deque<int>(2);\n\n        // Act: Add many elements to trigger multiple resizes\n        // Capacity progression: 2 -> 4 -> 8 -> 16 -> 32 -> 64 -> 128\n        for (int i = 0; i < 100; i++)\n        {\n            deque.AddRear(i);\n        }\n\n        // Assert: All elements should be intact after multiple resizes\n        Assert.That(deque.Count, Is.EqualTo(100));\n        Assert.That(deque.PeekFront(), Is.EqualTo(0));\n        Assert.That(deque.PeekRear(), Is.EqualTo(99));\n        Assert.That(deque.ToArray(), Is.EqualTo(Enumerable.Range(0, 100).ToArray()));\n    }\n\n    [Test]\n    public static void Deque_CircularBehavior_WorksCorrectly()\n    {\n        // Arrange: Create deque with capacity 4\n        var deque = new Deque<int>(4);\n\n        // Act: Test circular wrap-around behavior\n        deque.AddRear(1);      // Internal: [1, _, _, _], front=0, rear=1\n        deque.AddRear(2);      // Internal: [1, 2, _, _], front=0, rear=2\n        deque.RemoveFront();   // Internal: [_, 2, _, _], front=1, rear=2\n        deque.RemoveFront();   // Internal: [_, _, _, _], front=2, rear=2\n        deque.AddRear(3);      // Internal: [_, _, 3, _], front=2, rear=3\n        deque.AddRear(4);      // Internal: [_, _, 3, 4], front=2, rear=0 (wrapped)\n        deque.AddRear(5);      // Internal: [5, _, 3, 4], front=2, rear=1 (wrapped)\n\n        // Assert: Elements should be in correct logical order despite circular storage\n        Assert.That(deque.ToArray(), Is.EqualTo(new[] { 3, 4, 5 }));\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/DisjointSet/DisjointSetTests.cs",
    "content": "using DataStructures.DisjointSet;\n\nnamespace DataStructures.Tests.DisjointSet;\n\n[TestFixture]\npublic class DisjointSetTests\n{\n    [Test]\n    public static void MakeSetDataInitializationTest()\n    {\n        DisjointSet<int> ds = new();\n        var one = ds.MakeSet(1);\n        var two = ds.MakeSet(2);\n        one.Data.Should().Be(1);\n        two.Data.Should().Be(2);\n    }\n    [Test]\n    public static void UnionTest()\n    {\n        DisjointSet<int> ds = new();\n        var one = ds.MakeSet(1);\n        var two = ds.MakeSet(2);\n        var three = ds.MakeSet(3);\n        ds.UnionSet(one, two);\n        ds.FindSet(one).Should().Be(ds.FindSet(two));\n        ds.UnionSet(one, three);\n        ds.FindSet(two).Should().Be(ds.FindSet(three));\n        (one.Rank + two.Rank + three.Rank).Should().Be(1);\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Fenwick/BinaryIndexedTreeTests.cs",
    "content": "using DataStructures.Fenwick;\n\nnamespace DataStructures.Tests.Fenwick;\n\n[TestFixture]\ninternal class BinaryIndexedTreeTests\n{\n    [Test]\n    public void GetSum_CreateBITAndRequestSum_ReturnCorrect()\n    {\n        int[] array = [2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9];\n        var tree = new BinaryIndexedTree(array);\n        var expectedSum = 12;\n\n        var resultedSum = tree.GetSum(5);\n\n        resultedSum.Should().Be(expectedSum);\n    }\n\n    [Test]\n    public void UpdateTree_UpdateTreeAndRequestSum_GetSum()\n    {\n        int[] array = [2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9];\n        var tree = new BinaryIndexedTree(array);\n        var expectedSum = 18;\n\n        array[3] += 6;\n        tree.UpdateTree(3, 6);\n\n        var resultedSum = tree.GetSum(5);\n        resultedSum.Should().Be(expectedSum);\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/GlobalUsings.cs",
    "content": "// -----------------------------------------------------------------------------\n// Global using directives for the C-Sharp solution.\n// These namespaces are imported globally so they don’t need to be repeatedly declared\n// in individual files, improving readability and reducing boilerplate.\n//\n// Guidelines:\n// - Keep only the most commonly used namespaces here.\n// - Add project-specific namespaces (e.g., Utilities.Extensions) only if they are\n//   required across the majority of files in the project.\n// - Avoid placing rarely used namespaces here to maintain clarity.\n// -----------------------------------------------------------------------------\n\nglobal using System;                        // Core base classes and fundamental types\nglobal using System.Collections.Generic;    // Generic collection types (List, Dictionary, etc.)\nglobal using System.Linq;                   // LINQ query operators for collections\nglobal using System.Text;                   // Text encoding, StringBuilder, etc.\nglobal using NUnit.Framework;               // Testing framework providing attributes and assertions for test cases\nglobal using FluentAssertions;              // Assertion library for more readable and expressive unit tests\n"
  },
  {
    "path": "DataStructures.Tests/Graph/DirectedWeightedGraphTests.cs",
    "content": "using DataStructures.Graph;\n\nnamespace DataStructures.Tests.Graph;\n\n[TestFixture]\npublic class DirectedWeightedGraphTests\n{\n    [TestCase(-1)]\n    [TestCase(-2)]\n    [TestCase(-3)]\n    public void GraphInitializationTest_ShouldThrowOverflow(int capacity)\n    {\n        Func<DirectedWeightedGraph<char>> createGraph = () => new DirectedWeightedGraph<char>(capacity);\n\n        createGraph.Should().Throw<InvalidOperationException>()\n            .WithMessage(\"Graph capacity should always be a non-negative integer.\");\n    }\n\n    [TestCase(1)]\n    [TestCase(10)]\n    [TestCase(20)]\n    [TestCase(30)]\n    public void GraphInitializationTest_Success(int capacity)\n    {\n        Func<DirectedWeightedGraph<char>> createGraph = () => new DirectedWeightedGraph<char>(capacity);\n\n        createGraph.Should().NotThrow();\n    }\n\n    [Test]\n    public void GraphAddVertexTest_Success()\n    {\n        var graph = new DirectedWeightedGraph<char>(10);\n\n        graph.AddVertex('A');\n        graph.AddVertex('B');\n        graph.AddVertex('C');\n\n        graph.Count.Should().Be(3);\n    }\n\n    [Test]\n    public void GraphAddVertexTest_ShouldThrowOverflow()\n    {\n        var graph = new DirectedWeightedGraph<char>(10);\n        for (var i = 0; i < 10; i++)\n        {\n            graph.AddVertex('A');\n        }\n\n        Action addOverflow = () => graph.AddVertex('A');\n\n        graph.Count.Should().Be(10);\n        graph.Vertices.Should().OnlyContain(x => x != null && x.Data == 'A');\n        addOverflow.Should().Throw<InvalidOperationException>()\n            .WithMessage(\"Graph overflow.\");\n    }\n\n    [Test]\n    public void GraphRemoveVertexTest_Success()\n    {\n        var graph = new DirectedWeightedGraph<char>(10);\n        var vertexA = graph.AddVertex('A');\n        var vertexB = graph.AddVertex('B');\n        var vertexC = graph.AddVertex('C');\n        graph.AddEdge(vertexB, vertexA, 5);\n        graph.AddEdge(vertexC, vertexA, 5);\n        var neighborsB = graph.GetNeighbors(vertexB).ToList();\n        var neighborsC = graph.GetNeighbors(vertexC).ToList();\n\n        graph.RemoveVertex(vertexA);\n\n        neighborsB.Should().HaveCount(1);\n        neighborsB[0].Should().Be(vertexA);\n        neighborsC.Should().HaveCount(1);\n        neighborsC[0].Should().Be(vertexA);\n        graph.GetNeighbors(vertexB).Should().HaveCount(0);\n        graph.GetNeighbors(vertexC).Should().HaveCount(0);\n    }\n\n    [Test]\n    public void GraphRemoveAndAddVertexTest_Success()\n    {\n        double weight_A_B = 1;\n        double weight_A_C = 2;\n        double weight_A_D = 3;\n        double weight_B_A = 4;\n        double weight_B_C = 5;\n        double weight_C_A = 6;\n        double weight_C_B = 7;\n        double weight_C_D = 8;\n        double weight_D_A = 9;\n        double weight_D_C = 10;\n\n        var graph = new DirectedWeightedGraph<char>(10);\n        var vertexA = graph.AddVertex('A');\n        var vertexB = graph.AddVertex('B');\n        var vertexC = graph.AddVertex('C');\n        graph.AddEdge(vertexA, vertexB, weight_A_B);\n        graph.AddEdge(vertexA, vertexC, weight_A_C);\n        graph.AddEdge(vertexB, vertexA, weight_B_A);\n        graph.AddEdge(vertexB, vertexC, weight_B_C);\n        graph.AddEdge(vertexC, vertexA, weight_C_A);\n        graph.AddEdge(vertexC, vertexB, weight_C_B);\n\n        var vertexA_Index_BeforeUpdate = vertexA.Index;\n        vertexA_Index_BeforeUpdate.Should().Be(0);\n        var neighborsA_BeforeUpdate = graph.GetNeighbors(vertexA).ToList();\n        neighborsA_BeforeUpdate.Should().HaveCount(2);\n        neighborsA_BeforeUpdate[0].Should().Be(vertexB);\n        neighborsA_BeforeUpdate[1].Should().Be(vertexC);\n\n        var vertexB_Index_BeforeUpdate = vertexB.Index;\n        vertexB_Index_BeforeUpdate.Should().Be(1);\n        var neighborsB_BeforeUpdate = graph.GetNeighbors(vertexB).ToList();\n        neighborsB_BeforeUpdate.Should().HaveCount(2);\n        neighborsB_BeforeUpdate[0].Should().Be(vertexA);\n        neighborsB_BeforeUpdate[1].Should().Be(vertexC);\n\n        var vertexC_Index_BeforeUpdate = vertexC.Index;\n        vertexC_Index_BeforeUpdate.Should().Be(2);\n        var neighborsC_BeforeUpdate = graph.GetNeighbors(vertexC).ToList();\n        neighborsC_BeforeUpdate.Should().HaveCount(2);\n        neighborsC_BeforeUpdate[0].Should().Be(vertexA);\n        neighborsC_BeforeUpdate[1].Should().Be(vertexB);\n\n        var weight_A_B_BeforeUpdate = graph.AdjacentDistance(vertexA, vertexB);\n        var weight_A_C_BeforeUpdate = graph.AdjacentDistance(vertexA, vertexC);\n        var weight_B_A_BeforeUpdate = graph.AdjacentDistance(vertexB, vertexA);\n        var weight_B_C_BeforeUpdate = graph.AdjacentDistance(vertexB, vertexC);\n        var weight_C_A_BeforeUpdate = graph.AdjacentDistance(vertexC, vertexA);\n        var weight_C_B_BeforeUpdate = graph.AdjacentDistance(vertexC, vertexB);\n        weight_A_B_BeforeUpdate.Should().Be(weight_A_B);\n        weight_A_C_BeforeUpdate.Should().Be(weight_A_C);\n        weight_B_A_BeforeUpdate.Should().Be(weight_B_A);\n        weight_B_C_BeforeUpdate.Should().Be(weight_B_C);\n        weight_C_A_BeforeUpdate.Should().Be(weight_C_A);\n        weight_C_B_BeforeUpdate.Should().Be(weight_C_B);\n\n        graph.RemoveVertex(vertexB);\n        var vertexD = graph.AddVertex('D');\n        graph.AddEdge(vertexA, vertexD, weight_A_D);\n        graph.AddEdge(vertexC, vertexD, weight_C_D);\n        graph.AddEdge(vertexD, vertexA, weight_D_A);\n        graph.AddEdge(vertexD, vertexC, weight_D_C);\n\n        var vertexA_Index_AfterUpdate = vertexA.Index;\n        vertexA_Index_AfterUpdate.Should().Be(0);\n        var neighborsA_AfterUpdate = graph.GetNeighbors(vertexA).ToList();\n        neighborsA_AfterUpdate.Should().HaveCount(2);\n        neighborsA_AfterUpdate[0].Should().Be(vertexC);\n        neighborsA_AfterUpdate[1].Should().Be(vertexD);\n\n        var vertexC_Index_AfterUpdate = vertexC.Index;\n        vertexC_Index_AfterUpdate.Should().Be(1);\n        var neighborsC_AfterUpdate = graph.GetNeighbors(vertexC).ToList();\n        neighborsC_AfterUpdate.Should().HaveCount(2);\n        neighborsC_AfterUpdate[0].Should().Be(vertexA);\n        neighborsC_AfterUpdate[1].Should().Be(vertexD);\n\n        var vertexD_Index_AfterUpdate = vertexD.Index;\n        vertexD_Index_AfterUpdate.Should().Be(2);\n        var neighborsD_AfterUpdate = graph.GetNeighbors(vertexD).ToList();\n        neighborsD_AfterUpdate.Should().HaveCount(2);\n        neighborsD_AfterUpdate[0].Should().Be(vertexA);\n        neighborsD_AfterUpdate[1].Should().Be(vertexC);\n\n        var weight_A_C_AfterUpdate = graph.AdjacentDistance(vertexA, vertexC);\n        var weight_A_D_AfterUpdate = graph.AdjacentDistance(vertexA, vertexD);\n        var weight_C_A_AfterUpdate = graph.AdjacentDistance(vertexC, vertexA);\n        var weight_C_D_AfterUpdate = graph.AdjacentDistance(vertexC, vertexD);\n        var weight_D_A_AfterUpdate = graph.AdjacentDistance(vertexD, vertexA);\n        var weight_D_C_AfterUpdate = graph.AdjacentDistance(vertexD, vertexC);\n        weight_A_D_AfterUpdate.Should().Be(weight_A_D);\n        weight_A_C_AfterUpdate.Should().Be(weight_A_C);\n        weight_D_A_AfterUpdate.Should().Be(weight_D_A);\n        weight_D_C_AfterUpdate.Should().Be(weight_D_C);\n        weight_C_A_AfterUpdate.Should().Be(weight_C_A);\n        weight_C_D_AfterUpdate.Should().Be(weight_C_D);\n    }\n\n    [Test]\n    public void GraphRemoveVertexTest_ShouldThrowVertexNotInGraph()\n    {\n        var graph = new DirectedWeightedGraph<char>(10);\n        var vertexA = new Vertex<char>('A', 0);\n\n        Action removeVertex = () => graph.RemoveVertex(vertexA);\n\n        removeVertex.Should().Throw<InvalidOperationException>()\n            .WithMessage($\"Vertex does not belong to graph: {vertexA}.\");\n    }\n\n    [Test]\n    public void GraphAddEdgeTest_Success()\n    {\n        var graph = new DirectedWeightedGraph<char>(10);\n        var vertexA = graph.AddVertex('A');\n        var vertexB = graph.AddVertex('B');\n        var vertexC = graph.AddVertex('C');\n\n        graph.AddEdge(vertexA, vertexB, 5);\n\n        graph.AreAdjacent(vertexA, vertexB).Should().BeTrue();\n        graph.AreAdjacent(vertexA, vertexC).Should().BeFalse();\n    }\n\n    [Test]\n    public void GraphAddEdgeTest_ShouldThrowZeroWeight()\n    {\n        var graph = new DirectedWeightedGraph<char>(10);\n        var vertexA = graph.AddVertex('A');\n        var vertexB = graph.AddVertex('B');\n\n        Action addZeroEdge = () => graph.AddEdge(vertexA, vertexB, 0);\n\n        addZeroEdge.Should().Throw<InvalidOperationException>()\n            .WithMessage(\"Edge weight cannot be zero.\");\n    }\n\n    [Test]\n    public void GraphAddEdgeTest_ShouldThrowVertexNotInGraph()\n    {\n        var graph = new DirectedWeightedGraph<char>(10);\n        var vertexA = graph.AddVertex('A');\n        var vertexB = new Vertex<char>('B', 1);\n\n        Action addZeroEdge = () => graph.AddEdge(vertexA, vertexB, 0);\n\n        addZeroEdge.Should().Throw<InvalidOperationException>()\n            .WithMessage($\"Vertex does not belong to graph: {vertexB}.\");\n    }\n\n    [Test]\n    public void GraphAddEdgeTest_ShouldThrowEdgeExists()\n    {\n        var graph = new DirectedWeightedGraph<char>(10);\n        var vertexA = graph.AddVertex('A');\n        var vertexB = graph.AddVertex('B');\n        const int currentEdgeWeight = 5;\n        graph.AddEdge(vertexA, vertexB, currentEdgeWeight);\n\n        Action addZeroEdge = () => graph.AddEdge(vertexA, vertexB, 10);\n\n        addZeroEdge.Should().Throw<InvalidOperationException>()\n            .WithMessage($\"Vertex already exists: {currentEdgeWeight}\");\n    }\n\n    [Test]\n    public void GraphRemoveEdgeTest_Success()\n    {\n        var graph = new DirectedWeightedGraph<char>(10);\n        var vertexA = graph.AddVertex('A');\n        var vertexB = graph.AddVertex('B');\n        graph.AddEdge(vertexA, vertexB, 5);\n\n        graph.RemoveEdge(vertexA, vertexB);\n\n        graph.AreAdjacent(vertexA, vertexB).Should().BeFalse();\n    }\n\n    [Test]\n    public void GraphRemoveEdgeTest_ShouldThrowVertexNotInGraph()\n    {\n        var graph = new DirectedWeightedGraph<char>(10);\n        var vertexA = graph.AddVertex('A');\n        var vertexB = new Vertex<char>('B', 1);\n\n        Action removeEdge = () => graph.RemoveEdge(vertexA, vertexB);\n\n        removeEdge.Should().Throw<InvalidOperationException>()\n            .WithMessage($\"Vertex does not belong to graph: {vertexB}.\");\n    }\n\n    [Test]\n    public void GraphGetNeighborsTest_Success()\n    {\n        var graph = new DirectedWeightedGraph<char>(10);\n        var vertexA = graph.AddVertex('A');\n        var vertexB = graph.AddVertex('B');\n        var vertexC = graph.AddVertex('C');\n        var vertexD = graph.AddVertex('D');\n        graph.AddEdge(vertexA, vertexB, 5);\n        graph.AddEdge(vertexA, vertexC, 5);\n        graph.AddEdge(vertexA, vertexD, 5);\n\n        var neighborsA = graph.GetNeighbors(vertexA).ToArray();\n\n        neighborsA.Should().HaveCount(3);\n        neighborsA[0].Should().Be(vertexB);\n        neighborsA[1].Should().Be(vertexC);\n        neighborsA[2].Should().Be(vertexD);\n    }\n\n    [Test]\n    public void GraphGetNeighborsTest_ShouldThrowVertexNotInGraph()\n    {\n        var graph = new DirectedWeightedGraph<char>(10);\n        var vertexA = new Vertex<char>('A', 0);\n\n        Func<List<Vertex<char>?>> getNeighbors = () =>\n        {\n            var enumerable = graph.GetNeighbors(vertexA);\n            return enumerable.ToList();\n        };\n\n        getNeighbors.Should().Throw<InvalidOperationException>()\n            .WithMessage($\"Vertex does not belong to graph: {vertexA}.\");\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Hashing/HashTableTests.cs",
    "content": "using DataStructures.Hashing;\n\nnamespace DataStructures.Tests.Hashing;\n\n[TestFixture]\npublic class HashTableTests\n{\n    [Test]\n    public void Add_ThrowsException_WhenKeyIsNull()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        Assert.Throws<ArgumentNullException>(() => hashTable.Add(null, 1));\n    }\n\n    [Test]\n    public void Add_ThrowsException_WhenKeyAlreadyExists()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        hashTable.Add(\"a\", 1);\n\n        Assert.Throws<ArgumentException>(() => hashTable.Add(\"a\", 2));\n    }\n\n    [Test]\n    public void Add_IncreasesCount_WhenKeyDoesNotExist()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        hashTable.Add(\"a\", 1);\n\n        Assert.That(hashTable.Count, Is.EqualTo(1));\n    }\n\n    [Test]\n    public void Add_DoesNotIncreaseCount_WhenKeyAlreadyExists()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        hashTable.Add(\"a\", 1);\n        try\n        {\n            hashTable.Add(\"a\", 2);\n        }\n        catch (ArgumentException)\n        {\n            Console.WriteLine(\"ArgumentException\");\n        }\n        Assert.That(hashTable.Count, Is.EqualTo(1));\n    }\n\n    [Test]\n    public void Add_ThrowsException_WhenValueIsNull()\n    {\n        var hashTable = new HashTable<string, string>();\n\n        Assert.Throws<ArgumentNullException>(() => hashTable.Add(\"a\", null));\n    }\n\n    [Test]\n    public void Add_IncreasesCount_WhenValueDoesNotExist()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        hashTable.Add(\"b\", 1);\n\n        Assert.That(hashTable.Count, Is.EqualTo(1));\n    }\n\n    [Test]\n    public void Add_DoesNotIncreaseCount_WhenValueAlreadyExists()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        hashTable.Add(\"a\", 1);\n\n        try\n        {\n            hashTable.Add(\"b\", 1);\n        }\n        catch (ArgumentException)\n        {\n            Console.WriteLine(\"ArgumentException\");\n        }\n\n        Assert.That(hashTable.Count, Is.EqualTo(2));\n    }\n\n    [Test]\n    public void Add_IncreasesCount_WhenValueIsNull()\n    {\n        var hashTable = new HashTable<string, string>();\n\n        try\n        {\n            hashTable.Add(\"a\", null);\n        }\n        catch (ArgumentNullException)\n        {\n            Console.WriteLine(\"ArgumentNullException\");\n        }\n        Assert.That(hashTable.Count, Is.EqualTo(0));\n    }\n\n    [Test]\n    public void Add_IncreasesCount_WhenValueAlreadyExists()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        hashTable.Add(\"a\", 1);\n        hashTable.Add(\"b\", 1);\n        Assert.That(hashTable.Count, Is.EqualTo(2));\n    }\n\n    [Test]\n    public void Add_ThrowsException_OnCollision()\n    {\n        // Arrange\n        var hashTable = new HashTable<Collider, int>();\n        hashTable.Add(new Collider(1), 1);\n\n\n        // Act & Assert\n        Assert.Throws<ArgumentException>(() => hashTable.Add(new Collider(1), 2));\n    }\n\n    [Test]\n    public void Remove_ThrowsException_WhenKeyIsNull()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        Assert.Throws<ArgumentNullException>(() => hashTable.Remove(null));\n    }\n\n    [Test]\n    public void Remove_ReturnsFalse_WhenKeyDoesNotExist()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        Assert.That(hashTable.Remove(\"a\"), Is.False);\n    }\n\n    [Test]\n    public void Remove_ReturnsTrue_WhenKeyExists()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        hashTable.Add(\"a\", 1);\n\n        Assert.That(hashTable.Remove(\"a\"), Is.True);\n    }\n\n    [Test]\n    public void Remove_DecreasesCount_WhenKeyExists()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        hashTable.Add(\"a\", 1);\n        hashTable.Remove(\"a\");\n\n        Assert.That(hashTable.Count, Is.EqualTo(0));\n    }\n\n    [Test]\n    public void Remove_DoesNotDecreaseCount_WhenKeyDoesNotExist()\n    {\n        var hashTable = new HashTable<string, int>();\n        hashTable.Remove(\"a\");\n\n        Assert.That(hashTable.Count, Is.EqualTo(0));\n    }\n\n    [Test]\n    public void Remove_TriggersResizeDown()\n    {\n        var hashTable = new HashTable<int, string>(4);\n        for (var i = 1; i <= 50; i++)\n        {\n            hashTable.Add(i, $\"Value{i}\");\n        }\n\n        for (var i = 1; i <= 40; i++)\n        {\n            hashTable.Remove(i);\n        }\n\n        Assert.That(hashTable.Capacity, Is.EqualTo(40));\n    }\n\n    [Test]\n    public void Remove_TriggersResizeDown_MinimumOfDefaultCapacity()\n    {\n        var hashTable = new HashTable<int, string>(4);\n        for (var i = 1; i <= 50; i++)\n        {\n            hashTable.Add(i, $\"Value{i}\");\n        }\n\n        for (var i = 1; i <= 48; i++)\n        {\n            hashTable.Remove(i);\n        }\n\n        Assert.That(hashTable.Capacity, Is.EqualTo(16));\n    }\n\n    [Test]\n    public void ContainsValue_ReturnsFalse_WhenValueDoesNotExist()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        Assert.That(hashTable.ContainsValue(1), Is.False);\n    }\n\n    [Test]\n    public void ContainsValue_ReturnsTrue_WhenValueExists()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        hashTable.Add(\"a\", 1);\n\n        Assert.That(hashTable.ContainsValue(1), Is.True);\n    }\n\n    [Test]\n    public void ContainsValue_ReturnsFalse_WhenValueIsNull()\n    {\n        var hashTable = new HashTable<string, string>();\n\n        Assert.Throws<ArgumentNullException>(() => hashTable.ContainsValue(null));\n    }\n\n    [Test]\n    public void ContainsKey_ReturnsFalse_WhenKeyDoesNotExist()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        Assert.That(hashTable.ContainsKey(\"a\"), Is.False);\n    }\n\n    [Test]\n    public void ContainsKey_ReturnsTrue_WhenKeyExists()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        hashTable.Add(\"a\", 1);\n\n        Assert.That(hashTable.ContainsKey(\"a\"), Is.True);\n    }\n\n    [Test]\n    public void ContainsKey_ReturnsFalse_WhenKeyIsNull()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        Assert.Throws<ArgumentNullException>(() => hashTable.ContainsKey(null));\n    }\n\n    [Test]\n    public void Clear_SetsCountToZero()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        hashTable.Add(\"a\", 1);\n        hashTable.Clear();\n\n        Assert.That(hashTable.Count, Is.EqualTo(0));\n    }\n\n    [Test]\n    public void Clear_RemovesAllElements()\n    {\n        var hashTable = new HashTable<string, int>();\n\n        hashTable.Add(\"a\", 1);\n        hashTable.Clear();\n\n        Assert.That(hashTable.ContainsKey(\"a\"), Is.False);\n    }\n\n    [Test]\n    public void Clear_ResetsTable()\n    {\n        var hashTable = new HashTable<int, string>();\n        hashTable.Add(1, \"A\");\n        hashTable.Clear();\n        hashTable.Add(2, \"B\");\n        Assert.That(hashTable.Count, Is.EqualTo(1));\n        Assert.That(hashTable[2], Is.EqualTo(\"B\"));\n    }\n\n    [Test]\n    public void Resize_IncreasesCapacity()\n    {\n        var hashTable = new HashTable<string, int>(4);\n\n        hashTable.Add(\"one\", 1);\n        hashTable.Add(\"two\", 2);\n        hashTable.Add(\"three\", 3);\n        hashTable.Add(\"four\", 4);\n        hashTable.Add(\"humour\", 5);\n\n        /// Next Prime number after 4 is 5\n        /// Capacity should be 5\n        /// After resizing, the capacity should be 10\n        Assert.That(hashTable.Capacity, Is.EqualTo(10));\n    }\n    [Test]\n    public void LoadFactor_ReturnsCorrectValue()\n    {\n        var hashTable = new HashTable<string, int>(4);\n\n        hashTable.Add(\"one\", 1);\n        hashTable.Add(\"two\", 2);\n        hashTable.Add(\"three\", 3);\n        hashTable.Add(\"four\", 4);\n        hashTable.Add(\"humour\", 5);\n        Assert.That(hashTable.LoadFactor, Is.EqualTo(0.75f));\n    }\n\n    [Test]\n    public void Keys_ReturnsCorrectKeys()\n    {\n        var hashTable = new HashTable<int, string>();\n        hashTable.Add(1, \"one\");\n        hashTable.Add(2, \"two\");\n        hashTable.Add(3, \"three\");\n\n        var keys = new List<int> { 1, 2, 3 };\n\n        Assert.That(keys, Is.EquivalentTo(hashTable.Keys));\n    }\n\n    [Test]\n    public void Values_ReturnsCorrectValues()\n    {\n        var hashTable = new HashTable<int, string>();\n        hashTable.Add(1, \"one\");\n        hashTable.Add(2, \"two\");\n        hashTable.Add(3, \"three\");\n\n        var values = new List<string> { \"one\", \"two\", \"three\" };\n\n        Assert.That(values, Is.EquivalentTo(hashTable.Values));\n    }\n\n    [Test]\n    public void Constructor_ThrowsException_WhenCapacityIsZero()\n    {\n        Assert.Throws<ArgumentOutOfRangeException>(() => new HashTable<string, int>(0));\n    }\n\n    [Test]\n    public void Constructor_ThrowsException_WhenLoadFactorIsZero()\n    {\n        Assert.Throws<ArgumentOutOfRangeException>(() => new HashTable<string, int>(4, 0));\n    }\n\n    [Test]\n    public void Constructor_ThrowsException_WhenLoadFactorIsLessThanZero()\n    {\n        Assert.Throws<ArgumentOutOfRangeException>(() => new HashTable<string, int>(4, -1));\n    }\n\n    [Test]\n    public void Constructor_ThrowsException_WhenLoadFactorIsGreaterThanOne()\n    {\n        Assert.Throws<ArgumentOutOfRangeException>(() => new HashTable<string, int>(4, 2));\n    }\n\n    [Test]\n    public void Constructor_RoundsCapacityToPrime()\n    {\n        var hashTable = new HashTable<int, string>(17);\n        Assert.That(hashTable.Capacity, Is.EqualTo(19));\n    }\n\n    [Test]\n    public void GetIndex_ThrowsException_WhenKeyIsNull()\n    {\n        var hashTable = new HashTable<string, int>(4);\n        Assert.Throws<ArgumentNullException>(() => hashTable.GetIndex(null));\n    }\n\n    [Test]\n    public void FindEntry_ThrowsException_WhenKeyIsNull()\n    {\n        var hashTable = new HashTable<string, int>(4);\n        Assert.Throws<ArgumentNullException>(() => hashTable.FindEntry(null));\n    }\n\n    [Test]\n    public void This_Get_ThrowsException_WhenKeyIsNull()\n    {\n        var hashTable = new HashTable<string, int>(4);\n        Assert.Throws<ArgumentNullException>(() =>\n        {\n            var value = hashTable[null];\n            Console.WriteLine(value);\n        });\n    }\n\n    [Test]\n    public void This_Set_ThrowsException_WhenKeyIsNull()\n    {\n        var hashTable = new HashTable<string, int>(4);\n        Assert.Throws<ArgumentNullException>(() => hashTable[null] = 1);\n    }\n\n    [Test]\n    public void This_Get_ReturnsCorrectValue()\n    {\n        var hashTable = new HashTable<string, int>(4);\n        hashTable.Add(\"one\", 1);\n        Assert.That(hashTable[\"one\"], Is.EqualTo(1));\n    }\n\n    [Test]\n    public void This_Set_UpdatesValue()\n    {\n        var hashTable = new HashTable<string, int>(4);\n        hashTable.Add(\"one\", 1);\n        hashTable[\"one\"] = 2;\n        Assert.That(hashTable[\"one\"], Is.EqualTo(2));\n    }\n\n    [Test]\n    public void This_Set_KeyNotFoundException_WhenKeyDoesNotExist()\n    {\n        var hashTable = new HashTable<string, int>(4);\n        Assert.Throws<KeyNotFoundException>(() => hashTable[\"one\"] = 2);\n    }\n\n    [Test]\n    public void This_Get_KeyNotFoundException_WhenKeyDoesNotExist()\n    {\n        var hashTable = new HashTable<string, int>(4);\n        Assert.Throws<KeyNotFoundException>(() =>\n        {\n            var value = hashTable[\"one\"];\n            Console.WriteLine(value);\n        });\n    }\n\n    [Test]\n    public void Test_NegativeHashKey_ReturnsCorrectValue()\n    {\n        var hashTable = new HashTable<NegativeHashKey, int>(4);\n        hashTable.Add(new NegativeHashKey(1), 1);\n        Assert.That(hashTable[new NegativeHashKey(1)], Is.EqualTo(1));\n    }\n\n    [Test]\n    public void Resize_HandlesNegativeHashCodeCorrectly()\n    {\n        // Arrange\n        var hashTable = new HashTable<NegativeHashKey, string>(2);\n\n        // Act\n        hashTable.Add(new NegativeHashKey(1), \"A\");\n        hashTable.Add(new NegativeHashKey(2), \"B\");\n        hashTable.Add(new NegativeHashKey(3), \"C\");\n\n        // Assert\n        Assert.That(hashTable[new NegativeHashKey(1)], Is.EqualTo(\"A\"));\n        Assert.That(hashTable[new NegativeHashKey(2)], Is.EqualTo(\"B\"));\n        Assert.That(hashTable[new NegativeHashKey(3)], Is.EqualTo(\"C\"));\n    }\n\n    [Test]\n    public void Resize_HandlesNegativeIndexCorrectly()\n    {\n        // Arrange\n        var hashTable = new HashTable<NegativeHashKey, string>(2);\n        var key = new NegativeHashKey(111);\n        hashTable.Add(key, \"Value\");\n\n        // Act\n        hashTable.Resize();\n\n        // Assert\n        Assert.That(hashTable[key], Is.EqualTo(\"Value\"));\n    }\n\n    [Test]\n    public void Add_ShouldTriggerResize_WhenThresholdExceeded()\n    {\n        // Arrange\n        var initialCapacity = 4;\n        var hashTable = new HashTable<int, string>(initialCapacity);\n\n        // Act\n        for (var i = 1; i <= 32; i++)\n        {\n            hashTable.Add(i, $\"Value{i}\");\n        }\n\n        // Assert\n        hashTable.Capacity.Should().BeGreaterThan(initialCapacity);\n        hashTable.Count.Should().Be(32);\n    }\n\n\n    [Test]\n    public void Add_ThrowsException_WhenKeyIsDefault()\n    {\n        // Arrange\n        var hashTable = new HashTable<int, string>();\n\n        // Act & Assert\n        Action act = () => hashTable.Add(default, \"Value\");\n        act.Should().Throw<ArgumentNullException>().WithMessage(\"*key*\");\n    }\n\n    [Test]\n    public void Add_ThrowsException_WhenValueIsDefault()\n    {\n        // Arrange\n        var hashTable = new HashTable<int, string>();\n\n        // Act & Assert\n        Action act = () => hashTable.Add(1, default);\n        act.Should().Throw<ArgumentNullException>().WithMessage(\"*value*\");\n    }\n\n    [Test]\n    public void Add_StoresValueCorrectly()\n    {\n        // Arrange\n        var hashTable = new HashTable<int, string>();\n\n        // Act\n        hashTable.Add(1, \"Value1\");\n\n        // Assert\n        hashTable[1].Should().Be(\"Value1\");\n    }\n\n    [Test]\n    public void Get_ReturnsCorrectValue_ForExistingKey()\n    {\n        // Arrange\n        var hashTable = new HashTable<string, int>();\n        hashTable.Add(\"key\", 42);\n\n        // Act\n        var value = hashTable[\"key\"];\n\n        // Assert\n        value.Should().Be(42);\n    }\n\n    [Test]\n    public void Get_ThrowsException_WhenKeyDoesNotExist()\n    {\n        // Arrange\n        var hashTable = new HashTable<string, int>();\n\n        // Act & Assert\n        Action act = () => _ = hashTable[\"nonexistent\"];\n        act.Should().Throw<KeyNotFoundException>();\n    }\n\n    [Test]\n    public void Capacity_Increases_WhenResizeOccurs()\n    {\n        var initialCapacity = 4;\n        var hashTable = new HashTable<int, string>(initialCapacity);\n\n        for (var i = 1; i <= 5; i++)\n        {\n            hashTable.Add(i, $\"Value{i}\");\n        }\n\n        hashTable.Capacity.Should().BeGreaterThan(initialCapacity);\n    }\n\n    [Test]\n    public void IndexerSet_Throws_KeyNotFound()\n    {\n        // Arrange\n        var hashTable = new HashTable<int, string>();\n\n        // Act & Assert\n        Assert.Throws<KeyNotFoundException>(() => hashTable[1] = \"A\");\n    }\n}\n\npublic class NegativeHashKey(int id)\n{\n    private readonly int id = id;\n\n    public override int GetHashCode()\n    {\n        // Return a negative hash code\n        return -id;\n    }\n\n    public override bool Equals(object? obj)\n    {\n        if (obj is NegativeHashKey other)\n        {\n            return id == other.id;\n        }\n        return false;\n    }\n}\n\n/// <summary>\n/// Class to simulate hash collisions\n/// </summary>\n/// <param name=\"id\">Id of this object</param>\npublic class Collider(int id)\n{\n    private readonly int id = id;\n    public override int GetHashCode() => 42; // Force all instances to collide\n    public override bool Equals(object? obj) => obj is Collider other && other.id == id;\n}\n"
  },
  {
    "path": "DataStructures.Tests/Hashing/NumberTheory/PrimeNumberTests.cs",
    "content": "using DataStructures.Hashing.NumberTheory;\n\nnamespace DataStructures.Tests.Hashing.NumberTheory;\n\n[TestFixture]\npublic static class PrimeNumberTests\n{\n    private static readonly object[] IsPrimeSource =\n    [\n        new object[] { 0, false },\n        new object[] { 1, false },\n        new object[] { 2, true },\n        new object[] { 3, true },\n        new object[] { 4, false },\n        new object[] { 5, true },\n        new object[] { 6, false },\n        new object[] { 7, true },\n        new object[] { 8, false },\n        new object[] { 9, false },\n        new object[] { 10, false },\n        new object[] { 11, true },\n        new object[] { 12, false },\n        new object[] { 13, true },\n        new object[] { 14, false },\n        new object[] { 15, false },\n        new object[] { 16, false },\n        new object[] { 17, true },\n        new object[] { 18, false },\n        new object[] { 19, true },\n        new object[] { 20, false },\n        new object[] { 21, false },\n        new object[] { 22, false },\n        new object[] { 23, true },\n        new object[] { 24, false },\n        new object[] { 25, false },\n        new object[] { 26, false },\n        new object[] { 27, false },\n        new object[] { 28, false },\n        new object[] { 29, true },\n        new object[] { 30, false },\n        new object[] { 31, true },\n        new object[] { 32, false },\n        new object[] { 33, false },\n        new object[] { 34, false },\n        new object[] { 35, false },\n        new object[] { 36, false },\n        new object[] { 37, true },\n        new object[] { 38, false },\n        new object[] { 39, false },\n        new object[] { 40, false },\n    ];\n\n    private static readonly object[] NextPrimeSource =\n    [\n        new object[] { 0, 1, false, 2 },\n        new object[] { 1, 1, false, 2 },\n        new object[] { 3, 1, false, 5 },\n        new object[] { 4, 1, false, 5 },\n        new object[] { 5, 1, false, 7 },\n        new object[] { 6, 1, false, 7 },\n        new object[] { 7, 1, false, 11 },\n        new object[] { 8, 1, false, 11 },\n        new object[] { 9, 1, false, 11 },\n        new object[] { 10, 1, false, 11 },\n        new object[] { 11, 1, false, 13 },\n        new object[] { 12, 1, false, 13 },\n        new object[] { 13, 1, false, 17 },\n        new object[] { 14, 1, false, 17 },\n        new object[] { 15, 1, false, 17 },\n        new object[] { 16, 1, false, 17 },\n        new object[] { 17, 1, false, 19 },\n        new object[] { 18, 1, false, 19 },\n        new object[] { 19, 1, false, 23 },\n        new object[] { 20, 1, false, 23 },\n        new object[] { 21, 1, false, 23 },\n        new object[] { 22, 1, false, 23 },\n        new object[] { 23, 1, false, 29 },\n        new object[] { 24, 1, false, 29 },\n        new object[] { 25, 1, false, 29 },\n        new object[] { 26, 1, false, 29 },\n        new object[] { 27, 1, false, 29 },\n        new object[] { 28, 1, false, 29 },\n        new object[] { 29, 1, false, 31 },\n        new object[] { 4, 1, true, 3 },\n        new object[] { 5, 1, true, 3 },\n        new object[] { 6, 1, true, 5 },\n        new object[] { 7, 1, true, 5 },\n        new object[] { 8, 1, true, 7 },\n        new object[] { 9, 1, true, 7 },\n        new object[] { 10, 1, true, 7 }\n    ];\n\n    [TestCaseSource(nameof(IsPrimeSource))]\n    public static void IsPrimeTest(int number, bool expected)\n    {\n        var actual = PrimeNumber.IsPrime(number);\n        Assert.That(expected, Is.EqualTo(actual));\n    }\n\n    [TestCaseSource(nameof(NextPrimeSource))]\n    public static void NextPrimeTest(int number, int factor, bool desc, int expected)\n    {\n        var actual = PrimeNumber.NextPrime(number, factor, desc);\n        Assert.That(expected, Is.EqualTo(actual));\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Heap/BinaryHeapTests.cs",
    "content": "using DataStructures.Heap;\n\nnamespace DataStructures.Tests.Heap;\n\ninternal static class BinaryHeapTests\n{\n    private static BinaryHeap<int> BuildTestHeap()\n    {\n        var heap = new BinaryHeap<int>();\n        var elems = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n        foreach (var i in elems)\n        {\n            heap.Push(i);\n        }\n\n        return heap;\n    }\n\n    [Test]\n    public static void Constructor_UseCustomComparer_BuildCorrectHeap()\n    {\n        var revHeap = new BinaryHeap<int>(Comparer<int>.Create((x, y) => y.CompareTo(x)));\n        foreach (var i in new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 })\n        {\n            revHeap.Push(i);\n        }\n\n        Assert.That(revHeap.Count, Is.EqualTo(10));\n        Assert.That(revHeap.Peek(), Is.EqualTo(1));\n        Assert.That(revHeap.Pop(), Is.EqualTo(1));\n        Assert.That(revHeap.Peek(), Is.EqualTo(2));\n    }\n\n    [Test]\n    public static void Push_AddElements_BuildCorrectHeap()\n    {\n        var heap = BuildTestHeap();\n\n        Assert.That(heap.Peek(), Is.EqualTo(10));\n        Assert.That(heap.Count, Is.EqualTo(10));\n    }\n\n    public static void Pop_RemoveElements_HeapStillValid()\n    {\n        var heap = BuildTestHeap();\n\n        Assert.That(heap.Peek(), Is.EqualTo(10));\n        Assert.That(heap.Count, Is.EqualTo(10));\n\n        Assert.That(heap.Pop(), Is.EqualTo(10));\n        Assert.That(heap.Count, Is.EqualTo(9));\n        Assert.That(heap.Contains(10), Is.False);\n\n        Assert.That(heap.Pop(), Is.EqualTo(9));\n        Assert.That(heap.Count, Is.EqualTo(8));\n        Assert.That(heap.Contains(9), Is.False);\n    }\n\n    [Test]\n    public static void Pop_EmptyHeap_ThrowsCorrectException()\n    {\n        var heap = new BinaryHeap<int>();\n\n        Assert.Throws<InvalidOperationException>(() => heap.Pop());\n    }\n\n    [Test]\n    public static void Peek_NonEmptyHeap_ReturnsCorrectAnswer()\n    {\n        var heap = BuildTestHeap();\n\n        Assert.That(heap.Peek(), Is.EqualTo(10));\n    }\n\n    [Test]\n    public static void Peek_EmptyHeap_ThrowsCorrectException()\n    {\n        var heap = new BinaryHeap<int>();\n\n        Assert.Throws<InvalidOperationException>(() => heap.Peek());\n    }\n\n    [Test]\n    public static void PushPop_EmptyHeap_ReturnsCorrectAnswer()\n    {\n        var heap = new BinaryHeap<int>();\n\n        Assert.That(heap.PushPop(10), Is.EqualTo(10));\n    }\n\n    [Test]\n    public static void PushPop_NonEmptyHeap_ReturnsCorrectAnswer()\n    {\n        var heap = BuildTestHeap();\n\n        Assert.That(heap.PushPop(20), Is.EqualTo(20));\n        Assert.That(heap.PushPop(-10), Is.EqualTo(10));\n    }\n\n    [Test]\n    public static void Contains_NonEmptyHeap_ReturnsCorrectAnswer()\n    {\n        var heap = BuildTestHeap();\n\n        Assert.That(heap.Contains(1), Is.True);\n        Assert.That(heap.Contains(5), Is.True);\n        Assert.That(heap.Contains(10), Is.True);\n        Assert.That(heap.Contains(11), Is.False);\n    }\n\n    [Test]\n    public static void Contains_EmptyHeap_ReturnsCorrectAnswer()\n    {\n        var heap = new BinaryHeap<int>();\n\n        Assert.That(heap.Contains(1), Is.False);\n        Assert.That(heap.Contains(5), Is.False);\n        Assert.That(heap.Contains(10), Is.False);\n        Assert.That(heap.Contains(11), Is.False);\n    }\n\n    [Test]\n    public static void Remove_NonEmptyHeap_HeapStillValid()\n    {\n        var heap = BuildTestHeap();\n\n        heap.Remove(2);\n        Assert.That(heap.Contains(2), Is.False);\n        Assert.That(heap.Peek(), Is.EqualTo(10));\n        Assert.That(heap.Count, Is.EqualTo(9));\n\n        heap.Remove(8);\n        Assert.That(heap.Contains(8), Is.False);\n        Assert.That(heap.Peek(), Is.EqualTo(10));\n        Assert.That(heap.Count, Is.EqualTo(8));\n\n        heap.Remove(5);\n        Assert.That(heap.Contains(5), Is.False);\n        Assert.That(heap.Peek(), Is.EqualTo(10));\n        Assert.That(heap.Count, Is.EqualTo(7));\n\n        Assert.Throws<ArgumentException>(() => heap.Remove(11));\n    }\n\n    [Test]\n    public static void Remove_EmptyHeap_ThrowsCorrectException()\n    {\n        var heap = new BinaryHeap<int>();\n\n        Assert.Throws<ArgumentException>(() => heap.Remove(1));\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Heap/FibonacciHeaps/FibonacciHeapTests.cs",
    "content": "using DataStructures.Heap.FibonacciHeap;\n\nnamespace DataStructures.Tests.Heap.FibonacciHeaps;\n\ninternal class TestFHeap : FibonacciHeap<int>\n{\n    public void RawCut(FHeapNode<int> x, FHeapNode<int> y)\n    {\n        Cut(x, y);\n    }\n\n    public void RawCascadingCut(FHeapNode<int> y)\n    {\n        CascadingCut(y);\n    }\n\n    public void RawConsolidate()\n    {\n        Consolidate();\n    }\n}\n\ninternal static class FibonacciHeapTests\n{\n    private static FibonacciHeap<int> BuildTestHeap()\n    {\n        var heap = new FibonacciHeap<int>();\n        var elems = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n        foreach (var i in elems)\n        {\n            heap.Push(i);\n        }\n\n        return heap;\n    }\n\n    [Test]\n    public static void Push_AddElements_BuildCorrectHeap()\n    {\n        var heap = BuildTestHeap();\n\n        Assert.That(heap.Peek(), Is.EqualTo(1));\n        Assert.That(heap.Count, Is.EqualTo(10));\n    }\n\n    public static void Pop_RemoveElements_HeapStillValid()\n    {\n        var heap = BuildTestHeap();\n\n        Assert.That(heap.Peek(), Is.EqualTo(1));\n        Assert.That(heap.Count, Is.EqualTo(10));\n\n        Assert.That(heap.Pop(), Is.EqualTo(1));\n        Assert.That(heap.Count, Is.EqualTo(9));\n\n        Assert.That(heap.Pop(), Is.EqualTo(2));\n        Assert.That(heap.Count, Is.EqualTo(8));\n    }\n\n    [Test]\n    public static void Pop_EmptyHeap_ThrowsCorrectException()\n    {\n        var heap = new FibonacciHeap<int>();\n\n        Assert.Throws<InvalidOperationException>(() => heap.Pop());\n    }\n\n    [Test]\n    public static void Pop_NonEmptyHeap_ReturnsInSortedOrder()\n    {\n        var heap = new FibonacciHeap<int>();\n\n        var rand = new Random();\n        var heapSize = 100;\n\n        for (var i = 0; i < heapSize; i++)\n        {\n            heap.Push(rand.Next(1000));\n        }\n\n        var element = heap.Pop();\n\n        for (var i = 0; i < heapSize - 1; i++)\n        {\n            var newElement = heap.Pop();\n            Assert.That(element, Is.LessThanOrEqualTo(newElement));\n            element = newElement;\n        }\n\n        Assert.That(heap.Count, Is.Zero);\n    }\n\n    [Test]\n    public static void Peek_EmptyHeap_ThrowsCorrectException()\n    {\n        var heap = new FibonacciHeap<int>();\n\n        Assert.Throws<InvalidOperationException>(() => heap.Peek());\n    }\n\n    [Test]\n    public static void DecreaseKey_NonEmptyHeap_ReturnsCorrectAnswer()\n    {\n        var heap = BuildTestHeap();\n\n        var node = heap.Push(11);\n        heap.DecreaseKey(node, -1);\n\n        Assert.That(heap.Pop(), Is.EqualTo(-1));\n        Assert.That(heap.Pop(), Is.EqualTo(1));\n\n        node = heap.Push(5);\n        heap.DecreaseKey(node, 1);\n        Assert.That(heap.Pop(), Is.EqualTo(1));\n\n        Assert.That(heap.Pop(), Is.EqualTo(2));\n        Assert.That(heap.Pop(), Is.EqualTo(3));\n    }\n\n    [Test]\n    public static void Union_NonEmptyHeap_ReturnsSortedOrder()\n    {\n        var oddHeap = new FibonacciHeap<int>();\n\n        for (var i = 1; i < 10; i += 2)\n        {\n            oddHeap.Push(i);\n        }\n\n        var evenHeap = new FibonacciHeap<int>();\n\n        for (var i = 0; i < 10; i += 2)\n        {\n            evenHeap.Push(i);\n        }\n\n        oddHeap.Union(evenHeap);\n\n        for (var i = 0; i < 10; i++)\n        {\n            Assert.That(oddHeap.Pop(), Is.EqualTo(i));\n        }\n\n        Assert.That(oddHeap.Count, Is.Zero);\n        Assert.That(evenHeap.Count, Is.Zero);\n    }\n\n    [Test]\n    public static void Union_EmptyHeap_BecomesOtherHeap()\n    {\n        var thisHeap = new FibonacciHeap<int>();\n        var otherHeap = BuildTestHeap();\n\n        var minNode = otherHeap.Peek();\n        var otherCount = otherHeap.Count;\n\n        Assert.That(thisHeap.Count, Is.Zero);\n\n        thisHeap.Union(otherHeap);\n\n        Assert.That(otherHeap.Count, Is.Zero);\n        Assert.That(minNode, Is.EqualTo(thisHeap.Peek()));\n        Assert.Throws<InvalidOperationException>(() => otherHeap.Peek());\n\n        Assert.That(thisHeap.Count, Is.EqualTo(otherCount));\n    }\n\n    [Test]\n    public static void Union_FullHeapWithEmptyHeap_Unchanged()\n    {\n        var thisHeap = BuildTestHeap();\n        var otherHeap = new FibonacciHeap<int>();\n\n        var previousCount = thisHeap.Count;\n        var previousMin = thisHeap.Peek();\n\n        thisHeap.Union(otherHeap);\n\n        Assert.That(previousCount, Is.EqualTo(thisHeap.Count));\n        Assert.That(previousMin, Is.EqualTo(thisHeap.Peek()));\n    }\n\n    [Test]\n    public static void DecreaseKey_EmptyHeap_ThrowsCorrectException()\n    {\n        var heap = new FibonacciHeap<int>();\n        var item = new FHeapNode<int>(1);\n\n        Assert.Throws<ArgumentException>(() => heap.DecreaseKey(item, 0));\n    }\n\n    [Test]\n    public static void DecreaseKey_TryIncreaseKey_ThrowsCorrectException()\n    {\n        var heap = new FibonacciHeap<int>();\n        var item = heap.Push(1);\n\n        Assert.Throws<InvalidOperationException>(() => heap.DecreaseKey(item, 2));\n    }\n\n    [Test]\n    public static void DecreaseKey_NonEmptyHeap_PreservesHeapStructure()\n    {\n        var heap = new FibonacciHeap<int>();\n\n        for (var i = 11; i < 20; i++)\n        {\n            heap.Push(i);\n        }\n\n        var item = heap.Push(10);\n\n        for (var i = 0; i < 10; i++)\n        {\n            heap.Push(i);\n        }\n\n        var bigItem = heap.Push(20);\n\n        heap.DecreaseKey(item, -1);\n        Assert.That(-1, Is.EqualTo(heap.Pop()));\n\n        var currentVal = -1;\n        for (var i = 0; i < 10; i++)\n        {\n            var newVal = heap.Pop();\n            Assert.That(currentVal < newVal, Is.True);\n\n            currentVal = newVal;\n        }\n\n        heap.DecreaseKey(bigItem, -1);\n        Assert.That(-1, Is.EqualTo(heap.Pop()));\n\n        currentVal = -1;\n        for (var i = 0; i < 9; i++)\n        {\n            var newVal = heap.Pop();\n            Assert.That(currentVal < newVal, Is.True);\n\n            currentVal = newVal;\n        }\n    }\n\n    [Test]\n    public static void Cut_EmptyHeap_ThrowsCorrectExcpetion()\n    {\n        var heap = new TestFHeap();\n        var item1 = new FHeapNode<int>(1);\n        var item2 = new FHeapNode<int>(2);\n\n        Assert.Throws<InvalidOperationException>(() => heap.RawCut(item1, item2));\n    }\n\n    [Test]\n    public static void Cut_FilledHeap_AlteredItem()\n    {\n        var heap = new TestFHeap();\n        var item1 = heap.Push(1);\n        var item2 = heap.Push(2);\n\n        item2.Degree = -1;\n\n        Assert.Throws<InvalidOperationException>(() => heap.RawCut(item1, item2));\n    }\n\n    [Test]\n    public static void Consolidate_EmptyHeap_DoesNothing()\n    {\n        var heap = new TestFHeap();\n        heap.RawConsolidate();\n\n        Assert.Throws<InvalidOperationException>(() => heap.Peek());\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Heap/MinMaxHeapTests.cs",
    "content": "using DataStructures.Heap;\n\nnamespace DataStructures.Tests.Heap;\n\n[TestFixture]\npublic static class MinMaxHeapTests\n{\n    private static readonly object[] CollectionsSource =\n    [\n        new[] { 5, 10, -2, 0, 3, 13, 5, -8, 41, -5, -7, -60, -12 },\n        new[] { 'e', '4', 'x', 'D', '!', '$', '-', '_', '2', ')', 'Z', 'q' },\n        new[] { \"abc\", \"abc\", \"xyz\", \"bcd\", \"klm\", \"opq\", \"ijk\" },\n    ];\n\n    [Test]\n    public static void CustomComparerTest()\n    {\n        var arr = new[] { \"aaaa\", \"c\", \"dd\", \"bbb\" };\n        var comparer = Comparer<string>.Create((a, b) => Comparer<int>.Default.Compare(a.Length, b.Length));\n\n        var mmh = new MinMaxHeap<string>(comparer: comparer);\n        foreach (var s in arr)\n        {\n            mmh.Add(s);\n        }\n\n        Assert.That(comparer, Is.EqualTo(mmh.Comparer));\n        Assert.That(\"c\", Is.EqualTo(mmh.GetMin()));\n        Assert.That(\"aaaa\", Is.EqualTo(mmh.GetMax()));\n    }\n\n    [TestCaseSource(nameof(CollectionsSource))]\n    public static void AddTest<T>(IEnumerable<T> collection)\n    {\n        var mmh = new MinMaxHeap<T>();\n        foreach (var item in collection)\n        {\n            mmh.Add(item);\n        }\n\n        var minValue = mmh.GetMin();\n        var maxValue = mmh.GetMax();\n\n        Assert.That(collection.Min(), Is.EqualTo(minValue));\n        Assert.That(collection.Max(), Is.EqualTo(maxValue));\n        Assert.That(collection.Count(), Is.EqualTo(mmh.Count));\n    }\n\n    [TestCaseSource(nameof(CollectionsSource))]\n    public static void ExtractMaxTest<T>(IEnumerable<T> collection)\n    {\n        var ordered = collection.OrderByDescending(x => x);\n        var mmh = new MinMaxHeap<T>(collection);\n        var emptyHeap = new MinMaxHeap<int>();\n\n        var first = mmh.ExtractMax();\n        var second = mmh.GetMax();\n\n        Assert.Throws<InvalidOperationException>(() => emptyHeap.ExtractMax());\n        Assert.That(ordered.ElementAt(0), Is.EqualTo(first));\n        Assert.That(ordered.ElementAt(1), Is.EqualTo(second));\n        Assert.That(collection.Count() - 1, Is.EqualTo(mmh.Count));\n    }\n\n    [TestCaseSource(nameof(CollectionsSource))]\n    public static void ExtractMinTest<T>(IEnumerable<T> collection)\n    {\n        var ordered = collection.OrderBy(x => x);\n        var mmh = new MinMaxHeap<T>(collection);\n        var emptyHeap = new MinMaxHeap<int>();\n\n        var first = mmh.ExtractMin();\n        var second = mmh.GetMin();\n\n        Assert.Throws<InvalidOperationException>(() => emptyHeap.ExtractMin());\n        Assert.That(ordered.ElementAt(0), Is.EqualTo(first));\n        Assert.That(ordered.ElementAt(1), Is.EqualTo(second));\n        Assert.That(collection.Count() - 1, Is.EqualTo(mmh.Count));\n    }\n\n    [TestCaseSource(nameof(CollectionsSource))]\n    public static void GetMaxTest<T>(IEnumerable<T> collection)\n    {\n        var emptyHeap = new MinMaxHeap<T>();\n        var mmh = new MinMaxHeap<T>(collection);\n\n        var maxValue = mmh.GetMax();\n\n        Assert.Throws<InvalidOperationException>(() => emptyHeap.GetMax());\n        Assert.That(collection.Max(), Is.EqualTo(maxValue));\n    }\n\n    [TestCaseSource(nameof(CollectionsSource))]\n    public static void GetMinTest<T>(IEnumerable<T> collection)\n    {\n        var emptyHeap = new MinMaxHeap<T>();\n        var mmh = new MinMaxHeap<T>(collection);\n\n        var minValue = mmh.GetMin();\n\n        Assert.Throws<InvalidOperationException>(() => emptyHeap.GetMin());\n        Assert.That(collection.Min(), Is.EqualTo(minValue));\n    }\n\n    [Test]\n    public static void HeapSortUsingGet<T>(\n        [ValueSource(nameof(CollectionsSource))] IEnumerable<T> collection,\n        [Values] bool ascending)\n    {\n        var ordered = ascending ? collection.OrderBy(x => x) : collection.OrderByDescending(x => x);\n        var mmh = new MinMaxHeap<T>(collection);\n        var extracted = new List<T>();\n\n        while (mmh.Count > 0)\n        {\n            T value;\n            if (ascending)\n            {\n                value = mmh.GetMin();\n                _ = mmh.ExtractMin();\n            }\n            else\n            {\n                value = mmh.GetMax();\n                _ = mmh.ExtractMax();\n            }\n\n            extracted.Add(value);\n        }\n\n        Assert.That(ordered.SequenceEqual(extracted), Is.True);\n    }\n\n    [Test]\n    public static void HeapSortUsingExtract<T>(\n        [ValueSource(nameof(CollectionsSource))] IEnumerable<T> collection,\n        [Values] bool ascending)\n    {\n        var ordered = ascending ? collection.OrderBy(x => x) : collection.OrderByDescending(x => x);\n        var mmh = new MinMaxHeap<T>(collection);\n        var extracted = new List<T>();\n\n        while (mmh.Count > 0)\n        {\n            var value = ascending ? mmh.ExtractMin() : mmh.ExtractMax();\n            extracted.Add(value);\n        }\n\n        Assert.That(ordered.SequenceEqual(extracted), Is.True);\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Heap/PairingHeap/PairingHeapComparerTests.cs",
    "content": "using DataStructures.Heap.PairingHeap;\n\nnamespace DataStructures.Tests.Heap.PairingHeap;\n\ninternal class PairingHeapComparerTests\n{\n    [Test]\n    public void Compare_CheckAscending_ReturnNegative()\n    {\n        var minHeap = new PairingNodeComparer<int>(Sorting.Ascending, Comparer<int>.Default);\n        var node1 = new PairingHeapNode<int>(10);\n        var node2 = new PairingHeapNode<int>(20);\n\n        var items = minHeap.Compare(node1.Value, node2.Value);\n\n        items.Should().Be(-1);\n    }\n\n    [Test]\n    public void Compare_CheckAscending_ReturnPositive()\n    {\n        var minHeap = new PairingNodeComparer<int>(Sorting.Descending, Comparer<int>.Default);\n        var node1 = new PairingHeapNode<int>(10);\n        var node2 = new PairingHeapNode<int>(20);\n\n        var items = minHeap.Compare(node1.Value, node2.Value);\n\n        items.Should().Be(1);\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Heap/PairingHeap/PairingHeapTests.cs",
    "content": "using System.Collections;\nusing DataStructures.Heap.PairingHeap;\n\nnamespace DataStructures.Tests.Heap.PairingHeap;\n\ninternal class PairingHeapTests\n{\n    [Test]\n    public void BuildMinHeap_CheckEnumerator_NotThrowOnEnumerate()\n    {\n        var minHeap = new PairingHeap<int>();\n        minHeap.Insert(1);\n\n        var items = minHeap.ToList();\n\n        items.Should().HaveCount(1);\n    }\n\n    [Test]\n    public void BuildMinHeap_CheckEnumerable_NotThrowOnEnumerate()\n    {\n        var minHeap = new PairingHeap<int>();\n        minHeap.Insert(1);\n\n        foreach (var node in (IEnumerable)minHeap)\n        {\n            node.Should().NotBe(null);\n        }\n    }\n\n    [Test]\n    public void BuildMinHeap_UpdateNonExistingNode_ThrowException()\n    {\n        var minHeap = new PairingHeap<int>();\n        minHeap.Insert(1);\n        minHeap.Extract();\n\n        Action act = () => minHeap.UpdateKey(1, 10);\n\n        act.Should().Throw<ArgumentException>();\n    }\n\n    [Test]\n    public void BuildMinHeap_UpdateBadNode_ThrowException()\n    {\n        var minHeap = new PairingHeap<int>();\n        minHeap.Insert(10);\n\n        Action act = () => minHeap.UpdateKey(10, 11);\n\n        act.Should().Throw<ArgumentException>();\n    }\n\n    [Test]\n    public void BuildMinHeap_CreateHeap_HeapIsCheked()\n    {\n        var nodeCount = 1000 * 10;\n        var minHeap = new PairingHeap<int>();\n        for (var i = 0; i <= nodeCount; i++)\n        {\n            minHeap.Insert(i);\n        }\n\n        for (var i = 0; i <= nodeCount; i++)\n        {\n            minHeap.UpdateKey(i, i - 1);\n        }\n\n        var min = 0;\n        for (var i = 0; i <= nodeCount; i++)\n        {\n            min = minHeap.Extract();\n            Assert.That(min, Is.EqualTo(i - 1));\n        }\n\n        Assert.That(minHeap.Count, Is.EqualTo(minHeap.Count));\n\n        var rnd = new Random();\n        var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(_ => rnd.Next()).ToList();\n\n        foreach (var item in testSeries)\n        {\n            minHeap.Insert(item);\n        }\n\n        for (var i = 0; i < testSeries.Count; i++)\n        {\n            var decremented = testSeries[i] - rnd.Next(0, 1000);\n            minHeap.UpdateKey(testSeries[i], decremented);\n            testSeries[i] = decremented;\n        }\n\n        testSeries.Sort();\n\n        for (var i = 0; i < nodeCount - 2; i++)\n        {\n            min = minHeap.Extract();\n            Assert.That(testSeries[i], Is.EqualTo(min));\n        }\n\n        Assert.That(minHeap.Count, Is.EqualTo(minHeap.Count));\n    }\n\n    [Test]\n    public void BuildMaxHeap_CreateHeap_HeapIsCheked()\n    {\n        var nodeCount = 1000 * 10;\n        var maxHeap = new PairingHeap<int>(Sorting.Descending);\n        for (var i = 0; i <= nodeCount; i++)\n        {\n            maxHeap.Insert(i);\n        }\n\n        for (var i = 0; i <= nodeCount; i++)\n        {\n            maxHeap.UpdateKey(i, i + 1);\n        }\n\n        Assert.That(maxHeap.Count, Is.EqualTo(maxHeap.Count));\n\n        var max = 0;\n        for (var i = nodeCount; i >= 0; i--)\n        {\n            max = maxHeap.Extract();\n            Assert.That(max, Is.EqualTo(i + 1));\n        }\n\n        var rnd = new Random();\n        var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(_ => rnd.Next()).ToList();\n\n        foreach (var item in testSeries)\n        {\n            maxHeap.Insert(item);\n        }\n\n        for (var i = 0; i < testSeries.Count; i++)\n        {\n            var incremented = testSeries[i] + rnd.Next(0, 1000);\n            maxHeap.UpdateKey(testSeries[i], incremented);\n            testSeries[i] = incremented;\n        }\n\n        testSeries = testSeries.OrderByDescending(x => x).ToList();\n        for (var i = 0; i < nodeCount - 2; i++)\n        {\n            max = maxHeap.Extract();\n            Assert.That(testSeries[i], Is.EqualTo(max));\n        }\n\n        Assert.That(maxHeap.Count, Is.EqualTo(maxHeap.Count));\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/InvertedIndexTests.cs",
    "content": "namespace DataStructures.Tests;\n\npublic class InvertedIndexTests\n{\n    [Test]\n    public void Or_GetSourcesWithAtLeastOneFromList_ReturnAllSources()\n    {\n        var index = new InvertedIndex();\n        var source1 = \"one star is sparkling bright\";\n        var source2 = \"two stars are sparkling even brighter\";\n        index.AddToIndex(nameof(source1), source1);\n        index.AddToIndex(nameof(source2), source2);\n\n        var or = index.Or(new List<string> { \"star\", \"sparkling\" });\n\n        or.Should().BeEquivalentTo(nameof(source1), nameof(source2));\n    }\n\n    [Test]\n    public void And_GetSourcesWithAllInsideList_ReturnFirstSource()\n    {\n        var index = new InvertedIndex();\n        var source1 = \"one star is sparkling bright\";\n        var source2 = \"two stars are sparkling even brighter\";\n        index.AddToIndex(nameof(source1), source1);\n        index.AddToIndex(nameof(source2), source2);\n\n        var and = index.And(new List<string> { \"star\", \"sparkling\" });\n\n        and.Should().BeEquivalentTo(nameof(source1));\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/LinkedList/CircularLinkedListTests.cs",
    "content": "using DataStructures.LinkedList.CircularLinkedList;\n\nnamespace DataStructures.Tests.LinkedList;\n\n[TestFixture]\npublic static class CircularLinkedListTests\n{\n    [Test]\n    public static void TestInsertAtBeginning()\n    {\n        var cll = new CircularLinkedList<int>();\n        cll.InsertAtBeginning(10);\n        cll.InsertAtBeginning(20);\n        cll.InsertAtBeginning(30);\n\n        Assert.That(\"30 20 10\", Is.EqualTo(GetDisplayOutput(cll).Trim()));\n    }\n\n    [Test]\n    public static void TestInsertAtEnd()\n    {\n        var cll = new CircularLinkedList<int>();\n        cll.InsertAtEnd(10);\n        cll.InsertAtEnd(20);\n        cll.InsertAtEnd(30);\n\n        Assert.That(\"10 20 30\", Is.EqualTo(GetDisplayOutput(cll).Trim()));\n    }\n\n    [Test]\n    public static void TestInsertAfter()\n    {\n        var cll = new CircularLinkedList<int>();\n        cll.InsertAtEnd(10);\n        cll.InsertAtEnd(20);\n        cll.InsertAtEnd(30);\n        cll.InsertAfter(20, 25);\n\n        Assert.That(\"10 20 25 30\", Is.EqualTo(GetDisplayOutput(cll).Trim()));\n    }\n\n    [Test]\n    public static void TestInsertAtBeginningInEmptyList()\n    {\n        var cll = new CircularLinkedList<int>();\n        cll.InsertAtBeginning(10);\n\n        Assert.That(\"10\", Is.EqualTo(GetDisplayOutput(cll).Trim()));\n    }\n\n    [Test]\n    public static void TestInsertAtEndInEmptyList()\n    {\n        var cll = new CircularLinkedList<int>();\n        cll.InsertAtEnd(10);\n\n        Assert.That(\"10\", Is.EqualTo(GetDisplayOutput(cll).Trim()));\n    }\n\n    [Test]\n    public static void TestInsertAfterInEmptyList()\n    {\n        var cll = new CircularLinkedList<int>();\n        var ex = Assert.Throws<InvalidOperationException>(() => cll.InsertAfter(10, 20));\n\n        Assert.That(ex!.Message, Is.EqualTo(\"List is empty.\"));\n    }\n\n    [Test]\n    public static void TestInsertAfterSpecificNode()\n    {\n        var cll = new CircularLinkedList<int>();\n        cll.InsertAtEnd(10);\n        cll.InsertAtEnd(20);\n        cll.InsertAtEnd(30);\n        cll.InsertAfter(20, 25); // Insert after node with value 20\n\n        Assert.That(\"10 20 25 30\", Is.EqualTo(GetDisplayOutput(cll).Trim()));\n    }\n\n    [Test]\n    public static void TestInsertAfterOnNonExistingValue()\n    {\n        var cll = new CircularLinkedList<int>();\n        cll.InsertAtEnd(10);\n        cll.InsertAfter(99, 25); // 99 does not exist\n\n        Assert.That(\"10\", Is.EqualTo(GetDisplayOutput(cll).Trim()));\n    }\n\n    [Test]\n    public static void TestDeleteNode()\n    {\n        var cll = new CircularLinkedList<int>();\n        cll.InsertAtEnd(10);\n        cll.InsertAtEnd(20);\n        cll.InsertAtEnd(30);\n        cll.DeleteNode(20);\n\n        Assert.That(\"10 30\", Is.EqualTo(GetDisplayOutput(cll).Trim()));\n    }\n\n    [Test]\n    public static void TestDeleteOnlyNode()\n    {\n        var cll = new CircularLinkedList<int>();\n        cll.InsertAtBeginning(10);\n        cll.DeleteNode(10);\n\n        Assert.That(cll.IsEmpty(), Is.EqualTo(true));\n    }\n\n    [Test]\n    public static void TestDeleteHeadNode()\n    {\n        var cll = new CircularLinkedList<int>();\n        cll.InsertAtEnd(10);\n        cll.InsertAtEnd(20);\n        cll.InsertAtEnd(30);\n        cll.DeleteNode(10);\n\n        Assert.That(\"20 30\", Is.EqualTo(GetDisplayOutput(cll).Trim()));\n    }\n\n    [Test]\n    public static void TestDeleteTailNode()\n    {\n        var cll = new CircularLinkedList<int>();\n        cll.InsertAtEnd(10);\n        cll.InsertAtEnd(20);\n        cll.InsertAtEnd(30);\n        cll.DeleteNode(30);\n\n        Assert.That(\"10 20\", Is.EqualTo(GetDisplayOutput(cll).Trim()));\n    }\n\n    [Test]\n    public static void TestDeleteFromEmptyList()\n    {\n        var cll = new CircularLinkedList<int>();\n        var ex = Assert.Throws<InvalidOperationException>(() => cll.DeleteNode(10));\n\n        Assert.That(ex!.Message, Is.EqualTo(\"List is empty.\"));\n    }\n\n    [Test]\n    public static void TestDeleteNonExistentNode()\n    {\n        var cll = new CircularLinkedList<int>();\n        cll.InsertAtEnd(10);\n        cll.InsertAtEnd(20);\n        cll.InsertAtEnd(30);\n        cll.DeleteNode(40); // Attempting to delete a node that doesn't exist\n\n        Assert.That(\"10 20 30\", Is.EqualTo(GetDisplayOutput(cll).Trim()));\n    }\n\n    private static string GetDisplayOutput<T>(CircularLinkedList<T> list)\n    {\n        var head = list.GetHead();\n        if (head == null)\n        {\n            return string.Empty;\n        }\n\n        var current = head;\n        var result = new System.Text.StringBuilder();\n\n        do\n        {\n            result.Append(current!.Data + \" \");\n            current = current.Next;\n        }\n        while (current != head);\n\n        return result.ToString().Trim();\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/LinkedList/DoublyLinkedListTests.cs",
    "content": "using DataStructures.LinkedList.DoublyLinkedList;\n\nnamespace DataStructures.Tests.LinkedList;\n\npublic static class DoublyLinkedListTests\n{\n    [Test]\n    public static void TestGetData()\n    {\n        var dll = new DoublyLinkedList<int>(new[] { 0, 1, 2, 3, 4 });\n        var arr = dll.GetData().ToArray();\n\n        Assert.That(dll.Count, Is.EqualTo(5));\n        Assert.That(new[] { 0, 1, 2, 3, 4 }, Is.EqualTo(arr));\n    }\n\n    [Test]\n    public static void TestGetAt()\n    {\n        var dll = new DoublyLinkedList<int>(new[] { 0, 1, 2, 3, 4 });\n\n        var one = dll.GetAt(1);\n        var three = dll.GetAt(3);\n\n        Assert.That(one.Data, Is.EqualTo(1));\n        Assert.That(three.Data, Is.EqualTo(3));\n        Assert.Throws<ArgumentOutOfRangeException>(\n            () => dll.GetAt(-1)\n        );\n        Assert.Throws<ArgumentOutOfRangeException>(\n            () => dll.GetAt(5)\n        );\n    }\n\n    [Test]\n    public static void TestAddtion()\n    {\n        var dll = new DoublyLinkedList<int>(0);\n        var one = dll.Add(1);\n\n        dll.Add(3);\n        dll.AddAfter(2, one);\n        dll.Add(4);\n\n        var arr = dll.GetData().ToArray();\n        var reversedArr = dll.GetDataReversed().ToArray();\n\n        Assert.That(dll.Count, Is.EqualTo(5));\n        Assert.That(new[] { 0, 1, 2, 3, 4 }, Is.EqualTo(arr));\n        Assert.That(new[] { 4, 3, 2, 1, 0 }, Is.EqualTo(reversedArr));\n    }\n\n    [Test]\n    public static void TestRemove()\n    {\n        var dll = new DoublyLinkedList<int>(new[] { 0, 1, 2, 3, 4 });\n\n        dll.RemoveNode(dll.Find(2));\n        dll.RemoveHead();\n        dll.Remove();\n\n        var arr = dll.GetData().ToArray();\n        var reversedArr = dll.GetDataReversed().ToArray();\n\n        Assert.That(dll.Count, Is.EqualTo(2));\n        Assert.That(new[] { 1, 3 }, Is.EqualTo(arr));\n        Assert.That(new[] { 3, 1 }, Is.EqualTo(reversedArr));\n    }\n\n    [Test]\n    public static void TestFind()\n    {\n        var dll = new DoublyLinkedList<int>(new[] { 0, 1, 2, 3, 4 });\n\n        var one = dll.Find(1);\n        var three = dll.Find(3);\n\n        Assert.That(one.Data, Is.EqualTo(1));\n        Assert.That(three.Data, Is.EqualTo(3));\n    }\n\n    [Test]\n    public static void TestIndexOf()\n    {\n        var dll = new DoublyLinkedList<int>(new[] { 0, 1, 2, 3, 4 });\n\n        var one = dll.IndexOf(1);\n        var three = dll.IndexOf(3);\n\n        Assert.That(one, Is.EqualTo(1));\n        Assert.That(three, Is.EqualTo(3));\n    }\n\n    [Test]\n    public static void TestContains()\n    {\n        var dll = new DoublyLinkedList<int>(new[] { 0, 1, 2, 3, 4 });\n\n        var one = dll.Contains(1);\n        var six = dll.Contains(6);\n\n        Assert.That(one, Is.True);\n        Assert.That(six, Is.False);\n    }\n\n    [Test]\n    public static void TestReverse()\n    {\n        var dll = new DoublyLinkedList<int>(new[] { 0, 1, 2, 3, 4 });\n        dll.Reverse();\n        var arr = dll.GetData().ToArray();\n\n        var empty = new DoublyLinkedList<int>(new int[] { });\n        empty.Reverse();\n        var emptyArr = empty.GetData().ToArray();\n\n        Assert.That(arr, Is.EqualTo(new[] { 4, 3, 2, 1, 0 }));\n        Assert.That(emptyArr, Is.EqualTo(new int[] { }));\n    }\n\n    [Test]\n    public static void TestGetDataReversed()\n    {\n        var dll = new DoublyLinkedList<int>(new[] { 0, 1, 2, 3, 4 });\n        var arr = dll.GetData().ToArray();\n        var reversedArr = dll.GetDataReversed().ToArray();\n\n        Assert.That(arr, Is.EqualTo(new[] { 0, 1, 2, 3, 4 }));\n        Assert.That(reversedArr, Is.EqualTo(new[] { 4, 3, 2, 1, 0 }));\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/LinkedList/LinkedListTests.cs",
    "content": "using DataStructures.LinkedList.SinglyLinkedList;\n\nnamespace DataStructures.Tests.LinkedList;\n\npublic static class LinkedListTests\n{\n    [Test]\n    public static void LengthWorksCorrectly([Random(0, 1000, 100)] int quantity)\n    {\n        // Arrange\n        var a = new SinglyLinkedList<int>();\n\n        // Act\n        var r = TestContext.CurrentContext.Random;\n        for (var i = 0; i < quantity; i++)\n        {\n            _ = a.AddFirst(r.Next());\n        }\n\n        // Assert\n        Assert.That(quantity, Is.EqualTo(a.Length()));\n    }\n\n    [Test]\n    public static void LengthOnEmptyListIsZero()\n    {\n        // Arrange\n        var a = new SinglyLinkedList<int>();\n\n        // Act\n\n        // Assert\n        Assert.That(0, Is.EqualTo(a.Length()));\n    }\n\n    [Test]\n    public static void GetItemsFromLinkedList()\n    {\n        // Arrange\n        var testObj = new SinglyLinkedList<string>();\n        _ = testObj.AddLast(\"H\");\n        _ = testObj.AddLast(\"E\");\n        _ = testObj.AddLast(\"L\");\n        _ = testObj.AddLast(\"L\");\n        _ = testObj.AddLast(\"O\");\n\n        // Act\n        var items = testObj.GetListData();\n\n        // Assert\n        Assert.That(5, Is.EqualTo(items.Count()));\n        Assert.That(\"O\", Is.EqualTo(testObj.GetElementByIndex(4)));\n    }\n\n    [Test]\n    public static void GetElementByIndex_IndexOutOfRange_ArgumentOutOfRangeExceptionThrown()\n    {\n        // Arrange\n        var list = new SinglyLinkedList<int>();\n\n        // Act\n        _ = list.AddFirst(1);\n        _ = list.AddFirst(2);\n        _ = list.AddFirst(3);\n\n        // Assert\n        _ = Assert.Throws<ArgumentOutOfRangeException>(() => list.GetElementByIndex(-1));\n        _ = Assert.Throws<ArgumentOutOfRangeException>(() => list.GetElementByIndex(3));\n    }\n\n\n    [Test]\n    public static void RemoveItemsFromList()\n    {\n        // Arrange\n        var testObj = new SinglyLinkedList<string>();\n        _ = testObj.AddLast(\"X\");\n        _ = testObj.AddLast(\"H\");\n        _ = testObj.AddLast(\"E\");\n        _ = testObj.AddLast(\"L\");\n        _ = testObj.AddLast(\"L\");\n        _ = testObj.AddLast(\"I\");\n        _ = testObj.AddLast(\"O\");\n\n        // Act\n        var xRemoveSucess = testObj.DeleteElement(\"X\");\n        var oRemoveSucess = testObj.DeleteElement(\"O\");\n        var eRemoveSucess = testObj.DeleteElement(\"E\");\n        var lRemoveSucess = testObj.DeleteElement(\"L\");\n        var l2RemoveSucess = testObj.DeleteElement(\"L\");\n        var l3RemoveSucess = testObj.DeleteElement(\"L\");\n        var nonExistantRemoveSucess = testObj.DeleteElement(\"F\");\n\n        var resultString = testObj.GetElementByIndex(0) + testObj.GetElementByIndex(1);\n\n        // Assert\n        Assert.That(\"HI\", Is.EqualTo(resultString));\n        Assert.That(xRemoveSucess, Is.True);\n        Assert.That(oRemoveSucess, Is.True);\n        Assert.That(eRemoveSucess, Is.True);\n        Assert.That(lRemoveSucess, Is.True);\n        Assert.That(l2RemoveSucess, Is.True);\n        Assert.That(l3RemoveSucess, Is.False);\n        Assert.That(nonExistantRemoveSucess, Is.False);\n    }\n\n    [Test]\n    public static void DeleteFirstFromList()\n    {\n        // Arrange\n        var testObj = new SinglyLinkedList<string>();\n        _ = testObj.AddLast(\"H\");\n        _ = testObj.AddLast(\"E\");\n        _ = testObj.AddLast(\"L\");\n        _ = testObj.AddLast(\"L\");\n        _ = testObj.AddLast(\"O\");\n\n        // Act\n        var deleteSuccess = testObj.DeleteFirst();\n\n        // Assert\n        Assert.That(deleteSuccess, Is.True);\n        Assert.That(4, Is.EqualTo(testObj.Length()));\n        Assert.That(\"E\", Is.EqualTo(testObj.GetElementByIndex(0)));\n    }\n\n    [Test]\n    public static void DeleteFirstFromEmptyList()\n    {\n        // Arrange\n        var testObj = new SinglyLinkedList<string>();\n\n        // Act\n        var deleteSuccess = testObj.DeleteFirst();\n\n        // Assert\n        Assert.That(deleteSuccess, Is.False);\n    }\n\n    [Test]\n    public static void DeleteLastFromList()\n    {\n        // Arrange\n        var testObj = new SinglyLinkedList<string>();\n        _ = testObj.AddLast(\"H\");\n        _ = testObj.AddLast(\"E\");\n        _ = testObj.AddLast(\"L\");\n        _ = testObj.AddLast(\"L\");\n        _ = testObj.AddLast(\"O\");\n\n        // Act\n        var deleteSuccess = testObj.DeleteLast();\n\n        // Assert\n        Assert.That(deleteSuccess, Is.True);\n        Assert.That(4, Is.EqualTo(testObj.Length()));\n        Assert.That(\"L\", Is.EqualTo(testObj.GetElementByIndex(testObj.Length() - 1)));\n    }\n\n    [Test]\n    public static void DeleteLastFromEmptyList()\n    {\n        // Arrange\n        var testObj = new SinglyLinkedList<string>();\n\n        // Act\n        var deleteSuccess = testObj.DeleteLast();\n\n        // Assert\n        Assert.That(deleteSuccess, Is.False);\n    }\n\n}\n"
  },
  {
    "path": "DataStructures.Tests/LinkedList/SkipListTests.cs",
    "content": "using DataStructures.LinkedList.SkipList;\n\nnamespace DataStructures.Tests.LinkedList;\n\npublic static class SkipListTests\n{\n    [Test]\n    public static void TestAdd()\n    {\n        var list = new SkipList<int>();\n        list.AddOrUpdate(1, 1);\n        list[2] = 2;\n        list[3] = 3;\n\n        list.Count.Should().Be(3);\n        list.GetValues().Should().ContainInOrder(1, 2, 3);\n    }\n\n    [Test]\n    public static void TestUpdate()\n    {\n        var list = new SkipList<string>();\n\n        // Add some elements.\n        list[1] = \"v1\";\n        list[2] = \"v2\";\n        list[5] = \"v5\";\n\n        // Update\n        list.AddOrUpdate(1, \"v1-updated\");\n        list[2] = \"v2-updated\";\n\n        list.Count.Should().Be(3);\n        list.GetValues().Should().ContainInOrder(\"v1-updated\", \"v2-updated\", \"v5\");\n    }\n\n    [Test]\n    public static void TestContains()\n    {\n        var list = new SkipList<int>();\n        list.AddOrUpdate(1, 1);\n        list.AddOrUpdate(3, 3);\n        list.AddOrUpdate(5, 5);\n\n        list.Contains(1).Should().BeTrue();\n        list.Contains(3).Should().BeTrue();\n        list.Contains(5).Should().BeTrue();\n        list.Contains(0).Should().BeFalse();\n        list.Contains(2).Should().BeFalse();\n        list.Contains(9).Should().BeFalse();\n    }\n\n    [Test]\n    public static void TestGetByKey_Success()\n    {\n        var list = new SkipList<string>();\n        list[1] = \"value1\";\n\n        list[1].Should().Be(\"value1\");\n    }\n\n    [Test]\n    public static void TestGetByKey_KeyNotFoundException()\n    {\n        var list = new SkipList<string>();\n        list[1] = \"value1\";\n\n        string value;\n        Action act = () => value = list[2];\n        act.Should().Throw<KeyNotFoundException>();\n    }\n\n    [Test]\n    public static void TestRemove_ItemRemoved()\n    {\n        var list = new SkipList<int>();\n        list.AddOrUpdate(1, 1);\n        list.AddOrUpdate(2, 2);\n        list.AddOrUpdate(3, 3);\n\n        list.Count.Should().Be(3);\n        list.Contains(2).Should().BeTrue();\n\n        var isRemoved = list.Remove(2);\n\n        list.Count.Should().Be(2);\n        list.Contains(2).Should().BeFalse();\n        isRemoved.Should().BeTrue();\n    }\n\n    [Test]\n    public static void TestRemove_ItemNotFound()\n    {\n        var list = new SkipList<int>();\n        list.AddOrUpdate(1, 1);\n        list.AddOrUpdate(2, 2);\n        list.AddOrUpdate(3, 3);\n\n        var isRemoved = list.Remove(222);\n\n        list.Count.Should().Be(3);\n        isRemoved.Should().BeFalse();\n    }\n\n    [Test]\n    public static void TestGetValues()\n    {\n        var list = new SkipList<string>();\n        list[4] = \"four\";\n        list[2] = \"two\";\n        list[3] = \"three\";\n        list[1] = \"one\";\n\n        var valuesSortedByKey = list.GetValues();\n\n        valuesSortedByKey.Should().ContainInOrder(\"one\", \"two\", \"three\", \"four\");\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Probabilistic/BloomFilterTests.cs",
    "content": "using DataStructures.Probabilistic;\n\nnamespace DataStructures.Tests.Probabilistic;\n\npublic class BloomFilterTests\n{\n    static readonly string[] TestNames = [\"kal;jsnfka\", \"alkjsdfn;lakm\", \"aljfopiawjf\", \"afowjeaofeij\", \"oajwsefoaiwje\", \"aoiwjfaoiejmf\", \"aoijfoawiejf\"];\n\n    private class SimpleObject(string name, int number)\n    {\n        public string Name { get; set; } = name;\n        public int Number { get; set; } = number;\n    }\n\n    private class SimpleObjectOverridenHash(string name, int number)\n    {\n        private const uint FnvPrime = 16777619;\n        private const uint FnvOffsetBasis = 2166136261;\n        public string Name { get; set; } = name;\n        public int Number { get; set; } = number;\n\n        public override int GetHashCode()\n        {\n            var bytes = Encoding.UTF8.GetBytes(Name).Concat(BitConverter.GetBytes(Number));\n            var hash = FnvOffsetBasis;\n            foreach (var @byte in bytes)\n            {\n                hash = hash * FnvPrime;\n                hash ^= @byte;\n            }\n\n            return (int)hash;\n        }\n\n        public override bool Equals(object? obj)\n        {\n            return obj is SimpleObjectOverridenHash asSimpleObj && asSimpleObj.Name == Name && asSimpleObj.Number == Number;\n        }\n    }\n\n    [Test]\n    public void TestBloomFilterInsertOptimalSize()\n    {\n        var filter = new BloomFilter<int>(1000);\n        var set = new HashSet<int>();\n        var rand = new Random(124);\n        var falsePositives = 0;\n        for (var i = 0; i < 1000; i++)\n        {\n            var k = rand.Next(0, 1000);\n            if (!set.Contains(k) && filter.Search(k))\n            {\n                falsePositives++;\n            }\n            filter.Insert(k);\n            set.Add(k);\n            Assert.That(filter.Search(k), Is.True);\n        }\n\n        Assert.That(.05 > falsePositives / 1000.0, Is.True); // be a bit generous in our fault tolerance here\n    }\n\n    [Test]\n    public void TestBloomFilterInsert()\n    {\n        var filter = new BloomFilter<SimpleObject>(100000, 3);\n        var rand = new Random();\n        for (var i = 0; i < 1000; i++)\n        {\n            var simpleObject = new SimpleObject(TestNames[rand.Next(TestNames.Length)], rand.Next(15));\n            filter.Insert(simpleObject);\n            Assert.That(filter.Search(simpleObject), Is.True);\n        }\n    }\n\n    [Test]\n    public void TestBloomFilterSearchOverridenHash()\n    {\n        var filter = new BloomFilter<SimpleObjectOverridenHash>(100000, 3);\n        var simpleObjectInserted = new SimpleObjectOverridenHash(\"foo\", 1);\n        var simpleObjectInserted2 = new SimpleObjectOverridenHash(\"foo\", 1);\n        var simpleObjectNotInserted = new SimpleObjectOverridenHash(\"bar\", 2);\n        filter.Insert(simpleObjectInserted);\n        Assert.That(filter.Search(simpleObjectInserted), Is.True);\n        Assert.That(filter.Search(simpleObjectInserted2), Is.True);\n        Assert.That(filter.Search(simpleObjectNotInserted), Is.False);\n    }\n\n    [Test]\n    public void TestBloomFilterSearch()\n    {\n        var filter = new BloomFilter<SimpleObject>(10000, 3);\n        var simpleObjectInserted = new SimpleObject(\"foo\", 1);\n        var simpleObjectNotInserted = new SimpleObject(\"foo\", 1);\n        filter.Insert(simpleObjectInserted);\n        Assert.That(filter.Search(simpleObjectNotInserted), Is.False);\n        Assert.That(filter.Search(simpleObjectInserted), Is.True);\n\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Probabilistic/CountMinSketchTests.cs",
    "content": "using DataStructures.Probabilistic;\n\nnamespace DataStructures.Tests.Probabilistic;\n\npublic class CountMinSketchTests\n{\n    public class SimpleObject(string name, int number)\n    {\n        public string Name { get; set; } = name;\n        public int Number { get; set; } = number;\n    }\n\n    [Test]\n    public void TestInsertAndCount()\n    {\n        var obj1 = new SimpleObject(\"foo\", 5);\n        var obj2 = new SimpleObject(\"bar\", 6);\n\n        var sketch = new CountMinSketch<SimpleObject>(200, 5);\n\n        for (var i = 0; i < 5000; i++)\n        {\n            sketch.Insert(obj1);\n            sketch.Insert(obj2);\n        }\n\n        sketch.Query(obj1).Should().BeGreaterOrEqualTo(5000);\n        sketch.Query(obj2).Should().BeGreaterOrEqualTo(5000);\n    }\n\n    [Test]\n    public void TestOptimalInitializer()\n    {\n        var obj1 = new SimpleObject(\"foo\", 5);\n        var obj2 = new SimpleObject(\"bar\", 6);\n\n        var sketch = new CountMinSketch<SimpleObject>(.001, .05);\n\n        for (var i = 0; i < 5000; i++)\n        {\n            sketch.Insert(obj1);\n            sketch.Insert(obj2);\n        }\n\n        sketch.Query(obj1).Should().BeGreaterOrEqualTo(5000);\n        sketch.Query(obj2).Should().BeGreaterOrEqualTo(5000);\n    }\n\n    [Test]\n    public void TestProbabilities()\n    {\n        var sketch = new CountMinSketch<int>(.01, .05);\n        var random = new Random();\n        var insertedItems = new Dictionary<int, int>();\n        for (var i = 0; i < 10000; i++)\n        {\n            var item = random.Next(0, 1000000);\n            sketch.Insert(item);\n            if (insertedItems.ContainsKey(item))\n            {\n                insertedItems[item]++;\n            }\n            else\n            {\n                insertedItems.Add(item, 1);\n            }\n        }\n\n        var numMisses = 0;\n        foreach (var item in insertedItems)\n        {\n            if (sketch.Query(item.Key) - item.Value > .01 * 100000)\n            {\n                numMisses++;\n            }\n        }\n\n        (numMisses / (double)insertedItems.Count).Should().BeLessOrEqualTo(.05);\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Probabilistic/HyperLogLogTest.cs",
    "content": "using DataStructures.Probabilistic;\n\nnamespace DataStructures.Tests.Probabilistic;\n\npublic class HyperLogLogTest\n{\n    [Test]\n    public void TestHyperLogLog()\n    {\n        var hll = new HyperLogLog<int>();\n        HashSet<int> actual = [];\n\n        var rand = new Random();\n        var tolerance = .05;\n        for (var i = 0; i < 10000; i++)\n        {\n            var k = rand.Next(20000);\n            hll.Add(k);\n            actual.Add(k);\n        }\n\n        hll.Cardinality().Should()\n            .BeGreaterOrEqualTo((int)(actual.Count * (1 - tolerance)))\n            .And\n            .BeLessOrEqualTo((int)(actual.Count * (1 + tolerance)));\n    }\n\n    [Test]\n    public void TestHyperLogLogMerge()\n    {\n        var hll1 = new HyperLogLog<int>();\n        var hll2 = new HyperLogLog<int>();\n        var rand = new Random();\n        var tolerance = .05;\n        HashSet<int> actual = [];\n        for (var i = 0; i < 5000; i++)\n        {\n            var k = rand.Next(20000);\n            hll1.Add(k);\n            actual.Add(k);\n        }\n\n        for (var i = 0; i < 5000; i++)\n        {\n            var k = rand.Next(20000);\n            hll2.Add(k);\n            actual.Add(k);\n        }\n\n        var hll = HyperLogLog<int>.Merge(hll1, hll2);\n        hll.Cardinality().Should()\n            .BeGreaterOrEqualTo((int)(actual.Count * (1 - tolerance)))\n            .And\n            .BeLessOrEqualTo((int)(actual.Count * (1 + tolerance)));\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Queue/ArrayBasedQueueTests.cs",
    "content": "using DataStructures.Queue;\n\nnamespace DataStructures.Tests.Queue;\n\npublic static class ArrayBasedQueueTests\n{\n    [Test]\n    public static void DequeueWorksCorrectly()\n    {\n        // Arrange\n        var q = new ArrayBasedQueue<char>(3);\n        q.Enqueue('A');\n        q.Enqueue('B');\n        q.Enqueue('C');\n        var result = new StringBuilder();\n\n        // Act\n        for (var i = 0; i < 3; i++)\n        {\n            result.Append(q.Dequeue());\n        }\n\n        // Assert\n        Assert.That(\"ABC\", Is.EqualTo(result.ToString()));\n        Assert.That(q.IsEmpty(), Is.True, \"Queue is empty\");\n        Assert.That(q.IsFull(), Is.False, \"Queue is full\");\n    }\n\n    [Test]\n    public static void PeekWorksCorrectly()\n    {\n        // Arrange\n        var q = new ArrayBasedQueue<int>(2);\n        q.Enqueue(1);\n        q.Enqueue(2);\n        var peeked = 0;\n\n        // Act\n        for (var i = 0; i < 3; i++)\n        {\n            peeked = q.Peek();\n        }\n\n        // Assert\n        Assert.That(1, Is.EqualTo(peeked));\n        Assert.That(q.IsEmpty(), Is.False, \"Queue is empty\");\n        Assert.That(q.IsFull(), Is.True, \"Queue is full\");\n    }\n\n    [Test]\n    public static void DequeueEmptyQueueThrowsInvalidOperationException()\n    {\n        // Arrange\n        var q = new ArrayBasedQueue<int>(1);\n        Exception? exception = null;\n\n        // Act\n        try\n        {\n            q.Dequeue();\n        }\n        catch (Exception ex)\n        {\n            exception = ex;\n        }\n\n        // Assert\n        Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType()));\n    }\n\n    [Test]\n    public static void EnqueueFullQueueThrowsInvalidOperationException()\n    {\n        // Arrange\n        var q = new ArrayBasedQueue<int>(1);\n        q.Enqueue(0);\n        Exception? exception = null;\n\n        // Act\n        try\n        {\n            q.Enqueue(1);\n        }\n        catch (Exception ex)\n        {\n            exception = ex;\n        }\n\n        // Assert\n        Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType()));\n    }\n\n    [Test]\n    public static void PeekEmptyQueueThrowsInvalidOperationException()\n    {\n        // Arrange\n        var q = new ArrayBasedQueue<int>(1);\n        Exception? exception = null;\n\n        // Act\n        try\n        {\n            q.Peek();\n        }\n        catch (Exception ex)\n        {\n            exception = ex;\n        }\n\n        // Assert\n        Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType()));\n    }\n\n    [Test]\n    public static void ClearWorksCorrectly()\n    {\n        // Arrange\n        var q = new ArrayBasedQueue<int>(2);\n        q.Enqueue(1);\n        q.Enqueue(2);\n\n        // Act\n        q.Clear();\n\n        // Assert\n        Assert.That(q.IsEmpty(), Is.True, \"Queue is empty\");\n        Assert.That(q.IsFull(), Is.False, \"Queue is full\");\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Queue/ListBasedQueueTests.cs",
    "content": "using DataStructures.Queue;\n\nnamespace DataStructures.Tests.Queue;\n\npublic static class ListBasedQueueTests\n{\n    [Test]\n    public static void DequeueWorksCorrectly()\n    {\n        // Arrange\n        var q = new ListBasedQueue<char>();\n        q.Enqueue('A');\n        q.Enqueue('B');\n        q.Enqueue('C');\n        var result = new StringBuilder();\n\n        // Act\n        for (var i = 0; i < 3; i++)\n        {\n            result.Append(q.Dequeue());\n        }\n\n        // Assert\n        Assert.That(\"ABC\", Is.EqualTo(result.ToString()));\n        Assert.That(q.IsEmpty(), Is.True, \"Queue is empty\");\n        Assert.That(q.IsFull(), Is.False, \"Queue is full\");\n    }\n\n    [Test]\n    public static void PeekWorksCorrectly()\n    {\n        // Arrange\n        var q = new ListBasedQueue<int>();\n        q.Enqueue(1);\n        q.Enqueue(2);\n        var peeked = 0;\n\n        // Act\n        for (var i = 0; i < 3; i++)\n        {\n            peeked = q.Peek();\n        }\n\n        // Assert\n        Assert.That(1, Is.EqualTo(peeked));\n        Assert.That(q.IsEmpty(), Is.False, \"Queue is empty\");\n        Assert.That(q.IsFull(), Is.False, \"Queue is full\");\n    }\n\n    [Test]\n    public static void DequeueEmptyQueueThrowsInvalidOperationException()\n    {\n        // Arrange\n        var q = new ListBasedQueue<int>();\n        Exception? exception = null;\n\n        // Act\n        try\n        {\n            q.Dequeue();\n        }\n        catch (Exception ex)\n        {\n            exception = ex;\n        }\n\n        // Assert\n        Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType()));\n    }\n\n    [Test]\n    public static void PeekEmptyQueueThrowsInvalidOperationException()\n    {\n        // Arrange\n        var q = new ListBasedQueue<int>();\n        Exception? exception = null;\n\n        // Act\n        try\n        {\n            q.Peek();\n        }\n        catch (Exception ex)\n        {\n            exception = ex;\n        }\n\n        // Assert\n        Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType()));\n    }\n\n    [Test]\n    public static void ClearWorksCorrectly()\n    {\n        // Arrange\n        var q = new ListBasedQueue<int>();\n        q.Enqueue(1);\n        q.Enqueue(2);\n\n        // Act\n        q.Clear();\n\n        // Assert\n        Assert.That(q.IsEmpty(), Is.True, \"Queue is empty\");\n        Assert.That(q.IsFull(), Is.False, \"Queue is full\");\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Queue/StackBasedQueueTests.cs",
    "content": "using DataStructures.Queue;\n\nnamespace DataStructures.Tests.Queue;\n\npublic static class StackBasedQueueTests\n{\n    [Test]\n    public static void DequeueWorksCorrectly()\n    {\n        // Arrange\n        var q = new StackBasedQueue<char>();\n        q.Enqueue('A');\n        q.Enqueue('B');\n        q.Enqueue('C');\n        var result = new StringBuilder();\n\n        // Act\n        for (var i = 0; i < 3; i++)\n        {\n            result.Append(q.Dequeue());\n        }\n\n        // Assert\n        Assert.That(\"ABC\", Is.EqualTo(result.ToString()));\n        Assert.That(q.IsEmpty(), Is.True, \"Queue is empty\");\n        Assert.That(q.IsFull(), Is.False, \"Queue is full\");\n    }\n\n    [Test]\n    public static void PeekWorksCorrectly()\n    {\n        // Arrange\n        var q = new StackBasedQueue<int>();\n        q.Enqueue(1);\n        q.Enqueue(2);\n        var peeked = 0;\n\n        // Act\n        for (var i = 0; i < 3; i++)\n        {\n            peeked = q.Peek();\n        }\n\n        // Assert\n        Assert.That(1, Is.EqualTo(peeked));\n        Assert.That(q.IsEmpty(), Is.False, \"Queue is empty\");\n        Assert.That(q.IsFull(), Is.False, \"Queue is full\");\n    }\n\n    [Test]\n    public static void DequeueEmptyQueueThrowsInvalidOperationException()\n    {\n        // Arrange\n        var q = new StackBasedQueue<int>();\n        Exception? exception = null;\n\n        // Act\n        try\n        {\n            q.Dequeue();\n        }\n        catch (Exception ex)\n        {\n            exception = ex;\n        }\n\n        // Assert\n        Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType()));\n    }\n\n    [Test]\n    public static void PeekEmptyQueueThrowsInvalidOperationException()\n    {\n        // Arrange\n        var q = new StackBasedQueue<int>();\n        Exception? exception = null;\n\n        // Act\n        try\n        {\n            q.Peek();\n        }\n        catch (Exception ex)\n        {\n            exception = ex;\n        }\n\n        // Assert\n        Assert.That(typeof(InvalidOperationException), Is.EqualTo(exception?.GetType()));\n    }\n\n    [Test]\n    public static void ClearWorksCorrectly()\n    {\n        // Arrange\n        var q = new StackBasedQueue<int>();\n        q.Enqueue(1);\n        q.Enqueue(2);\n\n        // Act\n        q.Clear();\n\n        // Assert\n        Assert.That(q.IsEmpty(), Is.True, \"Queue is empty\");\n        Assert.That(q.IsFull(), Is.False, \"Queue is full\");\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/RedBlackTreeTests.cs",
    "content": "using DataStructures.RedBlackTree;\n\nnamespace DataStructures.Tests;\n\ninternal class RedBlackTreeTests\n{\n    [Test]\n    public void Constructor_UseCustomComparer_FormsCorrect_Tree()\n    {\n        var tree = new RedBlackTree<int>(Comparer<int>.Create((x, y) => y.CompareTo(x)));\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.GetMin().Should().Be(10);\n        tree.GetMax().Should().Be(1);\n        tree.GetKeysInOrder().SequenceEqual(new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Add_Case3_FormsCorrectTree()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.Add(5);\n        tree.Count.Should().Be(1);\n    }\n\n    [Test]\n    public void Add_Case24_FormsCorrectTree()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 5, 4, 6, 3 });\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 3, 6 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Add_Case1_FormsCorrectTree()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 5, 4, 6, 3, 7 });\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 3, 6, 7 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Add_Case6_FormsCorrectTree()\n    {\n        // Right rotation\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 5, 4, 6, 3, 2 });\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 3, 2, 4, 6 }).Should().BeTrue();\n\n        // Left rotation\n        tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 5, 4, 6, 7, 8 });\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 7, 6, 8 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Add_Case5_FormsCorrectTree()\n    {\n        // Left-right rotation\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 5, 4, 6, 2, 3 });\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 3, 2, 4, 6 }).Should().BeTrue();\n\n        // Right-left rotation\n        tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 5, 4, 6, 8, 7 });\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 7, 6, 8 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Add_MultipleKeys_FormsCorrectTree()\n    {\n        var tree = new RedBlackTree<int>();\n\n        foreach (var value in new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 })\n        {\n            tree.Add(value);\n            tree.Count.Should().Be(value);\n        }\n\n        tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 4, 2, 1, 3, 6, 5, 8, 7, 9, 10 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Add_KeyAlreadyInTree_ThrowsException()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5 });\n        Assert.Throws<ArgumentException>(() => tree.Add(1));\n    }\n\n    [Test]\n    public void AddRange_MultipleKeys_FormsCorrectTree()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 9, 0, 1, 6, 7, 5, 2, 8, 4, 3 });\n        tree.Count.Should().Be(10);\n        tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 1, 0, 3, 2, 4, 7, 6, 9, 8 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Remove_SimpleCases_TreeStillValid()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 });\n        tree.Remove(6);\n        tree.Count.Should().Be(9);\n        tree.Contains(6).Should().BeFalse();\n        tree.GetKeysInOrder().SequenceEqual(new[] { 1, 8, 11, 13, 15, 17, 22, 25, 27 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 8, 1, 11, 17, 15, 25, 22, 27 }).Should().BeTrue();\n\n        tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 });\n        tree.Remove(1);\n        tree.Count.Should().Be(9);\n        tree.Contains(1).Should().BeFalse();\n        tree.GetKeysInOrder().SequenceEqual(new[] { 6, 8, 11, 13, 15, 17, 22, 25, 27 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 8, 6, 11, 17, 15, 25, 22, 27 }).Should().BeTrue();\n\n        tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 });\n        tree.Remove(17);\n        tree.Count.Should().Be(9);\n        tree.Contains(17).Should().BeFalse();\n        tree.GetKeysInOrder().SequenceEqual(new[] { 1, 6, 8, 11, 13, 15, 22, 25, 27 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 8, 1, 6, 11, 22, 15, 25, 27 }).Should().BeTrue();\n\n        tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 });\n        tree.Remove(25);\n        tree.Count.Should().Be(9);\n        tree.Contains(25).Should().BeFalse();\n        tree.GetKeysInOrder().SequenceEqual(new[] { 1, 6, 8, 11, 13, 15, 17, 22, 27 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 8, 1, 6, 11, 17, 15, 27, 22 }).Should().BeTrue();\n\n        tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 7, 3, 18, 10, 22, 8, 11, 26 });\n        tree.Remove(18);\n        tree.Count.Should().Be(7);\n        tree.Contains(18).Should().BeFalse();\n        tree.GetKeysInOrder().SequenceEqual(new[] { 3, 7, 8, 10, 11, 22, 26 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 7, 3, 22, 10, 8, 11, 26 }).Should().BeTrue();\n\n        tree = new RedBlackTree<int>();\n        tree.Add(1);\n        tree.Add(2);\n        tree.Remove(1);\n        tree.Count.Should().Be(1);\n        tree.GetKeysInOrder().SequenceEqual(new[] { 2 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 2 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Remove_Case1_TreeStillValid()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 5, 2, 8, 1 });\n        tree.Remove(1);\n        tree.Remove(2);\n        tree.Contains(2).Should().BeFalse();\n        tree.GetKeysInOrder().SequenceEqual(new[] { 5, 8 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 8 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Remove_Case3_TreeStillValid()\n    {\n        // Move to case 6\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 7, 3, 18, 1, 10, 22, 8, 11, 26 });\n        tree.Remove(1);\n        tree.Remove(3);\n        tree.Count.Should().Be(7);\n        tree.Contains(3).Should().BeFalse();\n        tree.GetKeysInOrder().SequenceEqual(new[] { 7, 8, 10, 11, 18, 22, 26 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 18, 10, 7, 8, 11, 22, 26 }).Should().BeTrue();\n\n        // Move to case 5\n        tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 8, 3, 2, 0, 9, 4, 7, 6, 1, 5 });\n        tree.Remove(8);\n        tree.Remove(6);\n        tree.Remove(9);\n        tree.Count.Should().Be(7);\n        tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 2, 3, 4, 5, 7 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 3, 1, 0, 2, 5, 4, 7 }).Should().BeTrue();\n\n        // Move to case 4\n        tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 7, 5, 8, 4, 6, 3, 2, 9, 0, 1 });\n        tree.Remove(9);\n        tree.Remove(6);\n        tree.Remove(5);\n        tree.Remove(8);\n        tree.Count.Should().Be(6);\n        tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 2, 3, 4, 7 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 3, 1, 0, 2, 7, 4 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Remove_Case4_TreeStillValid()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 5, 2, 8, 1, 4, 7, 9, 0, 3 });\n        tree.Remove(0);\n        tree.Remove(3);\n        tree.Remove(2);\n        tree.Count.Should().Be(6);\n        tree.Contains(2).Should().BeFalse();\n        tree.GetKeysInOrder().SequenceEqual(new[] { 1, 4, 5, 7, 8, 9 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 5, 4, 1, 8, 7, 9 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Remove_Case5_TreeStillValid()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 });\n        tree.Remove(8);\n        tree.Count.Should().Be(9);\n        tree.Contains(8).Should().BeFalse();\n        tree.GetKeysInOrder().SequenceEqual(new[] { 1, 6, 11, 13, 15, 17, 22, 25, 27 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 6, 1, 11, 17, 15, 25, 22, 27 }).Should().BeTrue();\n\n        tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 0, 6, 22 });\n        tree.Remove(13);\n        tree.Count.Should().Be(9);\n        tree.Contains(13).Should().BeFalse();\n        tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 6, 8, 11, 15, 17, 22, 25 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 15, 8, 1, 0, 6, 11, 22, 17, 25 }).Should().BeTrue();\n\n        tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 7, 0, 1, 4, 8, 2, 3, 6, 5, 9 });\n        tree.Remove(7);\n        tree.Remove(0);\n        tree.Remove(1);\n        tree.Remove(4);\n        tree.Remove(8);\n        tree.GetKeysInOrder().SequenceEqual(new[] { 2, 3, 5, 6, 9 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 3, 2, 6, 5, 9 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Remove_Case6_TreeStillValid()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 6, 22, 27 });\n        tree.Remove(13);\n        tree.Count.Should().Be(9);\n        tree.Contains(13).Should().BeFalse();\n        tree.GetKeysInOrder().SequenceEqual(new[] { 1, 6, 8, 11, 15, 17, 22, 25, 27 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 15, 8, 1, 6, 11, 25, 17, 22, 27 }).Should().BeTrue();\n\n        tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 13, 8, 17, 1, 11, 15, 25, 0, 6, 22 });\n        tree.Remove(8);\n        tree.Count.Should().Be(9);\n        tree.Contains(8).Should().BeFalse();\n        tree.GetKeysInOrder().SequenceEqual(new[] { 0, 1, 6, 11, 13, 15, 17, 22, 25 }).Should().BeTrue();\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 13, 1, 0, 11, 6, 17, 15, 25, 22 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void Remove_EmptyTree_ThrowsException()\n    {\n        var tree = new RedBlackTree<int>();\n        Assert.Throws<InvalidOperationException>(() => tree.Remove(1));\n    }\n\n    [Test]\n    public void Remove_KeyNotInTree_ThrowsException()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        Assert.Throws<KeyNotFoundException>(() => tree.Remove(24));\n    }\n\n    [Test]\n    public void Contains_CorrectReturn()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.Contains(3).Should().BeTrue();\n        tree.Contains(7).Should().BeTrue();\n        tree.Contains(24).Should().BeFalse();\n        tree.Contains(-1).Should().BeFalse();\n    }\n\n    [Test]\n    public void Contains_EmptyTree_ReturnsFalse()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.Contains(5).Should().BeFalse();\n        tree.Contains(-12).Should().BeFalse();\n    }\n\n    [Test]\n    public void GetMin_CorrectReturn()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.GetMin().Should().Be(1);\n    }\n\n    [Test]\n    public void GetMin_EmptyTree_ThrowsException()\n    {\n        var tree = new RedBlackTree<int>();\n        Assert.Throws<InvalidOperationException>(() => tree.GetMin());\n    }\n\n    [Test]\n    public void GetMax_CorrectReturn()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.GetMax().Should().Be(10);\n    }\n\n    [Test]\n    public void GetMax_EmptyTree_ThrowsException()\n    {\n        var tree = new RedBlackTree<int>();\n        Assert.Throws<InvalidOperationException>(() => tree.GetMax());\n    }\n\n    [Test]\n    public void GetKeysInOrder_CorrectReturn()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.GetKeysInOrder().SequenceEqual(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void GetKeysInOrder_EmptyTree_CorrectReturn()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.GetKeysInOrder().SequenceEqual(Array.Empty<int>()).Should().BeTrue();\n    }\n\n    [Test]\n    public void GetKeysPreOrder_CorrectReturn()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.GetKeysPreOrder().SequenceEqual(new[] { 4, 2, 1, 3, 6, 5, 8, 7, 9, 10 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void GetKeysPreOrder_EmptyTree_CorrectReturn()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.GetKeysPreOrder().SequenceEqual(Array.Empty<int>()).Should().BeTrue();\n    }\n\n    [Test]\n    public void GetKeysPostOrder_CorrectReturn()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.AddRange(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });\n        tree.GetKeysPostOrder().SequenceEqual(new[] { 1, 3, 2, 5, 7, 10, 9, 8, 6, 4 }).Should().BeTrue();\n    }\n\n    [Test]\n    public void GetKeysPostOrder_EmptyTree_CorrectReturn()\n    {\n        var tree = new RedBlackTree<int>();\n        tree.GetKeysPostOrder().SequenceEqual(Array.Empty<int>()).Should().BeTrue();\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/ScapegoatTree/ExtensionsTests.cs",
    "content": "using DataStructures.ScapegoatTree;\n\nnamespace DataStructures.Tests.ScapegoatTree;\n\npublic class ExtensionsTests\n{\n    [Test]\n    public void RebuildFlatTree_ValidFlatTree_RebuildsTree()\n    {\n        var expected = new Node<int>(3)\n        {\n            Left = new Node<int>(1)\n            {\n                Left = new Node<int>(-1),\n                Right = new Node<int>(2),\n            },\n            Right = new Node<int>(6)\n            {\n                Left = new Node<int>(5),\n            },\n        };\n\n\n        var list = new List<Node<int>>\n        {\n            new(-1),\n            new(1),\n            new(2),\n            new(3),\n            new(5),\n            new(6),\n        };\n\n        var tree = Extensions.RebuildFromList(list, 0, list.Count - 1);\n\n        Assert.That(list.Count, Is.EqualTo(tree.GetSize()));\n        Assert.That(expected.Key, Is.EqualTo(tree.Key));\n        Assert.That(tree.Left, Is.Not.Null);\n        Assert.That(tree.Right, Is.Not.Null);\n        Assert.That(expected.Left.Key, Is.EqualTo(tree.Left!.Key));\n        Assert.That(expected.Right.Key, Is.EqualTo(tree.Right!.Key));\n        Assert.That(tree.Left.Left, Is.Not.Null);\n        Assert.That(tree.Left.Right, Is.Not.Null);\n        Assert.That(expected.Left.Left.Key, Is.EqualTo(tree.Left!.Left!.Key));\n        Assert.That(expected.Left.Right.Key, Is.EqualTo(tree.Left!.Right!.Key));\n        Assert.That(tree.Right.Left, Is.Not.Null);\n        Assert.That(expected.Right.Left.Key, Is.EqualTo(tree.Right!.Left!.Key));\n    }\n\n    [Test]\n    public void RebuildFromList_RangeIsInvalid_ThrowsException()\n    {\n        Assert.Throws<ArgumentException>(() => Extensions.RebuildFromList(new List<Node<int>>(), 1, 0));\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/ScapegoatTree/ScapegoatTreeNodeTests.cs",
    "content": "using DataStructures.ScapegoatTree;\n\nnamespace DataStructures.Tests.ScapegoatTree;\n\n[TestFixture]\npublic class ScapegoatTreeNodeTests\n{\n    [TestCase(2, 1)]\n    [TestCase(\"B\", \"A\")]\n    public void RightSetter_OtherKeyPrecedesRightKey_ThrowsException<TKey>(TKey a, TKey b)\n        where TKey : IComparable\n    {\n        var instance = new Node<TKey>(a);\n        var other = new Node<TKey>(b);\n\n        Assert.Throws<ArgumentException>(() => instance.Right = other);\n    }\n\n    [TestCase(1, 2)]\n    [TestCase(\"A\", \"B\")]\n    public void RightSetter_OtherKeyFollowsRightKey_AddsChild<TKey>(TKey a, TKey b)\n        where TKey : IComparable\n    {\n        var instance = new Node<TKey>(a);\n        var other = new Node<TKey>(b);\n\n        Assert.DoesNotThrow(() => instance.Right = other);\n    }\n\n    [TestCase(1, 2)]\n    [TestCase(\"A\", \"B\")]\n    public void LeftSetter_OtherKeyFollowsLeftKey_ThrowsException<TKey>(TKey a, TKey b)\n        where TKey : IComparable\n    {\n        var instance = new Node<TKey>(a);\n        var other = new Node<TKey>(b);\n\n        Assert.Throws<ArgumentException>(() => instance.Left = other);\n    }\n\n    [TestCase(2, 1)]\n    [TestCase(\"B\", \"A\")]\n    public void LeftSetter_OtherKeyPrecedesLeftKey_AddsChild<TKey>(TKey a, TKey b)\n        where TKey : IComparable\n    {\n        var instance = new Node<TKey>(a);\n        var other = new Node<TKey>(b);\n\n        Assert.DoesNotThrow(() => instance.Left = other);\n    }\n\n    [TestCase(1, 2)]\n    [TestCase(\"A\", \"B\")]\n    public void CompareTo_InstanceKeyPrecedesOtherKey_ReturnsMinusOne<TKey>(TKey a, TKey b)\n        where TKey : IComparable\n    {\n        var instance = new Node<TKey>(a);\n        var other = new Node<TKey>(b);\n\n        var result = instance.Key.CompareTo(other.Key);\n\n        Assert.That(result, Is.EqualTo(-1));\n    }\n\n    [TestCase(2, 1)]\n    [TestCase(\"B\", \"A\")]\n    public void CompareTo_InstanceKeyFollowsOtherKey_ReturnsOne<TKey>(TKey a, TKey b)\n        where TKey : IComparable\n    {\n        var instance = new Node<TKey>(a);\n        var other = new Node<TKey>(b);\n\n        var result = instance.Key.CompareTo(other.Key);\n\n        Assert.That(1, Is.EqualTo(result));\n    }\n\n    [TestCase(1, 1)]\n    [TestCase(\"A\", \"A\")]\n    public void CompareTo_InstanceKeyEqualsOtherKey_ReturnsZero<TKey>(TKey a, TKey b)\n        where TKey : IComparable\n    {\n        var instance = new Node<TKey>(a);\n        var other = new Node<TKey>(b);\n\n        var result = instance.Key.CompareTo(other.Key);\n\n        Assert.That(0, Is.EqualTo(result));\n    }\n\n    [Test]\n    public void GetSize_NodeHasNoChildren_ReturnsOne()\n    {\n        var node = new Node<int>(1);\n\n        Assert.That(1, Is.EqualTo(node.GetSize()));\n    }\n\n    [Test]\n    public void GetSize_NodeHasChildren_ReturnsCorrectSize()\n    {\n        var node = new Node<int>(1, new Node<int>(2), new Node<int>(0));\n\n        Assert.That(3, Is.EqualTo(node.GetSize()));\n    }\n\n    [Test]\n    public void GetSmallestKeyNode_NodeHasNoLeftChildren_ReturnsNode()\n    {\n        var node = new Node<int>(1);\n\n        Assert.That(node, Is.EqualTo(node.GetSmallestKeyNode()));\n    }\n\n    [Test]\n    public void GetSmallestKeyNode_NodeHasSmallestChild_ReturnsChild()\n    {\n        var node = new Node<int>(1);\n        var smaller = new Node<int>(0);\n        var smallest = new Node<int>(-1);\n        node.Left = smaller;\n        smaller.Left = smallest;\n\n        Assert.That(smallest, Is.EqualTo(node.GetSmallestKeyNode()));\n    }\n\n    [Test]\n    public void GetLargestKeyNode_NodeHasNoRightChildren_ReturnsNode()\n    {\n        var node = new Node<int>(1);\n\n        Assert.That(node, Is.EqualTo(node.GetLargestKeyNode()));\n    }\n\n    [Test]\n    public void GetLargestKeyNode_NodeHasLargestChild_ReturnsChild()\n    {\n        var node = new Node<int>(1);\n        var larger = new Node<int>(2);\n        var largest = new Node<int>(3);\n        node.Right = larger;\n        larger.Right = largest;\n\n        Assert.That(largest, Is.EqualTo(node.GetLargestKeyNode()));\n    }\n\n    [Test]\n    public void IsAlphaWeightBalanced_TreeIsUnbalanced_ReturnsFalse()\n    {\n        var root = new Node<int>(0);\n        var a = new Node<int>(-1);\n        var b = new Node<int>(-2);\n        var c = new Node<int>(-3);\n        var d = new Node<int>(1);\n\n        root.Left = a;\n        a.Left = b;\n        b.Left = c;\n        root.Right = d;\n\n        Assert.That(root.IsAlphaWeightBalanced(0.5), Is.False);\n    }\n\n    [Test]\n    public void IsAlphaWeightBalanced_TreeIsBalanced_ReturnsTrue()\n    {\n        var root = new Node<int>(0);\n        var a = new Node<int>(-1);\n        var b = new Node<int>(-2);\n        var d = new Node<int>(1);\n\n        root.Left = a;\n        a.Left = b;\n        root.Right = d;\n\n        Assert.That(root.IsAlphaWeightBalanced(0.5), Is.True);\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/ScapegoatTree/ScapegoatTreeTests.cs",
    "content": "using DataStructures.ScapegoatTree;\n\nnamespace DataStructures.Tests.ScapegoatTree;\n\npublic class ScapegoatTreeTests\n{\n    [Test]\n    public void Constructor_NoParameters_InstanceIsValid()\n    {\n        var tree = new ScapegoatTree<int>();\n\n        Assert.That(tree.Root, Is.Null);\n        Assert.That(tree.Size == 0, Is.True);\n        Assert.That(tree.MaxSize == 0, Is.True);\n        Assert.That(tree.Alpha, Is.EqualTo(0.5));\n    }\n\n    [Test]\n    public void Constructor_AlphaParameter_InstanceIsValid()\n    {\n        var expected = 0.6;\n\n        var tree = new ScapegoatTree<int>(expected);\n\n        Assert.That(tree.Root, Is.Null);\n        Assert.That(tree.Size == 0, Is.True);\n        Assert.That(tree.MaxSize == 0, Is.True);\n        Assert.That(tree.Alpha, Is.EqualTo(expected));\n    }\n\n    [TestCase(1.1)]\n    [TestCase(0.4)]\n    public void Constructor_AlphaParameterIsInvalid_ThrowsException(double alpha)\n    {\n        Assert.Throws<ArgumentException>(() => new ScapegoatTree<int>(alpha));\n        Assert.Throws<ArgumentException>(() => new ScapegoatTree<int>(1, alpha));\n    }\n\n    [Test]\n    public void Constructor_KeyParameter_InstanceIsValid()\n    {\n        var expected = 10;\n\n        var tree = new ScapegoatTree<int>(expected);\n\n        Assert.That(tree.Root, Is.Not.Null);\n        Assert.That(tree.Root!.Key == expected, Is.True);\n        Assert.That(tree.Size == 1, Is.True);\n        Assert.That(tree.MaxSize == 1, Is.True);\n        Assert.That(tree.Alpha, Is.EqualTo(0.5));\n    }\n\n    [Test]\n    public void Constructor_KeyAndAlphaParameters_InstanceIsValid()\n    {\n        var key = 10;\n        var alpha = 0.8;\n\n        var tree = new ScapegoatTree<int>(key, alpha);\n\n        Assert.That(tree.Root, Is.Not.Null);\n        Assert.That(tree.Size == 1, Is.True);\n        Assert.That(tree.MaxSize == 1, Is.True);\n        Assert.That(tree.Alpha, Is.EqualTo(alpha));\n    }\n\n    [Test]\n    public void Constructor_NodeAndAlphaParameters_InstanceIsValid()\n    {\n        var node = new Node<int>(10, new Node<int>(11), new Node<int>(1));\n        var alpha = 0.8;\n\n        var tree = new ScapegoatTree<int>(node, alpha);\n\n        Assert.That(tree.Root, Is.Not.Null);\n        Assert.That(tree.Size == 3, Is.True);\n        Assert.That(tree.MaxSize == 3, Is.True);\n        Assert.That(tree.Alpha, Is.EqualTo(alpha));\n    }\n\n    [Test]\n    public void IsAlphaWeightBalanced_RootIsNull_ReturnsTrue()\n    {\n        var tree = new ScapegoatTree<int>();\n\n        var result = tree.IsAlphaWeightBalanced();\n\n        Assert.That(result, Is.True);\n    }\n\n    [Test]\n    public void Search_RootIsNull_ReturnsNull()\n    {\n        var tree = new ScapegoatTree<int>();\n\n        var result = tree.Search(1);\n\n        Assert.That(result, Is.Null);\n    }\n\n    [Test]\n    public void Search_KeyIsPresent_ReturnsKey()\n    {\n        var tree = new ScapegoatTree<int>(key: 1);\n\n        var result = tree.Search(1);\n\n        Assert.That(result, Is.Not.Null);\n        Assert.That(result!.Key, Is.EqualTo(1));\n    }\n\n    [TestCase(-2)]\n    [TestCase(3)]\n    public void Search_KeyIsNotPresent_ReturnsNull(int key)\n    {\n        var root = new Node<int>(1, new Node<int>(2), new Node<int>(-1));\n\n        var tree = new ScapegoatTree<int>(root, 0.5);\n\n        var result = tree.Search(key);\n\n        Assert.That(result, Is.Null);\n    }\n\n    [Test]\n    public void Insert_RootIsNull_InsertsRoot()\n    {\n        var tree = new ScapegoatTree<int>();\n\n        var inserted = tree.Insert(1);\n\n        Assert.That(inserted, Is.True);\n        Assert.That(tree.Root, Is.Not.Null);\n        Assert.That(tree.Root!.Key, Is.EqualTo(1));\n        Assert.That(tree.Size, Is.EqualTo(1));\n        Assert.That(tree.MaxSize, Is.EqualTo(1));\n    }\n\n    [Test]\n    public void Delete_RootIsNull_ReturnsFalse()\n    {\n        var tree = new ScapegoatTree<int>();\n\n        var deleted = tree.Delete(1);\n\n        Assert.That(deleted, Is.False);\n    }\n\n    [Test]\n    public void Delete_KeyIsNotPresent_ReturnsFalse()\n    {\n        var tree = new ScapegoatTree<int>(1);\n\n        var deleted = tree.Delete(2);\n\n        Assert.That(deleted, Is.False);\n        Assert.That(tree.Size, Is.EqualTo(1));\n    }\n\n    [Test]\n    public void Insert_KeyIsPresent_ReturnsFalse()\n    {\n        var tree = new ScapegoatTree<int>(1);\n\n        var inserted = tree.Insert(1);\n\n        Assert.That(inserted, Is.False);\n        Assert.That(tree.Size, Is.EqualTo(1));\n        Assert.That(tree.MaxSize, Is.EqualTo(1));\n    }\n\n    [Test]\n    public void Remove_KeyIsPresent_RemovesKey()\n    {\n        var tree = new ScapegoatTree<int>(1);\n\n        var inserted = tree.Insert(2);\n\n        Assert.That(inserted, Is.True);\n\n        var deleted = tree.Delete(2);\n\n        Assert.That(deleted, Is.True);\n        Assert.That(tree.Size, Is.EqualTo(1));\n    }\n\n    [Test]\n    public void Remove_KeyIsRootWithNoChildren_RemovesKey()\n    {\n        var tree = new ScapegoatTree<int>(1);\n\n        var deleted = tree.Delete(1);\n\n        Assert.That(deleted, Is.True);\n        Assert.That(tree.Root, Is.Null);\n        Assert.That(tree.Size, Is.EqualTo(0));\n    }\n\n    [Test]\n    public void Remove_KeyIsRootWithOneLeftChild_RemovesKey()\n    {\n        var tree = new ScapegoatTree<int>(1);\n\n        var inserted = tree.Insert(-1);\n\n        Assert.That(inserted, Is.True);\n\n        var deleted = tree.Delete(1);\n\n        Assert.That(deleted, Is.True);\n        Assert.That(tree.Size, Is.EqualTo(1));\n    }\n\n    [Test]\n    public void Remove_KeyIsRootWithOneRightChild_RemovesKey()\n    {\n        var tree = new ScapegoatTree<int>(1);\n\n        var inserted = tree.Insert(2);\n\n        Assert.That(inserted, Is.True);\n\n        var deleted = tree.Delete(1);\n\n        Assert.That(deleted, Is.True);\n        Assert.That(tree.Size, Is.EqualTo(1));\n    }\n\n    [Test]\n    public void Remove_KeyIsRootWithTwoChildren_RemovesKey()\n    {\n        var tree = new ScapegoatTree<int>(1);\n\n        var inserted = tree.Insert(-1);\n\n        Assert.That(inserted, Is.True);\n\n        inserted = tree.Insert(2);\n\n        Assert.That(inserted, Is.True);\n\n        var deleted = tree.Delete(1);\n\n        Assert.That(deleted, Is.True);\n        Assert.That(tree.Size, Is.EqualTo(2));\n    }\n\n    [Test]\n    public void Insert_KeyIsNotPresent_KeyIsInserted()\n    {\n        var tree = new ScapegoatTree<int>(1);\n\n        var inserted = tree.Insert(2);\n\n        Assert.That(inserted, Is.True);\n        Assert.That(tree.Size, Is.EqualTo(2));\n        Assert.That(tree.MaxSize, Is.EqualTo(2));\n    }\n\n    [TestCase(3, new[] { 2, 5, 1, 6 }, -1, 0.5)]\n    public void Insert_TreeIsUnbalanced_RebuildsTree(int root, int[] keys, int candidate, double alpha)\n    {\n        var tree = new ScapegoatTree<int>(root, alpha);\n\n        tree.TreeIsUnbalanced += FailTreeIsUnbalanced;\n\n        foreach (var item in keys)\n        {\n            Assert.DoesNotThrow(() => tree.Insert(item));\n        }\n\n        tree.TreeIsUnbalanced -= FailTreeIsUnbalanced;\n        tree.TreeIsUnbalanced += PassTreeIsUnbalanced;\n\n        Assert.Throws<SuccessException>(() => tree.Insert(candidate));\n    }\n\n    [TestCase(20, new[] { 10, 30, 5, 11, 29, 40, 50, 1, 12 }, new[] { 50, 40, 30, 29 }, 0.7)]\n    public void Delete_TreeIsUnbalanced_BalancesTree(int root, int[] keys, int[] candidates, double alpha)\n    {\n        var tree = new ScapegoatTree<int>(root, alpha);\n\n        tree.TreeIsUnbalanced += FailTreeIsUnbalanced;\n\n        foreach (var item in keys)\n        {\n            Assert.DoesNotThrow(() => tree.Insert(item));\n        }\n\n        tree.TreeIsUnbalanced -= FailTreeIsUnbalanced;\n        tree.TreeIsUnbalanced += PassTreeIsUnbalanced;\n\n        Assert.Throws<SuccessException>(() =>\n        {\n            foreach (var item in candidates)\n            {\n                tree.Delete(item);\n            }\n        });\n    }\n\n    [TestCase(20, new[] { 10, 30, 5, 11, 29, 40, 50 }, 10, 1)]\n    public void Delete_TreeIsUnbalanced_MaxSizeEqualsSize(int root, int[] keys, int candidate, double alpha)\n    {\n        var tree = new ScapegoatTree<int>(root, alpha);\n\n        tree.TreeIsUnbalanced += FailTreeIsUnbalanced;\n\n        foreach (var item in keys)\n        {\n            Assert.DoesNotThrow(() => tree.Insert(item));\n        }\n\n        tree.TreeIsUnbalanced -= FailTreeIsUnbalanced;\n\n        tree.Delete(candidate);\n\n        Assert.That(tree.MaxSize, Is.EqualTo(tree.Size));\n    }\n\n    [TestCase(3, new[] { 2, 5, 1, 6 }, -1, 0.5)]\n    [TestCase(3, new[] { 2, 5, 1, 6 }, 7, 0.5)]\n    public void Insert_TreeIsUnbalanced_BalancesTree(int root, int[] keys, int candidate, double alpha)\n    {\n        var tree = new ScapegoatTree<int>(root, alpha);\n\n        tree.TreeIsUnbalanced += FailTreeIsUnbalanced;\n\n        foreach (var item in keys)\n        {\n            Assert.DoesNotThrow(() => tree.Insert(item));\n        }\n\n        tree.TreeIsUnbalanced -= FailTreeIsUnbalanced;\n\n        var inserted = tree.Insert(candidate);\n\n        Assert.That(inserted, Is.True);\n        Assert.That(tree.Size == 6, Is.True);\n        Assert.That(tree.IsAlphaWeightBalanced(), Is.True);\n    }\n\n    [TestCase(3, 5, 0.5)]\n    public void Insert_TreeIsUnbalanced_BalancesTree2(int root, int candidate, double alpha)\n    {\n        var tree = new ScapegoatTree<int>(root, alpha);\n\n        var inserted = tree.Insert(candidate);\n\n        Assert.That(inserted, Is.True);\n        Assert.That(tree.Size == 2, Is.True);\n        Assert.That(tree.IsAlphaWeightBalanced(), Is.True);\n    }\n\n    [Test]\n    public void Contains_RootIsNull_ReturnsFalse()\n    {\n        var tree = new ScapegoatTree<int>();\n\n        Assert.That(tree.Contains(1), Is.False);\n    }\n\n    [Test]\n    public void Contains_RootHasKey_ReturnsTrue()\n    {\n        var tree = new ScapegoatTree<int>(1);\n\n        Assert.That(tree.Contains(1), Is.True);\n    }\n\n    [Test]\n    public void Contains_TreeHasKey_ReturnsTrue()\n    {\n        var tree = new ScapegoatTree<int>(1);\n\n        tree.Insert(2);\n\n        Assert.That(tree.Contains(2), Is.True);\n    }\n\n    [Test]\n    public void Contains_TreeDoesNotContainKey_ReturnsFalse()\n    {\n        var tree = new ScapegoatTree<int>(1);\n\n        tree.Insert(2);\n\n        Assert.That(tree.Contains(-1), Is.False);\n    }\n\n    [Test]\n    public void Clear_TreeHasKeys_ClearsTree()\n    {\n        var tree = new ScapegoatTree<int>(1);\n\n        tree.Clear();\n\n        Assert.That(tree.Size == 0, Is.True);\n        Assert.That(tree.MaxSize == 0, Is.True);\n        Assert.That(tree.Root, Is.Null);\n    }\n\n    [Test]\n    public void Tune_AlphaIsValid_ChangesAlpha()\n    {\n        var expected = 0.7;\n\n        var tree = new ScapegoatTree<int>();\n\n        tree.Tune(expected);\n\n        Assert.That(tree.Alpha, Is.EqualTo(expected));\n    }\n\n    [Test]\n    public void Tune_AlphaIsNotValid_ThrowsException()\n    {\n        var expected = 9.9;\n\n        var tree = new ScapegoatTree<int>();\n\n        Assert.Throws<ArgumentException>(() => tree.Tune(expected));\n    }\n\n    [Test]\n    public void FindScapegoatInPath_PathIsEmpty_ThrowsAnException()\n    {\n        var tree = new ScapegoatTree<int>();\n        Assert.Throws<ArgumentException>(() => tree.FindScapegoatInPath(new Stack<Node<int>>()));\n    }\n\n    [Test]\n    public void FindScapegoatInPath_ScapegoatIsNotPresent_ThrowsAnException()\n    {\n        var tree = new ScapegoatTree<int>(1, 1);\n        var path = new Stack<Node<int>>();\n        path.Push(tree.Root!);\n        Assert.Throws<InvalidOperationException>(() => tree.FindScapegoatInPath(path));\n    }\n\n    private static void FailTreeIsUnbalanced(object? sender, EventArgs? e)\n    {\n        Assert.Fail();\n    }\n\n    private static void PassTreeIsUnbalanced(object? sender, EventArgs? e)\n    {\n        Assert.Pass();\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/SegmentTrees/SegmentTreeApplyTests.cs",
    "content": "using DataStructures.SegmentTrees;\n\nnamespace DataStructures.Tests.SegmentTrees;\n\n[TestFixture]\npublic class SegmentTreeApplyTests\n{\n    private readonly SegmentTreeApply testTree = new([8, 9, 1, 4, 8, 7, 2]);\n\n    [Test]\n    public void Apply_Query_Update_Query_Test()\n    {\n        Assert.That(testTree.Query(1, 4), Is.EqualTo(22));\n        testTree.Apply(0, 3, 2);\n        Assert.That(testTree.Operand, Is.EqualTo(new[] { 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }));\n        Assert.That(testTree.Query(1, 4), Is.EqualTo(36));\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/SegmentTrees/SegmentTreeTests.cs",
    "content": "using DataStructures.SegmentTrees;\n\nnamespace DataStructures.Tests.SegmentTrees;\n\n[TestFixture]\npublic class SegmentTreeTests\n{\n    private readonly SegmentTree testTree = new([8, 9, 1, 4, 8, 7, 2]);\n\n    [Test]\n    public void TreeArray_Test()\n    {\n        int[] expectedArray = [0, 39, 22, 17, 17, 5, 15, 2, 8, 9, 1, 4, 8, 7, 2, 0];\n        Assert.That(testTree.Tree, Is.EqualTo(expectedArray));\n    }\n\n    [TestCase(1, 4, 22)]\n    [TestCase(2, 2, 1)]\n    public void Query_Test(int left, int right, int expectedValue)\n    {\n        Assert.That(testTree.Query(left, right), Is.EqualTo(expectedValue));\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/SegmentTrees/SegmentTreeUpdateTest.cs",
    "content": "using DataStructures.SegmentTrees;\n\nnamespace DataStructures.Tests.SegmentTrees;\n\n[TestFixture]\npublic class SegmentTreeUpdateTests\n{\n    [SetUp]\n    public void Init()\n    {\n        testTree = new SegmentTreeUpdate([8, 9, 1, 4, 8, 7, 2]);\n    }\n\n    private SegmentTreeUpdate testTree = new([8, 9, 1, 4, 8, 7, 2]);\n\n    [TestCase(2, 3, 1, 4, 24)]\n    [TestCase(0, 3, 1, 4, 22)]\n    public void Update_Test(int node, int value, int left, int right, int aftQuery)\n    {\n        testTree.Update(node, value);\n        Assert.That(aftQuery, Is.EqualTo(testTree.Query(left, right)));\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/SortedListTests.cs",
    "content": "namespace DataStructures.Tests;\n\n[TestFixture]\npublic class SortedListTests\n{\n    [Test]\n    public void Add_AddMultipleValues_SortingCorrectly(\n        [Random(1, 1000, 100, Distinct = true)]\n        int count)\n    {\n        var values = GetValues(count);\n        var list = new SortedList<int>();\n\n        foreach (var value in values)\n        {\n            list.Add(value);\n        }\n\n        Assert.That(list, Is.EqualTo(values.OrderBy(i => i)));\n    }\n\n    [Test]\n    public void Contains_PositiveArrayAdded_NegativeNumberAsked_FalseReturned(\n        [Random(1, 200, 10, Distinct = true)] int count)\n    {\n        var values = GetValues(count);\n        const int value = -1;\n\n        var list = new SortedList<int>();\n\n        foreach (var i in values)\n        {\n            list.Add(i);\n        }\n\n        Assert.That(list.Contains(value), Is.False);\n    }\n\n    [Test]\n    public void Contains_PositiveArrayAdded_ContainingValueAsked_TrueReturned(\n        [Random(1, 200, 10, Distinct = true)] int count)\n    {\n        var values = GetValues(count);\n        var value = values[TestContext.CurrentContext.Random.Next(count - 1)];\n\n        var list = new SortedList<int>();\n\n        foreach (var i in values)\n        {\n            list.Add(i);\n        }\n\n        Assert.That(list.Contains(value), Is.True);\n    }\n\n\n    [Test]\n    public void Remove_PositiveArrayAdded_NegativeNumberAsked_FalseReturned(\n        [Random(1, 200, 10, Distinct = true)] int count)\n    {\n        var values = GetValues(count);\n        const int value = -1;\n\n        var list = new SortedList<int>();\n\n        foreach (var i in values)\n        {\n            list.Add(i);\n        }\n\n        Assert.That(list.TryRemove(value), Is.False);\n    }\n\n    [Test]\n    public void Remove_PositiveArrayAdded_ContainingValueAsked_TrueReturned(\n        [Random(1, 200, 10, Distinct = true)] int count)\n    {\n        var values = GetValues(count);\n        var value = values[TestContext.CurrentContext.Random.Next(count - 1)];\n\n        var list = new SortedList<int>();\n\n        foreach (var i in values)\n        {\n            list.Add(i);\n        }\n\n        var expectingValues = values\n            .OrderBy(i => i)\n            .ToList();\n\n        expectingValues.Remove(value);\n\n        Assert.That(list.TryRemove(value), Is.True);\n        Assert.That(list, Is.EqualTo(expectingValues));\n    }\n\n    [Test]\n    public void Clear_ArrayAdded_ListCleaned_ListIsEmpty(\n        [Random(1, 20, 1, Distinct = true)] int count)\n    {\n        var values = GetValues(count);\n\n        var list = new SortedList<int>();\n\n        foreach (var i in values)\n        {\n            list.Add(i);\n        }\n\n        list.Clear();\n\n        Assert.That(list, Is.Empty);\n    }\n\n    private static List<int> GetValues(int count)\n        => Enumerable\n            .Range(0, count)\n            .Select(_ => TestContext.CurrentContext.Random.Next(1_000_000))\n            .ToList();\n}\n"
  },
  {
    "path": "DataStructures.Tests/Stack/ArrayBasedStackTests.cs",
    "content": "using DataStructures.Stack;\r\n\r\nnamespace DataStructures.Tests.Stack;\r\n\r\npublic static class ArrayBasedStackTests\r\n{\r\n    private const string StackEmptyErrorMessage = \"Stack is empty\";\r\n\r\n    [Test]\r\n    public static void CountTest()\r\n    {\r\n        var stack = new ArrayBasedStack<int>([0, 1, 2, 3, 4]);\r\n        stack.Top.Should().Be(4);\r\n    }\r\n\r\n    [Test]\r\n    public static void ClearTest()\r\n    {\r\n        var stack = new ArrayBasedStack<int>([0, 1, 2, 3, 4]);\r\n\r\n        stack.Clear();\r\n\r\n        stack.Top.Should().Be(-1);\r\n    }\r\n\r\n    [Test]\r\n    public static void ContainsTest()\r\n    {\r\n        var stack = new ArrayBasedStack<int>([0, 1, 2, 3, 4]);\r\n\r\n        Assert.Multiple(() =>\r\n        {\r\n            stack.Contains(0).Should().BeTrue();\r\n            stack.Contains(1).Should().BeTrue();\r\n            stack.Contains(2).Should().BeTrue();\r\n            stack.Contains(3).Should().BeTrue();\r\n            stack.Contains(4).Should().BeTrue();\r\n        });\r\n    }\r\n\r\n    [Test]\r\n    public static void PeekTest()\r\n    {\r\n        var stack = new ArrayBasedStack<int>([0, 1, 2, 3, 4]);\r\n\r\n        Assert.Multiple(() =>\r\n        {\r\n            stack.Peek().Should().Be(4);\r\n            stack.Peek().Should().Be(4);\r\n            stack.Peek().Should().Be(4);\r\n        });\r\n    }\r\n\r\n    [Test]\r\n    public static void PopTest()\r\n    {\r\n        var stack = new ArrayBasedStack<int>([0, 1, 2, 3, 4]);\r\n\r\n        Assert.Multiple(() =>\r\n        {\r\n            stack.Pop().Should().Be(4);\r\n            stack.Pop().Should().Be(3);\r\n            stack.Pop().Should().Be(2);\r\n            stack.Pop().Should().Be(1);\r\n            stack.Pop().Should().Be(0);\r\n        });\r\n    }\r\n\r\n    [Test]\r\n    public static void PushTest()\r\n    {\r\n        var stack = new ArrayBasedStack<int>();\r\n\r\n        Assert.Multiple(() =>\r\n            Enumerable.Range(0, 5)\r\n                .ToList()\r\n                .ForEach(number =>\r\n                {\r\n                    stack.Push(number);\r\n                    stack.Peek().Should().Be(number);\r\n                }));\r\n    }\r\n\r\n    [Test]\r\n    public static void AutomaticResizesTest()\r\n    {\r\n        const int initialCapacity = 2;\r\n        var stack = new ArrayBasedStack<int>\r\n        {\r\n            Capacity = initialCapacity,\r\n        };\r\n\r\n        stack.Push(0);\r\n        stack.Push(1);\r\n        stack.Push(2);\r\n        stack.Push(3);\r\n        stack.Push(4);\r\n\r\n        stack.Capacity.Should().BeGreaterThan(initialCapacity);\r\n    }\r\n\r\n    [Test]\r\n    public static void ShouldThrowStackEmptyExceptionOnEmptyPopTest()\r\n    {\r\n        var stack = new ArrayBasedStack<int>();\r\n\r\n        Action poppingAnEmptyStack = () => stack.Pop();\r\n\r\n        poppingAnEmptyStack.Should()\r\n            .Throw<InvalidOperationException>()\r\n            .WithMessage(StackEmptyErrorMessage);\r\n\r\n    }\r\n\r\n    [Test]\r\n    public static void ShouldThrowStackEmptyExceptionOnEmptyPeekTest()\r\n    {\r\n        var stack = new ArrayBasedStack<int>();\r\n\r\n        Action peekingAnEmptyStack = () => stack.Peek();\r\n\r\n        peekingAnEmptyStack.Should()\r\n            .Throw<InvalidOperationException>()\r\n            .WithMessage(StackEmptyErrorMessage);\r\n    }\r\n}\r\n"
  },
  {
    "path": "DataStructures.Tests/Stack/ListBasedStackTests.cs",
    "content": "using DataStructures.Stack;\r\n\r\nnamespace DataStructures.Tests.Stack;\r\n\r\npublic static class ListBasedStackTests\r\n{\r\n    [Test]\r\n    public static void CountTest()\r\n    {\r\n        var stack = new ListBasedStack<int>([0, 1, 2, 3, 4]);\r\n        stack.Count.Should().Be(5);\r\n    }\r\n\r\n    [Test]\r\n    public static void ClearTest()\r\n    {\r\n        var stack = new ListBasedStack<int>([0, 1, 2, 3, 4]);\r\n        stack.Clear();\r\n        stack.Count.Should().Be(0);\r\n    }\r\n\r\n    [Test]\r\n    public static void ContainsTest()\r\n    {\r\n        var stack = new ListBasedStack<int>([0, 1, 2, 3, 4]);\r\n\r\n        Assert.Multiple(() =>\r\n        {\r\n            stack.Contains(0).Should().BeTrue();\r\n            stack.Contains(1).Should().BeTrue();\r\n            stack.Contains(2).Should().BeTrue();\r\n            stack.Contains(3).Should().BeTrue();\r\n            stack.Contains(4).Should().BeTrue();\r\n        });\r\n    }\r\n\r\n    [Test]\r\n    public static void PeekTest()\r\n    {\r\n        var stack = new ListBasedStack<int>([0, 1, 2, 3, 4]);\r\n\r\n        Assert.Multiple(() =>\r\n        {\r\n            stack.Peek().Should().Be(4);\r\n            stack.Peek().Should().Be(4);\r\n            stack.Peek().Should().Be(4);\r\n        });\r\n    }\r\n\r\n    [Test]\r\n    public static void PopTest()\r\n    {\r\n        var stack = new ListBasedStack<int>([0, 1, 2, 3, 4]);\r\n\r\n        Assert.Multiple(() =>\r\n        {\r\n            stack.Pop().Should().Be(4);\r\n            stack.Pop().Should().Be(3);\r\n            stack.Pop().Should().Be(2);\r\n            stack.Pop().Should().Be(1);\r\n            stack.Pop().Should().Be(0);\r\n        });\r\n    }\r\n\r\n    [Test]\r\n    public static void PushTest()\r\n    {\r\n        var stack = new ListBasedStack<int>();\r\n\r\n        Assert.Multiple(() =>\r\n            Enumerable.Range(0, 5)\r\n                .ToList()\r\n                .ForEach(number =>\r\n                {\r\n                    stack.Push(number);\r\n                    stack.Peek().Should().Be(number);\r\n                }));\r\n    }\r\n}\r\n"
  },
  {
    "path": "DataStructures.Tests/Stack/QueueBasedStackTests.cs",
    "content": "using DataStructures.Stack;\n\nnamespace DataStructures.Tests.Stack;\n\npublic static class QueueBasedStackTests\n{\n    [Test]\n    public static void PopWorksCorrectly()\n    {\n        //Arrange\n        QueueBasedStack<char> s = new QueueBasedStack<char>();\n        s.Push('A');\n        s.Push('B');\n        s.Push('C');\n        var result = new StringBuilder();\n\n        //Act\n        for (int i = 0; i < 3; i++)\n        {\n            result.Append(s.Pop());\n        }\n\n\n        //Assert\n        Assert.That(\"CBA\", Is.EqualTo(result.ToString()));\n        Assert.That(s.IsEmpty(), Is.True, \"Stack is Empty\");\n    }\n    [Test]\n    public static void PeekWorksCorrectly()\n    {\n        //Arrange\n        QueueBasedStack<int> s = new QueueBasedStack<int>();\n        s.Push(1);\n        s.Push(2);\n        s.Push(3);\n        var peeked = 0;\n\n        //Act\n        for (int i = 0; i < 3; i++)\n        {\n            peeked = s.Peek();\n        }\n\n\n        //Assert\n        Assert.That(3, Is.EqualTo(peeked));\n        Assert.That(s.IsEmpty(), Is.False, \"Stack is Empty\");\n    }\n    [Test]\n    public static void PopEmptyStackThrowsInvalidOperationException()\n    {\n        //Arrange\n        var s = new QueueBasedStack<int>();\n        Exception? exception = null;\n\n        //Act\n        try\n        {\n            s.Pop();\n        }\n        catch (Exception ex)\n        {\n            exception = ex;\n        }\n\n        //Assert\n        Assert.That(exception?.GetType(), Is.EqualTo(typeof(InvalidOperationException)));\n    }\n    [Test]\n    public static void PeekEmptyStackThrowsInvalidOperationException()\n    {\n        //Arrange\n        var s = new QueueBasedStack<int>();\n        Exception? exception = null;\n\n        //Act\n        try\n        {\n            s.Peek();\n        }\n        catch (Exception ex)\n        {\n            exception = ex;\n        }\n\n        //Assert\n        Assert.That(exception?.GetType(), Is.EqualTo(typeof(InvalidOperationException)));\n    }\n    [Test]\n    public static void ClearWorksCorrectly()\n    {\n        // Arrange\n        var s = new QueueBasedStack<int>();\n        s.Push(1);\n        s.Push(2);\n\n        // Act\n        s.Clear();\n\n        // Assert\n        Assert.That(s.IsEmpty(), Is.True, \"Queue is empty\");\n\n    }\n    [Test]\n    public static void LengthWorksCorrectly()\n    {\n        // Arrange\n        var s = new QueueBasedStack<int>();\n        s.Push(1);\n        s.Push(2);\n        var length = 0;\n\n        // Act\n        length = s.Length();\n\n        // Assert\n        Assert.That(2, Is.EqualTo(length));\n\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/TimelineTests.cs",
    "content": "using FluentAssertions.Execution;\n\nnamespace DataStructures.Tests;\n\npublic static class TimelineTests\n{\n    [Test]\n    public static void CountTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.Count\n            .Should()\n            .Be(5);\n    }\n\n    [Test]\n    public static void TimesCountTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.TimesCount\n            .Should()\n            .Be(timeline.GetAllTimes().Length);\n    }\n\n    [Test]\n    public static void ValuesCountTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.ValuesCount\n            .Should()\n            .Be(timeline.GetAllValues().Length);\n    }\n\n    [Test]\n    public static void IndexerGetTest()\n    {\n        const string eventName = \"TestTime2\";\n        var eventDate = new DateTime(2000, 1, 1);\n\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { eventDate, eventName },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline[eventDate][0]\n            .Should()\n            .Be(eventName);\n    }\n\n    [Test]\n    public static void IndexerSetTest()\n    {\n        var eventDate = new DateTime(2000, 1, 1);\n\n        const string formerEventName = \"TestTime2\";\n        const string eventName = \"TestTime2Modified\";\n\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { eventDate, formerEventName },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline[new DateTime(2000, 1, 1)] = [eventName];\n\n        timeline[new DateTime(2000, 1, 1)][0]\n            .Should()\n            .Be(eventName);\n    }\n\n    [Test]\n    public static void EqualsTest()\n    {\n        var timeline1 = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var timeline2 = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        (timeline1 == timeline2)\n            .Should()\n            .BeTrue();\n    }\n\n    [Test]\n    public static void ClearTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.Clear();\n\n        timeline.Count\n            .Should()\n            .Be(0);\n    }\n\n    [Test]\n    public static void CopyToTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var array = new (DateTime Time, string Value)[timeline.Count];\n        timeline.CopyTo(array, 0);\n\n        timeline.Count\n            .Should()\n            .Be(array.Length);\n\n        var i = 0;\n        using (new AssertionScope())\n        {\n            foreach (var (time, value) in timeline)\n            {\n                array[i].Time\n                    .Should()\n                    .Be(time);\n\n                array[i].Value\n                    .Should()\n                    .Be(value);\n\n                ++i;\n            }\n        }\n    }\n\n    [Test]\n    public static void GetAllTimesTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var times = timeline.GetAllTimes();\n\n        var i = 0;\n        using (new AssertionScope())\n        {\n            foreach (var (time, _) in timeline)\n            {\n                times[i++]\n                    .Should()\n                    .Be(time);\n            }\n        }\n    }\n\n    [Test]\n    public static void GetTimesByValueTest()\n    {\n        var eventDate = new DateTime(2000, 1, 1);\n        const string eventName = \"TestTime2\";\n\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { eventDate, eventName },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.GetTimesByValue(eventName)[0]\n            .Should()\n            .Be(eventDate);\n    }\n\n    [Test]\n    public static void GetTimesBeforeTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var times = timeline.GetTimesBefore(new DateTime(2003, 1, 1));\n\n        using (new AssertionScope())\n        {\n            times.Length\n                .Should()\n                .Be(2);\n\n            times[0]\n                .Should()\n                .Be(new DateTime(1995, 1, 1));\n\n            times[1]\n                .Should()\n                .Be(new DateTime(2000, 1, 1));\n        }\n    }\n\n    [Test]\n    public static void GetTimesAfterTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var times = timeline.GetTimesAfter(new DateTime(2003, 1, 1));\n\n        using (new AssertionScope())\n        {\n            times.Length\n                .Should()\n                .Be(3);\n\n            times[0]\n                .Should()\n                .Be(new DateTime(2005, 1, 1));\n\n            times[1]\n                .Should()\n                .Be(new DateTime(2010, 1, 1));\n\n            times[2]\n                .Should()\n                .Be(new DateTime(2015, 1, 1));\n        }\n    }\n\n    [Test]\n    public static void GetAllValuesTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var values = timeline.GetAllValues();\n\n        var i = 0;\n        using (new AssertionScope())\n        {\n            foreach (var (_, value) in timeline)\n            {\n                values[i++]\n                    .Should()\n                    .Be(value);\n            }\n        }\n    }\n\n    [Test]\n    public static void GetValuesByTimeTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.GetValuesByTime(new DateTime(2000, 1, 1))[0]\n            .Should()\n            .Be(\"TestTime2\");\n    }\n\n    [Test]\n    public static void GetValuesBeforeTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var array = timeline.GetValuesBefore(new DateTime(2003, 1, 1)).ToArray();\n\n        using (new AssertionScope())\n        {\n            array.Length\n                .Should()\n                .Be(2);\n\n            array[0].Time\n                .Should()\n                .Be(new DateTime(1995, 1, 1));\n\n            array[1].Time\n                .Should()\n                .Be(new DateTime(2000, 1, 1));\n        }\n    }\n\n    [Test]\n    public static void GetValuesAfterTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var array = timeline.GetValuesAfter(new DateTime(2003, 1, 1)).ToArray();\n\n        using (new AssertionScope())\n        {\n            array.Length\n                .Should()\n                .Be(3);\n\n            array[0].Time\n                .Should()\n                .Be(new DateTime(2005, 1, 1));\n\n            array[1].Time\n                .Should()\n                .Be(new DateTime(2010, 1, 1));\n\n            array[2].Time\n                .Should()\n                .Be(new DateTime(2015, 1, 1));\n        }\n    }\n\n    [Test]\n    public static void GetValuesByMillisecondTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1985, 1, 1, 10, 0, 0, 250), \"TestTime1\" },\n            { new DateTime(1990, 1, 1, 10, 0, 0, 250), \"TestTime2\" },\n            { new DateTime(1995, 1, 1, 10, 0, 0, 250), \"TestTime3\" },\n            { new DateTime(2005, 1, 1, 10, 0, 0, 750), \"TestTime4\" },\n            { new DateTime(2015, 1, 1, 10, 0, 0, 750), \"TestTime5\" },\n        };\n\n        var query = timeline.GetValuesByMillisecond(750);\n\n        query.Count\n            .Should()\n            .Be(2);\n    }\n\n    [Test]\n    public static void GetValuesBySecondTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1985, 1, 1, 10, 0, 5), \"TestTime1\" },\n            { new DateTime(1990, 1, 1, 10, 0, 5), \"TestTime2\" },\n            { new DateTime(1995, 1, 1, 10, 0, 5), \"TestTime3\" },\n            { new DateTime(2005, 1, 1, 10, 0, 20), \"TestTime4\" },\n            { new DateTime(2015, 1, 1, 10, 0, 20), \"TestTime5\" },\n        };\n\n        var query = timeline.GetValuesBySecond(20);\n\n        using (new AssertionScope())\n        {\n            query.Count\n                .Should()\n                .Be(2);\n\n            timeline\n                .Should()\n                .Contain(query);\n        }\n    }\n\n    [Test]\n    public static void GetValuesByMinuteTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1985, 1, 1, 10, 15, 0), \"TestTime1\" },\n            { new DateTime(1990, 1, 1, 10, 15, 0), \"TestTime2\" },\n            { new DateTime(1995, 1, 1, 10, 15, 0), \"TestTime3\" },\n            { new DateTime(2005, 1, 1, 10, 40, 0), \"TestTime4\" },\n            { new DateTime(2015, 1, 1, 10, 40, 0), \"TestTime5\" },\n        };\n\n        var query = timeline.GetValuesByMinute(40);\n\n        using (new AssertionScope())\n        {\n            query.Count\n                .Should()\n                .Be(2);\n\n            timeline\n                .Should()\n                .Contain(query);\n        }\n    }\n\n    [Test]\n    public static void GetValuesByHourTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1985, 1, 1, 7, 0, 0), \"TestTime1\" },\n            { new DateTime(1990, 1, 1, 7, 0, 0), \"TestTime2\" },\n            { new DateTime(1995, 1, 1, 7, 0, 0), \"TestTime3\" },\n            { new DateTime(2005, 1, 1, 16, 0, 0), \"TestTime4\" },\n            { new DateTime(2015, 1, 1, 16, 0, 0), \"TestTime5\" },\n        };\n\n        var query = timeline.GetValuesByHour(16);\n\n        using (new AssertionScope())\n        {\n            query.Count\n                .Should()\n                .Be(2);\n\n            timeline\n                .Should()\n                .Contain(query);\n        }\n    }\n\n    [Test]\n    public static void GetValuesByDayTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1985, 1, 10), \"TestTime1\" },\n            { new DateTime(1990, 1, 10), \"TestTime2\" },\n            { new DateTime(1995, 1, 10), \"TestTime3\" },\n            { new DateTime(2005, 1, 20), \"TestTime4\" },\n            { new DateTime(2015, 1, 20), \"TestTime5\" },\n        };\n\n        var query = timeline.GetValuesByDay(20);\n\n        using (new AssertionScope())\n        {\n            query.Count\n                .Should()\n                .Be(2);\n\n            timeline\n                .Should()\n                .Contain(query);\n        }\n    }\n\n    [Test]\n    public static void GetValuesByTimeOfDayTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1985, 1, 1, 10, 30, 15, 500), \"TestTime1\" },\n            { new DateTime(1990, 1, 1, 10, 30, 15, 500), \"TestTime2\" },\n            { new DateTime(1995, 1, 1, 10, 30, 15, 500), \"TestTime3\" },\n            { new DateTime(2005, 1, 1, 21, 15, 40, 600), \"TestTime4\" },\n            { new DateTime(2015, 1, 1, 21, 15, 40, 600), \"TestTime5\" },\n        };\n\n        var query = timeline.GetValuesByTimeOfDay(new TimeSpan(0, 21, 15, 40, 600));\n\n        using (new AssertionScope())\n        {\n            query.Count\n                .Should()\n                .Be(2);\n\n            timeline\n                .Should()\n                .Contain(query);\n        }\n    }\n\n    [Test]\n    public static void GetValuesByDayOfWeekTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(2015, 1, 5), \"TestTime1\" }, //Monday\n            { new DateTime(2015, 2, 2), \"TestTime2\" }, //Monday\n            { new DateTime(2015, 1, 6), \"TestTime3\" }, //Tuesday\n            { new DateTime(2015, 1, 7), \"TestTime4\" }, //Wednesday\n            { new DateTime(2015, 1, 8), \"TestTime5\" }, //Thursday\n        };\n\n        var query = timeline.GetValuesByDayOfWeek(DayOfWeek.Monday);\n\n        using (new AssertionScope())\n        {\n            query.Count\n                .Should()\n                .Be(2);\n\n            timeline\n                .Should()\n                .Contain(query);\n        }\n    }\n\n    [Test]\n    public static void GetValuesByDayOfYearTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1985, 1, 3), \"TestTime1\" }, //3rd day of year\n            { new DateTime(1990, 1, 7), \"TestTime2\" }, //7th day of year\n            { new DateTime(1995, 1, 22), \"TestTime3\" }, //22th day of year\n            { new DateTime(2000, 2, 1), \"TestTime4\" }, //32th day of year\n            { new DateTime(2005, 2, 1), \"TestTime5\" }, //32th day of year\n        };\n\n        var query = timeline.GetValuesByDayOfYear(32);\n\n        using (new AssertionScope())\n        {\n            query.Count\n                .Should()\n                .Be(2);\n\n            timeline\n                .Should()\n                .Contain(query);\n        }\n    }\n\n    [Test]\n    public static void GetValuesByMonthTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1985, 1, 1), \"TestTime1\" },\n            { new DateTime(1990, 2, 1), \"TestTime2\" },\n            { new DateTime(1995, 3, 1), \"TestTime3\" },\n            { new DateTime(2005, 4, 1), \"TestTime4\" },\n            { new DateTime(2015, 4, 1), \"TestTime5\" },\n        };\n\n        var query = timeline.GetValuesByMonth(4);\n\n        using (new AssertionScope())\n        {\n            query.Count\n                .Should()\n                .Be(2);\n\n            timeline\n                .Should()\n                .Contain(query);\n        }\n    }\n\n    [Test]\n    public static void GetValuesByYearTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1985, 1, 2), \"TestTime1\" },\n            { new DateTime(1990, 2, 1), \"TestTime2\" },\n            { new DateTime(1995, 1, 2), \"TestTime3\" },\n            { new DateTime(2005, 2, 1), \"TestTime4\" },\n            { new DateTime(2005, 1, 2), \"TestTime5\" },\n        };\n\n        var query = timeline.GetValuesByYear(2005);\n\n        using (new AssertionScope())\n        {\n            query.Count\n                .Should()\n                .Be(2);\n\n            timeline\n                .Should()\n                .Contain(query);\n        }\n    }\n\n    [Test]\n    public static void AddDateTimeAndTValueTest() //void Add(DateTime time, TValue value)\n    {\n        var eventDate = new DateTime(2015, 1, 1);\n        const string eventName = \"TestTime\";\n\n        var timeline = new Timeline<string>\n        {\n            { eventDate, eventName }\n        };\n\n        timeline.Count\n            .Should()\n            .Be(1);\n\n        timeline[eventDate][0]\n            .Should()\n            .Be(eventName);\n    }\n\n    [Test]\n    public static void AddDateTimeAndTValueArrayTest() //void Add(params (DateTime, TValue)[] timeline)\n    {\n        var eventDate1 = new DateTime(2015, 1, 1);\n        const string eventName1 = \"TestTime1\";\n\n        var eventDate2 = new DateTime(1750, 1, 1);\n        const string eventName2 = \"TestTime2\";\n\n        var timeline = new Timeline<string>\n        {\n            {\n                (eventDate1, eventName1),\n                (eventDate2, eventName2)\n            }\n        };\n\n        using (new AssertionScope())\n        {\n            timeline.Count\n                .Should()\n                .Be(2);\n\n            timeline[eventDate1][0]\n                .Should()\n                .Be(eventName1);\n\n            timeline[eventDate2][0]\n                .Should()\n                .Be(eventName2);\n        }\n    }\n\n    [Test]\n    public static void AddTimelineTest() //void Add(Timeline<TValue> timeline)\n    {\n        var eventDate = new DateTime(2015, 1, 1);\n        const string eventName = \"TestTime\";\n\n        var timeline = new Timeline<string>\n        {\n            new Timeline<string>(eventDate, eventName)\n        };\n\n        using (new AssertionScope())\n        {\n            timeline.Count\n                .Should()\n                .Be(1);\n\n            timeline[eventDate][0]\n                .Should()\n                .Be(eventName);\n        }\n    }\n\n    [Test]\n    public static void AddNowTest()\n    {\n        var timeline = new Timeline<string>();\n\n        timeline.AddNow(\"Now\");\n\n        using (new AssertionScope())\n        {\n            timeline.Count\n                .Should()\n                .Be(1);\n\n            timeline.ContainsValue(\"Now\")\n                .Should()\n                .BeTrue();\n        }\n    }\n\n    [Test]\n    public static void ContainsDateTimeAndTValueTest() //bool Contains(DateTime time, TValue value)\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.Contains(new DateTime(2000, 1, 1), \"TestTime2\")\n            .Should()\n            .BeTrue();\n    }\n\n    [Test]\n    public static void ContainsDateTimeAndTValueArrayTest() //bool Contains(params (DateTime, TValue)[] timeline)\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.Contains(\n                (new DateTime(1995, 1, 1), \"TestTime1\"),\n                (new DateTime(2000, 1, 1), \"TestTime2\"))\n            .Should()\n            .BeTrue();\n    }\n\n    [Test]\n    public static void ContainsTimelineTest() //bool Contains(Timeline<TValue> timeline)\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.Contains(new Timeline<string>(new DateTime(2000, 1, 1), \"TestTime2\"))\n            .Should()\n            .BeTrue();\n    }\n\n    [Test]\n    public static void ContainsTimeTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.ContainsTime(new DateTime(2000, 1, 1))\n            .Should()\n            .BeTrue();\n    }\n\n    [Test]\n    public static void ContainsValueTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.ContainsValue(\"TestTime1\")\n            .Should()\n            .BeTrue();\n    }\n\n    [Test]\n    public static void RemoveDateTimeAndTValueTest() //bool Remove(DateTime time, TValue value)\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.Remove(new DateTime(2000, 1, 1), \"TestTime2\");\n\n        using (new AssertionScope())\n        {\n            timeline.Count\n                .Should()\n                .Be(4);\n\n            timeline.Contains(new DateTime(2000, 1, 1), \"TestTime2\")\n                .Should()\n                .BeFalse();\n        }\n    }\n\n    [Test]\n    public static void RemoveDateTimeAndTValueArrayTest() //bool Remove(params (DateTime, TValue)[] timeline)\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.Remove(\n            (new DateTime(1995, 1, 1), \"TestTime1\"),\n            (new DateTime(2000, 1, 1), \"TestTime2\"));\n\n        using (new AssertionScope())\n        {\n            timeline.Count\n                .Should()\n                .Be(3);\n\n            timeline.Contains(\n                    (new DateTime(1995, 1, 1), \"TestTime1\"),\n                    (new DateTime(2000, 1, 1), \"TestTime2\"))\n                .Should()\n                .BeFalse();\n        }\n    }\n\n    [Test]\n    public static void RemoveTimelineTest() //bool Remove(Timeline<TValue> timeline)\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.Remove(new Timeline<string>(new DateTime(2000, 1, 1), \"TestTime2\"));\n\n        using (new AssertionScope())\n        {\n            timeline.Count\n                .Should()\n                .Be(4);\n\n            timeline.Contains(new DateTime(2000, 1, 1), \"TestTime2\")\n                .Should()\n                .BeFalse();\n        }\n    }\n\n    [Test]\n    public static void RemoveTimeTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.RemoveTimes(new DateTime(2000, 1, 1));\n\n        using (new AssertionScope())\n        {\n            timeline.Count\n                .Should()\n                .Be(4);\n\n            timeline.ContainsTime(new DateTime(2000, 1, 1))\n                .Should()\n                .BeFalse();\n        }\n    }\n\n    [Test]\n    public static void RemoveValueTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        timeline.RemoveValues(\"TestTime1\");\n\n        using (new AssertionScope())\n        {\n            timeline.Count\n                .Should()\n                .Be(4);\n\n            timeline.ContainsValue(\"TestTime1\")\n                .Should()\n                .BeFalse();\n        }\n    }\n\n    [Test]\n    public static void ToArrayTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var array = timeline.ToArray();\n\n        timeline.Count\n            .Should()\n            .Be(array.Length);\n\n        using (new AssertionScope())\n        {\n            var i = 0;\n            foreach (var (time, value) in timeline)\n            {\n                time\n                    .Should()\n                    .Be(array[i].Time);\n\n                value\n                    .Should()\n                    .Be(array[i].Value);\n\n                ++i;\n            }\n        }\n    }\n\n    [Test]\n    public static void ToListTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var list = timeline.ToList();\n\n        timeline.Count\n            .Should()\n            .Be(list.Count);\n\n        using (new AssertionScope())\n        {\n            var i = 0;\n            foreach (var (time, value) in timeline)\n            {\n                time\n                    .Should()\n                    .Be(list[i].Time);\n\n                value\n                    .Should()\n                    .Be(list[i].Value);\n\n                ++i;\n            }\n        }\n    }\n\n    [Test]\n    public static void ToDictionaryTest()\n    {\n        var timeline = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var dictionary = timeline.ToDictionary();\n\n        var timelineList = new List<(DateTime Time, string Value)>();\n        foreach (var pair in timeline)\n        {\n            timelineList.Add(pair);\n        }\n\n        var dictionaryList = new List<(DateTime Time, string Value)>();\n        foreach (var (key, value) in dictionary)\n        {\n            dictionaryList.Add((key, value));\n        }\n\n        timelineList.OrderBy(pair => pair.Time);\n        dictionaryList.OrderBy(pair => pair.Time);\n\n        timelineList.Count\n            .Should()\n            .Be(dictionaryList.Count);\n\n        using (new AssertionScope())\n        {\n            for (var i = 0; i < timelineList.Count; ++i)\n            {\n                timelineList[i].Time\n                    .Should()\n                    .Be(dictionaryList[i].Time);\n\n                timelineList[i].Value\n                    .Should()\n                    .Be(dictionaryList[i].Value);\n            }\n        }\n    }\n\n    [Test]\n    public static void EqualityOperatorTest()\n    {\n        var timeline1 = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var timeline2 = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        (timeline1 == timeline2)\n            .Should()\n            .BeTrue();\n    }\n\n    [Test]\n    public static void InequalityOperatorTest()\n    {\n        var timeline1 = new Timeline<string>\n        {\n            { new DateTime(1995, 1, 1), \"TestTime1\" },\n            { new DateTime(2000, 1, 1), \"TestTime2\" },\n            { new DateTime(2005, 1, 1), \"TestTime3\" },\n            { new DateTime(2010, 1, 1), \"TestTime4\" },\n            { new DateTime(2015, 1, 1), \"TestTime5\" },\n        };\n\n        var timeline2 = new Timeline<string>\n        {\n            { new DateTime(1895, 1, 1), \"TestTime6\" },\n            { new DateTime(1900, 1, 1), \"TestTime7\" },\n            { new DateTime(1905, 1, 1), \"TestTime8\" },\n            { new DateTime(1910, 1, 1), \"TestTime9\" },\n            { new DateTime(1915, 1, 1), \"TestTime10\" },\n        };\n\n        (timeline1 == timeline2)\n            .Should()\n            .BeFalse();\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/Tries/TrieTests.cs",
    "content": "using DataStructures.Tries;\n\nnamespace DataStructures.Tests.Tries;\n\npublic static class TrieTests\n{\n    [Test]\n    public static void FindWordInTrie()\n    {\n        // Arrange\n        string[] words = [\n            \"trie\",\n            \"node\",\n            \"none\",\n            \"treatment\",\n        ];\n\n        // Act\n        Trie trie = new(words);\n\n        // Assert\n        Assert.That(trie.Find(\"trie\"), Is.True, \"The word 'trie' isn't in Trie structure\");\n        Assert.That(trie.Find(\"node\"), Is.True, \"The word 'node' isn't in Trie structure\");\n        Assert.That(trie.Find(\"none\"), Is.True, \"The word 'none' isn't in Trie structure\");\n        Assert.That(trie.Find(\"treatment\"), Is.True, \"The word 'treatment' isn't in Trie structure\");\n\n        Assert.That(trie.Find(\"nodes\"), Is.False, \"The word 'nodes' is in Trie sturcture\");\n        Assert.That(trie.Find(\"\"), Is.False, \"The word empty is in Trie structure\");\n        Assert.That(trie.Find(\"tri\"), Is.False, \"The word 'tri' is in Trie structure\");\n    }\n\n    [Test]\n    public static void InsertInTrie()\n    {\n        // Arrange\n        string[] words = [\n            \"trie\",\n            \"node\",\n            \"none\",\n            \"treatment\",\n        ];\n\n        Trie trie = new();\n\n        // Act\n        foreach (var t in words)\n        {\n            trie.Insert(t);\n        }\n\n        // Assert\n        Assert.That(trie.Find(\"trie\"), Is.True, \"The word 'trie' isn't in Trie structure\");\n        Assert.That(trie.Find(\"node\"), Is.True, \"The word 'node' isn't in Trie structure\");\n        Assert.That(trie.Find(\"none\"), Is.True, \"The word 'none' isn't in Trie structure\");\n        Assert.That(trie.Find(\"treatment\"), Is.True, \"The word 'treatment' isn't in Trie structure\");\n    }\n\n    [Test]\n    public static void RemoveFromTrie()\n    {\n        // Arrange\n        string[] words = [\n            \"trie\",\n            \"node\",\n            \"none\",\n            \"treatment\",\n        ];\n\n        Trie trie = new();\n\n        // Act\n        foreach (var t in words)\n        {\n            trie.Insert(t);\n        }\n        trie.Remove(\"trie\");\n\n        // Assert\n        Assert.That(trie.Find(\"trie\"), Is.False, \"The word 'trie' is in Trie structure\");\n        Assert.That(trie.Find(\"treatment\"), Is.True, \"The word 'treament' isn't in Trie structure\");\n        Assert.That(trie.Find(\"node\"), Is.True, \"The word 'node' isn't in Trie structure\");\n        Assert.That(trie.Find(\"none\"), Is.True, \"The word 'none' isn't in Trie structure\");\n    }\n\n    [Test]\n    public static void MultipleInsert()\n    {\n        // Arrange\n        string w = \"trie\";\n        Trie trie = new();\n\n        // Act\n        trie.Insert(w);\n        trie.Insert(w);\n\n        // Assert\n        Assert.That(trie.Find(\"trie\"), Is.True, \"The word 'trie' isn't in Trie structure\");\n        Assert.That(trie.Find(\"nodes\"), Is.False, \"The word 'nodes' is in Trie sturcture\");\n    }\n\n    [Test]\n    public static void RemoveAWordThatIsNtInTrie()\n    {\n        // Arrange\n        const string w = \"trie\";\n        Trie trie = new();\n\n        // Act\n        trie.Insert(w);\n        trie.Remove(\"tri\");\n        trie.Remove(\"none\");\n\n        // Assert\n        Assert.That(trie.Find(\"trie\"), Is.True, \"The word 'trie' isn't in Trie structure\");\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/UnrolledList/UnrolledLinkedListNodeTests.cs",
    "content": "using DataStructures.UnrolledList;\n\nnamespace DataStructures.Tests.UnrolledList;\n\npublic class UnrolledLinkedListNodeTests\n{\n    [Test]\n    public void GetAndSet_SetItemNodeAndGetIt_ReturnExpectedItem()\n    {\n        var node = new UnrolledLinkedListNode(6);\n        node.Set(0, 1);\n\n        var result = node.Get(0);\n\n        result.Should().Be(1);\n    }\n\n    [Test]\n    public void Get_GetLowIndex_ThrowArgumentException()\n    {\n        var node = new UnrolledLinkedListNode(6);\n\n        Action action = () => node.Get(-1);\n\n        action.Should().Throw<ArgumentException>();\n    }\n\n    [Test]\n    public void Get_GetHighIndex_ThrowArgumentException()\n    {\n        var node = new UnrolledLinkedListNode(6);\n\n        Action action = () => node.Get(7);\n\n        action.Should().Throw<ArgumentException>();\n    }\n\n    [Test]\n    public void Set_SetLowIndex_ThrowArgumentException()\n    {\n        var node = new UnrolledLinkedListNode(6);\n\n        Action action = () => node.Set(-1, 0);\n\n        action.Should().Throw<ArgumentException>();\n    }\n\n    [Test]\n    public void Set_SetHighIndex_ThrowArgumentException()\n    {\n        var node = new UnrolledLinkedListNode(6);\n\n        Action action = () => node.Set(7, 0);\n\n        action.Should().Throw<ArgumentException>();\n    }\n}\n"
  },
  {
    "path": "DataStructures.Tests/UnrolledList/UnrolledLinkedListTests.cs",
    "content": "using DataStructures.UnrolledList;\n\nnamespace DataStructures.Tests.UnrolledList;\n\npublic class UnrolledLinkedListTests\n{\n    [Test]\n    public void Insert_LinkArrayToLinkedList_ReturnArrayHaveSameItems()\n    {\n        var linkedList = new UnrolledLinkedList(6);\n        var contest = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };\n        foreach (var number in contest)\n        {\n            linkedList.Insert(number);\n        }\n\n        var result = linkedList.GetRolledItems();\n\n        result.Should().BeEquivalentTo(contest);\n    }\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "README.md",
    "content": "<div align = \"center\">\n\n# The Algorithms - C#\n\n[![Discord chat](https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA)](https://discord.gg/c7MnfGFGa6)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/58895a2795bd48a8b3b7eb6ebe22d576)](https://www.codacy.com/gh/TheAlgorithms/C-Sharp/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=TheAlgorithms/C-Sharp&amp;utm_campaign=Badge_Grade)\n[![codecov](https://codecov.io/gh/TheAlgorithms/C-Sharp/branch/master/graph/badge.svg)](https://codecov.io/gh/TheAlgorithms/C-Sharp)\n[![Donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/TheAlgorithms/donate)\n\n## All Algorithms implemented in C# - for education purposes\n\nThe repository is a collection of a variety of algorithms implemented in C#. The algorithms span over a variety of topics\nfrom computer science, mathematics and statistics, data science, machine learning, engineering, etc. The implementations\nand their associated documentations are meant to provide a learning resource for educators and students. Hence, one may\nfind more than one implementation for the same objective but using different algorithm strategies and optimizations.\n\n</div>\n\n## List of Algorithms\n\n* [Algorithms](./Algorithms)\n  * [Crypto](./Algorithms/Crypto/)\n    * [Paddings](./Algorithms/Crypto/Paddings/)\n      * [ISO 10125-2 Padding](./Algorithms/Crypto/Paddings/Iso10126D2Padding.cs)\n      * [ISO 7816-4 Padding](./Algorithms/Crypto/Paddings/Iso7816D4Padding.cs)\n      * [X9.32 Padding](./Algorithms/Crypto/Paddings/X932Padding.cs)\n      * [TBC Padding](./Algorithms/Crypto/Paddings/TbcPadding.cs)\n      * [PKCS7 Padding](./Algorithms/Crypto/Paddings/Pkcs7Padding.cs)\n    * [Digests](./Algorithms/Crypto/Digests/)\n      * [Ascon Hash Digest](./Algorithms/Crypto/Digests/AsconDigest.cs)\n      * [MD2 Digest](./Algorithms/Crypto/Digests/Md2Digest.cs)\n  * [Data Compression](./Algorithms/DataCompression)\n    * [Burrows-Wheeler transform](./Algorithms/DataCompression/BurrowsWheelerTransform.cs)\n    * [Huffman Compressor](./Algorithms/DataCompression/HuffmanCompressor.cs)\n    * [Shannon-Fano Compressor](./Algorithms/DataCompression/ShannonFanoCompressor.cs)\n  * [Encoders](./Algorithms/Encoders)\n    * [Caesar](./Algorithms/Encoders/CaesarEncoder.cs)\n    * [Vigenere](./Algorithms/Encoders/VigenereEncoder.cs)\n    * [Hill](./Algorithms/Encoders/HillEncoder.cs)\n    * [NYSIIS](./Algorithms/Encoders/NysiisEncoder.cs)\n    * [Soundex](./Algorithms/Encoders/SoundexEncoder.cs)\n    * [Feistel](./Algorithms/Encoders/FeistelCipher.cs)\n    * [Blowfish](./Algorithms/Encoders/BlowfishEncoder.cs)\n    * [Autokey](./Algorithms/Encoders/AutokeyEncoder.cs)\n  * [Graph](./Algorithms/Graph)\n    * [Minimum Spanning Tree](./Algorithms/Graph/MinimumSpanningTree)\n      * [Prim's Algorithm (Adjacency Matrix)](./Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs)\n      * [Kruskal's Algorithm](./Algorithms/Graph/MinimumSpanningTree/Kruskal.cs)\n    * [BreadthFirstTreeTraversal](./Algorithms/Graph/BreadthFirstTreeTraversal.cs)\n    * [BreadthFirstSearch](./Algorithms/Graph/BreadthFirstSearch.cs)\n    * [DepthFirstSearch](./Algorithms/Graph/DepthFirstSearch.cs)\n    * [Dijkstra Shortest Path](./Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs)\n    * [FloydWarshall](./Algorithms/Graph/FloydWarshall.cs)\n    * [Kosaraju](./Algorithms/Graph/Kosaraju.cs)\n    * [Topological Sort](./Algorithms/Graph/TopologicalSort.cs)\n  * [Knapsack problem](./Algorithms/Knapsack)\n    * [Naive solver](./Algorithms/Knapsack/NaiveKnapsackSolver.cs)\n    * [Dynamic Programming solver](./Algorithms/Knapsack/DynamicProgrammingKnapsackSolver.cs)\n    * [Branch and bound solver](./Algorithms/Knapsack/BranchAndBoundKnapsackSolver.cs)\n    * [IHeuristicKnapsackSolver](./Algorithms/Knapsack/IHeuristicKnapsackSolver.cs)\n  * [Linear Algebra](./Algorithms/LinearAlgebra)\n    * [Distances](./Algorithms/LinearAlgebra/Distances)\n      * [Chebyshev](./Algorithms/LinearAlgebra/Distances/Chebyshev.cs)\n      * [Euclidean](./Algorithms/LinearAlgebra/Distances/Euclidean.cs)\n      * [Manhattan](./Algorithms/LinearAlgebra/Distances/Manhattan.cs)\n      * [Minkowski](./Algorithms/LinearAlgebra/Distances/Minkowski.cs)\n    * [Eigenvalue](./Algorithms/LinearAlgebra/Eigenvalue)\n      * [Power Iteration](./Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs)\n  * [Modular Arithmetic](./Algorithms/ModularArithmetic)\n    * [Chinese Remainder Theorem](./Algorithms/ModularArithmetic/ChineseRemainderTheorem.cs)\n    * [Extended Euclidean Algorithm](./Algorithms/ModularArithmetic/ExtendedEuclideanAlgorithm.cs)\n    * [Modular Multiplicative Inverse](./Algorithms/ModularArithmetic/ModularMultiplicativeInverse.cs)\n  * [Numeric](./Algorithms/Numeric)\n    * [Absolute](./Algorithms/Numeric/Abs.cs) \n    * [Addition Without Arithmetic](./Algorithms/Numeric/AdditionWithoutArithmetic.cs) \n    * [Aliquot Sum Calculator](./Algorithms/Numeric/AliquotSumCalculator.cs)\n    * [Amicable Numbers Checker](./Algorithms/Numeric/AmicableNumbersChecker.cs)\n    * [Ceil](./Algorithms/Numeric/Ceil.cs)\n    * [Decomposition](./Algorithms/Numeric/Decomposition)\n      * [LU Decomposition](./Algorithms/Numeric/Decomposition/LU.cs)\n      * [Thin Singular Vector Decomposition](./Algorithms/Numeric/Decomposition/ThinSVD.cs)\n    * [Floor](./Algorithms/Floor.cs)\n    * [Greatest Common Divisor](./Algorithms/Numeric/GreatestCommonDivisor)\n      * [Euclidean GCD](./Algorithms/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinder.cs)\n      * [Binary GCD](./Algorithms/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinder.cs)\n    * [Factorization](./Algorithms/Numeric/Factorization)\n      * [Trial division Factorization](./Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs)\n    * [Modular Exponentiation](./Algorithms/Numeric/ModularExponentiation.cs)\n    * [Series](./Algorithms/Numeric/Series)\n      * [Maclaurin Series](./Algorithms/Numeric/Series/Maclaurin.cs)\n    * [Gauss-Jordan Elimination](./Algorithms/Numeric/GaussJordanElimination.cs)\n    * [BinomialCoefficient](./Algorithms/Numeric/BinomialCoefficient.cs)\n    * [Factorial](./Algorithms/Numeric/Factorial.cs)\n    * [Keith Number Checker](./Algorithms/Numeric/KeithNumberChecker.cs)\n    * [Pseudo-Inverse](./Algorithms/Numeric/Pseudoinverse/PseudoInverse.cs)\n    * [Narcissistic Number Checker](./Algorithms/Numeric/NarcissisticNumberChecker.cs)\n    * [Perfect Cube Checker](./Algorithms/Numeric/PerfectCubeChecker.cs)\n    * [Perfect Number Checker](./Algorithms/Numeric/PerfectNumberChecker.cs)\n    * [Perfect Square Checker](./Algorithms/Numeric/PerfectSquareChecker.cs)\n    * [Euler Method](./Algorithms/Numeric/EulerMethod.cs)\n    * [Classic Runge-Kutta Method](./Algorithms/Numeric/RungeKuttaMethod.cs)\n    * [Miller-Rabin primality check](./Algorithms/Numeric/MillerRabinPrimalityChecker.cs)\n    * [KrishnamurthyNumberChecker](./Algorithms/Numeric/KrishnamurthyNumberChecker.cs)\n    * [Automorphic Number](./Algorithms/Numeric/AutomorphicNumber.cs)\n    * [Josephus Problem](./Algorithms/Numeric/JosephusProblem.cs)\n    * [Newton's Square Root Calculation](./Algorithms/NewtonSquareRoot.cs)\n    * [SoftMax Function](./Algorithms/Numeric/SoftMax.cs)\n  * [RecommenderSystem](./Algorithms/RecommenderSystem)\n    * [CollaborativeFiltering](./Algorithms/RecommenderSystem/CollaborativeFiltering)\n  * [Machine Learning](./Algorithms/MachineLearning)\n    * [Linear Regression](./Algorithms/MachineLearning/LinearRegression.cs)\n    * [K-Nearest Neighbors](./Algorithms/MachineLearning/KNearestNeighbors.cs)\n    * [Logistic Regression](./Algorithms/MachineLearning/LogisticRegression.cs)\n  * [Searches](./Algorithms/Search)\n    * [A-Star](./Algorithms/Search/AStar/)\n    * [Binary Search](./Algorithms/Search/BinarySearcher.cs)\n\t* [BoyerMoore Search](./Algorithms/Search/BoyerMoore.cs)\n    * [Fast Search](./Algorithms/Search/FastSearcher.cs)\n    * [Fibonacci Search](./Algorithms/Search/FibonacciSearcher.cs)\n    * [Interpolation Search](./Algorithms/Search/InterpolationSearch.cs)\n    * [Jump Search](./Algorithms/Search/JumpSearcher.cs)\n    * [Linear Search](./Algorithms/Search/LinearSearcher.cs)\n    * [Recursive Binary Search](./Algorithms/Search/RecursiveBinarySearcher.cs)\n  * [Sorts](./Algorithms/Sorters)\n    * [Comparison](./Algorithms/Sorters/Comparison)\n      * [Binary Insertion Sort](./Algorithms/Sorters/Comparison/BinaryInsertionSorter.cs)\n      * [Bogo Sort](./Algorithms/Sorters/Comparison/BogoSorter.cs)\n      * [Bubble Sort](./Algorithms/Sorters/Comparison/BubbleSorter.cs)\n      * [Cocktail Sort](./Algorithms/Sorters/Comparison/CocktailSorter.cs)\n      * [Comb Sort](./Algorithms/Sorters/Comparison/CombSorter.cs)\n      * [Cycle Sort](./Algorithms/Sorters/Comparison/CycleSorter.cs)\n      * [Exchange Sort](./Algorithms/Sorters/Comparison/ExchangeSorter.cs)\n      * [Gnome Sort](./Algorithms/Sorters/Comparison/GnomeSorter.cs)\n      * [Heap Sort](./Algorithms/Sorters/Comparison/HeapSorter.cs)\n      * [Insertion Sort](./Algorithms/Sorters/Comparison/InsertionSorter.cs)\n      * [Merge Sort](./Algorithms/Sorters/Comparison/MergeSorter.cs)\n      * [Pancake Sort](./Algorithms/Sorters/Comparison/PancakeSorter.cs)\n      * [Quick Sort](./Algorithms/Sorters/Comparison/QuickSorter.cs)\n        * [Median of three pivot](./Algorithms/Sorters/Comparison/MedianOfThreeQuickSorter.cs)\n        * [Middle point pivot](./Algorithms/Sorters/Comparison/MiddlePointQuickSorter.cs)\n        * [Random pivot](./Algorithms/Sorters/Comparison/RandomPivotQuickSorter.cs)\n      * [Selection Sort](./Algorithms/Sorters/Comparison/SelectionSorter.cs)\n      * [Shell Sort](./Algorithms/Sorters/Comparison/ShellSorter.cs)\n      * [Tim Sort](./Algorithms/Sorters/Comparison/TimSorter.cs)\n      * [Simplified Tim Sort](./Algorithms/Sorters/Comparison/BasicTimSorter.cs)\n    * [External](./Algorithms/Sorters/External)\n      * [Merge Sort](./Algorithms/Sorters/External/ExternalMergeSorter.cs)\n    * [Integer](./Algorithms/Sorters/Integer)\n      * [Counting Sort](./Algorithms/Sorters/Integer/CountingSorter.cs)\n      * [Bucket Sort](./Algorithms/Sorters/Integer/BucketSorter.cs)\n      * [Radix Sort](./Algorithms/Sorters/Integer/RadixSorter.cs)\n    * [String](./Algorithms/Sorters/String)\n      * [MSD Radix Sort](./Algorithms/Sorters/String/MsdRadixStringSorter.cs)\n  * [Shufflers](./Algorithms/Shufflers)\n    * [Fisher-Yates Shuffler](./Algorithms/Shufflers/FisherYatesShuffler.cs)\n    * [LINQ Shuffler](./Algorithms/Shufflers/LinqShuffler.cs)\n    * [Naive Shuffler](./Algorithms/Shufflers/NaiveShuffler.cs)\n    * [Recursive Shuffler](./Algorithms/Shufflers/RecursiveShuffler.cs)\n  * [Sequences](./Algorithms/Sequences)\n    * [A000002 Kolakoski](./Algorithms/Sequences/KolakoskiSequence.cs)\n    * [A000004 Zero](./Algorithms/Sequences/ZeroSequence.cs)\n    * [A000005 Count of Divisors](./Algorithms/Sequences/DivisorsCountSequence.cs)\n    * [A000008 Make Change](./Algorithms/Sequences/MakeChangeSequence.cs)\n    * [A000010 Euler's Totient](./Algorithms/Sequences/EulerTotientSequence.cs)\n    * [A000012 All Ones](./Algorithms/Sequences/AllOnesSequence.cs)\n    * [A000027 Natural](./Algorithms/Sequences/NaturalSequence.cs)\n    * [A000032 Lucas Numbers](./Algorithms/Sequences/LucasNumbersBeginningAt2Sequence.cs)\n    * [A000040 Primes](./Algorithms/Sequences/PrimesSequence.cs)\n    * [A000045 Fibonacci](./Algorithms/Sequences/FibonacciSequence.cs)\n    * [A000079 Powers of 2](./Algorithms/Sequences/PowersOf2Sequence.cs)\n    * [A000108 Catalan](./Algorithms/Sequences/CatalanSequence.cs)\n    * [A000120 1's Counting](./Algorithms/Sequences/OnesCountingSequence.cs)\n    * [A000124 Central Polygonal Numbers](./Algorithms/Sequences/CentralPolygonalNumbersSequence.cs)\n    * [A000125 Cake Numbers](./Algorithms/Sequences/CakeNumbersSequence.cs)\n    * [A000142 Factorial](./Algorithms/Sequences/FactorialSequence.cs)\n    * [A000213 Tribonacci Numbers](./Algorithms/Sequences/TribonacciNumbersSequence.cs)\n    * [A000215 Fermat Numbers](./Algorithms/Sequences/FermatNumbersSequence.cs)\n    * [A000288 Tetranacci Numbers](./Algorithms/Sequences/TetranacciNumbersSequence.cs)\n    * [A000290 Squares](./Algorithms/Sequences/SquaresSequence.cs)\n    * [A000292 Tetrahedral numbers](./Algorithms/Sequences/TetrahedralSequence.cs)\n    * [A000578 Cubes](./Algorithms/Sequences/CubesSequence.cs)\n    * [A000720 PrimePi](./Algorithms/Sequences/PrimePiSequence.cs)\n    * [A001146 Number of Boolean Functions](./Algorithms/Sequences/NumberOfBooleanFunctionsSequence.cs)\n    * [A001462 Golomb's](./Algorithms/Sequences/GolombsSequence.cs)\n    * [A001478 Negative Integers](./Algorithms/Sequences/NegativeIntegersSequence.cs)\n    * [A002110 Primorial Numbers](./Algorithms/Sequences/PrimorialNumbersSequence.cs)\n    * [A002717 Matchstick Triangle Arrangement](./Algorithms/Sequences/MatchstickTriangleSequence.cs)\n    * [A005132 Recaman's](./Algorithms/Sequences/RecamansSequence.cs)\n    * [A006577 Number of '3n+1' steps to reach 1](./Algorithms/Sequences/ThreeNPlusOneStepsSequence.cs)\n    * [A006862 Euclid Numbers](./Algorithms/Sequences/EuclidNumbersSequence.cs)\n    * [A006879 Number of Primes by Number of Digits](./Algorithms/Sequences/NumberOfPrimesByNumberOfDigitsSequence.cs)\n    * [A006880 Number of Primes by Powers of 10](./Algorithms/Sequences/NumberOfPrimesByPowersOf10Sequence.cs)\n    * [A007318 Binomial](./Algorithms/Sequences/BinomialSequence.cs)\n    * [A007395 All Twos](./Algorithms/Sequences/AllTwosSequence.cs)\n    * [A010051 Binary Prime Constant](./Algorithms/Sequences/BinaryPrimeConstantSequence.cs)\n    * [A010701 All Threes](./Algorithms/Sequences/BinaryPrimeConstantSequence.cs)\n    * [A011557 Powers of 10](./Algorithms/Sequences/PowersOf10Sequence.cs)\n    * [A057588 Kummer Numbers](./Algorithms/Sequences/KummerNumbersSequence.cs)\n    * [A019434 Fermat Primes](./Algorithms/Sequences/FermatPrimesSequence.cs)\n    * [A181391 Van Eck's](./Algorithms/Sequences/VanEcksSequence.cs)\n  * [Stack](./Algorithms/Stack)\n      * [Next Greater Element](./Algorithms/Stack/NextGreaterElement.cs)\n      * [Balanced Parentheses Checker](./Algorithms/Stack/BalancedParenthesesChecker.cs)\n      * [Reverse Stack](./Algorithms/Stack/ReverseStack.cs)\n  * [String](./Algorithms/Strings)\n    * [Similarity](./Algorithms/Strings/Similarity/)\n      * [Cosine Similarity](./Algorithms/Strings/Similarity/CosineSimilarity.cs)\n      * [Damerau-Levenshtein Distance](./Algorithms/Strings/Similarity/DamerauLevenshteinDistance.cs)\n      * [Hamming Distance](./Algorithms/Strings/Similarity/HammingDistance.cs)\n      * [Jaro Similarity](./Algorithms/Strings/Similarity/JaroSimilarity.cs)\n      * [Jaro-Winkler Distance](./Algorithms/Strings/Similarity/JaroWinklerDistance.cs)\n      * [Optimal String Alignment](./Algorithms/Strings/Similarity/OptimalStringAlignment.cs)\n    * [Pattern Matching](./Algorithms/Strings/PatternMatching/)\n      * [Bitop Pattern Matching](./Algorithms/Strings/PatternMatching/Bitap.cs)\n      * [Naive String Search](./Algorithms/Strings/PatternMatching/NaiveStringSearch.cs)\n      * [Rabin Karp](./Algorithms/Strings/PatternMatching/RabinKarp.cs)\n      * [Boyer Moore](./Algorithms/Strings/PatternMatching/BoyerMoore.cs)\n      * [Knuth–Morris–Pratt Search](./Algorithms/Strings/PatternMatching/KnuthMorrisPrattSearcher.cs)\n      * [WildCard Pattern Matching](./Algorithms/Strings/PatternMatching/WildCardMatcher.cs)\n      * [Z-block substring search](./Algorithms/Strings/PatternMatching/ZblockSubstringSearch.cs)\n    * [Longest Consecutive Character](./Algorithms/Strings/GeneralStringAlgorithms.cs)\n    * [Manacher's Algorithm](./Algorithms/Strings/ManachersAlgorithm.cs)\n    * [Palindrome Checker](./Algorithms/Strings/Palindrome.cs)\n    * [Get all permutations of a string](./Algorithms/Strings/Permutation.cs)\n  * [Other](./Algorithms/Other)\n    * [Fermat Prime Checker](./Algorithms/Other/FermatPrimeChecker.cs)\n    * [Sieve of Eratosthenes](./Algorithms/Other/SieveOfEratosthenes.cs)\n    * [Kadane's Algorithm](./Algorithms/Other/KadanesAlgorithm.cs)\n    * [Luhn](./Algorithms/Other/Luhn.cs)\n    * [Int2Binary](./Algorithms/Other/Int2Binary.cs)\n    * [GeoLocation](./Algorithms/Other/GeoLocation.cs)\n    * [Mandelbrot](./Algorithms/Other/Mandelbrot.cs)\n    * [Koch Snowflake](./Algorithms/Other/KochSnowflake.cs)\n    * [RGB-HSV Conversion](./Algorithms/Other/RGBHSVConversion.cs)\n    * [Flood Fill](./Algorithms/Other/FloodFill.cs)\n    * [Pareto Optimization](./Algorithms/Other/ParetoOptimization.cs)\n    * [Gauss Optimization](./Algorithms/Other/GaussOptimization.cs)\n    * [Decisions Convolutions](./Algorithms/Other/DecisionsConvolutions.cs)\n    * [Welford's Variance](./Algorithms/Other/WelfordsVariance.cs)\n    * [Julian Easter](./Algorithms/Other/JulianEaster.cs)\n    * [Pollard's Rho](./Algorithms/Other/PollardsRhoFactorizing.cs)\n    * [GeoLocation Hash](./Algorithms/Other/Geohash.cs)\n    * [Geofencing](./Algorithms/Other/Geofence.cs)\n    * [Triangulation Algorithm](./Algorithms/Other/Triangulator.cs)\n  * [Problems](./Algorithms/Problems)\n    * [Stable Marriage](./Algorithms/Problems/StableMarriage)\n      * [Gale-Shapley](./Algorithms/Problems/StableMarriage/GaleShapley.cs)\n      * [Accepter](./Algorithms/Problems/StableMarriage/Accepter.cs)\n      * [Proposer](./Algorithms/Problems/StableMarriage/Proposer.cs)\n    * [N-Queens](./Algorithms/Problems/NQueens)\n      * [Backtracking](./Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs)\n    * [Knight Tour](./Algorithms/Problems/KnightTour/)\n      * [Open Knight Tour](./Algorithms/Problems/KnightTour/OpenKnightTour.cs)\n    * [Graph Coloring](./Algorithms/Problems/GraphColoring)\n      * [Backtracking Graph Coloring Solver](./Algorithms/Problems/GraphColoring/GraphColoringSolver.cs)\n    * [Dynamic Programming](./Algorithms/Problems/DynamicProgramming)\n      * [Coin Change](./Algorithms/Problems/DynamicProgramming/CoinChange/DynamicCoinChangeSolver.cs)\n      * [Levenshtein Distance](./Algorithms/Problems/DynamicProgramming/LevenshteinDistance/LevenshteinDistance.cs)\n    * [Traveling Salesman Problem (TSP)](./Algorithms/Problems/TravelingSalesman/TravelingSalesmanSolver.cs)\n      * [Brute-force and Nearest Neighbor algorithms](./Algorithms/Problems/TravelingSalesman/TravelingSalesmanSolver.cs)\n    * [Job Scheduling](./Algorithms/Problems/JobScheduling)\n      * [Interval Scheduling (Greedy)](./Algorithms/Problems/JobScheduling/IntervalSchedulingSolver.cs)\n* [Data Structures](./DataStructures)\n  * [Bag](./DataStructures/Bag) \n  * [Bit Array](./DataStructures/BitArray.cs)\n  * [Deque (Double-Ended Queue)](./DataStructures/Deque/Deque.cs)\n  * [Timeline](./DataStructures/Timeline.cs)\n  * [Segment Trees](./DataStructures/SegmentTrees)\n    * [Segment Tree](./DataStructures/SegmentTrees/SegmentTree.cs)\n    * [Segment Tree Multiplication](./DataStructures/SegmentTrees/SegmentTreeApply.cs)\n    * [Segment Tree Update](./DataStructures/SegmentTrees/SegmentTreeUpdate.cs)\n  * [Binary Search Tree](./DataStructures/BinarySearchTree)\n  * [Scapegoat Tree](./DataStructures/ScapegoatTree)\n  * [Fenwick tree (or Binary Indexed Tree)](./DataStructures/Fenwick/BinaryIndexedTree.cs)\n  * [AA Tree](./DataStructures/AATree)\n  * [AVL Tree](./DataStructures/AVLTree)\n  * [B-Tree](./DataStructures/BTree)\n  * [Red-Black Tree](./DataStructures/RedBlackTree)\n  * [Stack](./DataStructures/Stack)\n    * [Array-based Stack](./DataStructures/Stack/ArrayBasedStack.cs)\n    * [List-based Stack](./DataStructures/Stack/ListBasedStack.cs)\n    * [Queue-based Stack](./DataStructures/Stack/QueueBasedStack.cs)\n  * [Heap](./DataStructures/Heap)\n    * [Min-Max Heap](./DataStructures/Heap/MinMaxHeap.cs)\n    * [Binary Heap](./DataStructures/Heap/BinaryHeap.cs)\n    * [Fibonacci Heap](./DataStructures/Heap/FibonacciHeap/FibonacciHeap.cs)\n    * [Pairing Heap](./DataStructures/Heap/PairingHeap/PairingHeap.cs)\n  * [Probabilistic](./DataStructures/Probabilistic)\n    * [BloomFilter](./DataStructures/Probabilistic/BloomFilter.cs)\n    * [Count-Min Sketch](./DataStructures/Probabilistic/CountMinSketch.cs)\n    * [HyperLogLog](./DataStructures/Probabilistic/HyperLogLog.cs)\n  * [Queue](./DataStructures/Queue)\n    * [Array-based Queue](./DataStructures/Queue/ArrayBasedQueue.cs)\n    * [List-based Queue](./DataStructures/Queue/ListBasedQueue.cs)\n    * [Stack-based Queue](./DataStructures/Queue/StackBasedQueue.cs)\n  * [Linked List](./DataStructures/LinkedList)\n    * [Singly Linked List](./DataStructures/LinkedList/SinglyLinkedList/SinglyLinkedList.cs)\n    * [Doubly Linked List](./DataStructures/LinkedList/DoublyLinkedList/DoublyLinkedList.cs)\n    * [Skip List](./DataStructures/LinkedList/SkipList/SkipList.cs)\n    * [Circular Linked List](./DataStructures/LinkedList/CircularLinkedList/CircularLinkedList.cs)\t\n  * [Graph](./DataStructures/Graph)\n    * [Directed Weighted Graph Via Adjacency Matrix](./DataStructures/Graph/DirectedWeightedGraph.cs)\n  * [Disjoint Set](./DataStructures/DisjointSet)\n  * [SortedList](./DataStructures/SortedList.cs)\n  * [Inverted index](./DataStructures/InvertedIndex.cs)\n  * [Unrolled linked list](./DataStructures/UnrolledList/UnrolledLinkedList.cs)\n  * [Tries](./DataStructures/Tries/Trie.cs)\n  * [HashTable](./DataStructures/Hashing/HashTable.cs)\n  * [Cache](./DataStructures/Cache)\n    * [Least Frequently Used (LFU) Cache](./DataStructures/Cache/LfuCache.cs)\n    * [Least Recently Used (LRU) Cache](./DataStructures/Cache/LruCache.cs)\n\n## Project Update: .NET 8 Migration\n\nAs part of our continuous effort to stay up-to-date with the latest technologies, we have migrated our project to .NET 8. This upgrade enhances our project with the latest features and improvements from the .NET ecosystem.\n\n### New Requirements\n\n* To build and run this project, **.NET 8 SDK** is now required.\n* Ensure your development tools are compatible with .NET 8.\n\n### Building the Project\n\n* With .NET 8 SDK installed, you can build the project using the standard `dotnet build` command.\n* All existing build scripts have been updated to accommodate the .NET 8 SDK.\n\n### Running Tests\n\n* Our comprehensive suite of unit tests ensures compatibility with .NET 8.\n* Run tests using the `dotnet test` command as usual.\n\n## Contributing\n\nYou can contribute with pleasure to this repository.\nPlease orient on the directory structure and overall code style of this repository\nand refer to [our contributing guidelines](./CONTRIBUTING.md) for more details.\nIf you want to ask a question or suggest something, please open an issue.\n"
  },
  {
    "path": "Utilities/Exceptions/ItemNotFoundException.cs",
    "content": "namespace Utilities.Exceptions;\n\n/// <summary>\n///     Signs that sequence doesn't contain any items that one was looking for.\n/// </summary>\npublic class ItemNotFoundException : Exception\n{\n}\n"
  },
  {
    "path": "Utilities/Extensions/DictionaryExtensions.cs",
    "content": "namespace Utilities.Extensions;\n\npublic static class DictionaryExtensions\n{\n    /// <summary>\n    ///     Adds the specified key value tuples to the dictionary.\n    /// </summary>\n    /// <param name=\"keys\">The dictionary.</param>\n    /// <param name=\"enumerable\">The collection of key value tuples to add.</param>\n    /// <typeparam name=\"TKey\">The type of the keys in the dictionary.</typeparam>\n    /// <typeparam name=\"TValue\">The type of the values in the dictionary.</typeparam>\n    /// <exception cref=\"ArgumentException\">\n    ///     A key from the <paramref name=\"enumerable\"/> already exists in <paramref name=\"keys\"/>.\n    /// </exception>\n    public static void AddMany<TKey, TValue>(\n        this Dictionary<TKey, TValue> keys,\n        IEnumerable<(TKey Key, TValue Value)> enumerable) where TKey : notnull\n    {\n        foreach (var (key, value) in enumerable)\n        {\n            keys.Add(key, value);\n        }\n    }\n}\n"
  },
  {
    "path": "Utilities/Extensions/MatrixExtensions.cs",
    "content": "namespace Utilities.Extensions;\n\npublic static class MatrixExtensions\n{\n    /// <summary>\n    ///     Performs immutable dot product multiplication on source matrix to operand.\n    /// </summary>\n    /// <param name=\"source\">Source left matrix.</param>\n    /// <param name=\"operand\">Operand right matrix.</param>\n    /// <returns>Dot product result.</returns>\n    /// <exception cref=\"InvalidOperationException\">The width of a first operand should match the height of a second.</exception>\n    public static double[,] Multiply(this double[,] source, double[,] operand)\n    {\n        if (source.GetLength(1) != operand.GetLength(0))\n        {\n            throw new InvalidOperationException(\n                \"The width of a first operand should match the height of a second.\");\n        }\n\n        var result = new double[source.GetLength(0), operand.GetLength(1)];\n\n        for (var i = 0; i < result.GetLength(0); i++)\n        {\n            for (var j = 0; j < result.GetLength(1); j++)\n            {\n                double elementProduct = 0;\n\n                for (var k = 0; k < source.GetLength(1); k++)\n                {\n                    elementProduct += source[i, k] * operand[k, j];\n                }\n\n                result[i, j] = elementProduct;\n            }\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Makes a copy of a matrix. Changes to the copy should not affect the original.\n    /// </summary>\n    /// <param name=\"matrix\">The matrix.</param>\n    /// <returns>A copy of the matrix.</returns>\n    public static double[,] Copy(this double[,] matrix)\n    {\n        var result = new double[matrix.GetLength(0), matrix.GetLength(1)];\n        for (var i = 0; i < matrix.GetLength(0); i++)\n        {\n            for (var j = 0; j < matrix.GetLength(1); j++)\n            {\n                result[i, j] = matrix[i, j];\n            }\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Transposes a matrix.\n    /// </summary>\n    /// <param name=\"matrix\">The matrix.</param>\n    /// <returns>The transposed matrix.</returns>\n    public static double[,] Transpose(this double[,] matrix)\n    {\n        var result = new double[matrix.GetLength(1), matrix.GetLength(0)];\n        for (var i = 0; i < matrix.GetLength(0); i++)\n        {\n            for (var j = 0; j < matrix.GetLength(1); j++)\n            {\n                result[j, i] = matrix[i, j];\n            }\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Multiplies a matrix by a vector.\n    /// </summary>\n    /// <param name=\"matrix\">The matrix.</param>\n    /// <param name=\"vector\">The vector.</param>\n    /// <returns>The product of the matrix and the vector, which is a vector.</returns>\n    /// <exception cref=\"ArgumentException\">Dimensions of matrix and vector do not match.</exception>\n    public static double[] MultiplyVector(this double[,] matrix, double[] vector)\n    {\n        var vectorReshaped = new double[vector.Length, 1];\n        for (var i = 0; i < vector.Length; i++)\n        {\n            vectorReshaped[i, 0] = vector[i];\n        }\n\n        var resultMatrix = matrix.Multiply(vectorReshaped);\n        var result = new double[resultMatrix.GetLength(0)];\n        for (var i = 0; i < result.Length; i++)\n        {\n            result[i] = resultMatrix[i, 0];\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Performs matrix subtraction.\n    /// </summary>\n    /// <param name=\"lhs\">The LHS matrix.</param>\n    /// <param name=\"rhs\">The RHS matrix.</param>\n    /// <returns>The difference of the two matrices.</returns>\n    /// <exception cref=\"ArgumentException\">Dimensions of matrices do not match.</exception>\n    public static double[,] Subtract(this double[,] lhs, double[,] rhs)\n    {\n        if (lhs.GetLength(0) != rhs.GetLength(0) ||\n            lhs.GetLength(1) != rhs.GetLength(1))\n        {\n            throw new ArgumentException(\"Dimensions of matrices must be the same\");\n        }\n\n        var result = new double[lhs.GetLength(0), lhs.GetLength(1)];\n        for (var i = 0; i < lhs.GetLength(0); i++)\n        {\n            for (var j = 0; j < lhs.GetLength(1); j++)\n            {\n                result[i, j] = lhs[i, j] - rhs[i, j];\n            }\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Performs an element by element comparison on both matrices.\n    /// </summary>\n    /// <param name=\"source\">Source left matrix.</param>\n    /// <param name=\"operand\">Openrand right matrix.</param>\n    /// <returns>true: if all elements are the same; false otherwise.</returns>\n    public static bool IsEqual(this double[,] source, double[,] operand)\n    {\n        if (source.Length != operand.Length ||\n            source.GetLength(0) != operand.GetLength(0) ||\n            source.GetLength(1) != operand.GetLength(1))\n        {\n            return false;\n        }\n\n        for (var i = 0; i < source.GetLength(0); i++)\n        {\n            for (var j = 0; j < source.GetLength(0); j++)\n            {\n                if (Math.Abs(source[i, j] - operand[i, j]) >= 0.0001)\n                {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    ///     Performs a round operation on every element of the input matrix up to the neareast integer.\n    /// </summary>\n    /// <param name=\"source\">Input matrix.</param>\n    /// <returns>Matrix with rounded elements.</returns>\n    public static double[,] RoundToNextInt(this double[,] source)\n    {\n        var rows = source.GetLength(0);\n        var cols = source.GetLength(1);\n\n        var result = new double[rows, cols];\n\n        for (var i = 0; i < rows; i++)\n        {\n            for (var j = 0; j < cols; j++)\n            {\n                result[i, j] = Math.Round(source[i, j]);\n            }\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "Utilities/Extensions/RandomExtensions.cs",
    "content": "namespace Utilities.Extensions;\n\npublic static class RandomExtensions\n{\n    /// <summary>\n    ///     Returns a random normalized vector of the specified size.\n    /// </summary>\n    /// <param name=\"rand\">The random number generator.</param>\n    /// <param name=\"size\">The size of the vector to return.</param>\n    /// <returns>A random normalized vector.</returns>\n    public static double[] NextVector(this Random rand, int size)\n    {\n        var vector = Enumerable.Range(0, size)\n            .Select(_ => rand.NextDouble()).ToArray();\n        var norm = vector.Magnitude();\n        return vector.Select(x => x / norm).ToArray();\n    }\n}\n"
  },
  {
    "path": "Utilities/Extensions/VectorExtensions.cs",
    "content": "namespace Utilities.Extensions;\n\npublic static class VectorExtensions\n{\n    /// <summary>\n    ///     Makes a copy of a vector. Changes to the copy should not affect the original.\n    /// </summary>\n    /// <param name=\"vector\">The vector.</param>\n    /// <returns>The copy.</returns>\n    public static double[] Copy(this double[] vector)\n    {\n        var result = new double[vector.Length];\n        for (var i = 0; i < vector.Length; i++)\n        {\n            result[i] = vector[i];\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Computes the outer product of two vectors.\n    /// </summary>\n    /// <param name=\"lhs\">The LHS vector.</param>\n    /// <param name=\"rhs\">The RHS vector.</param>\n    /// <returns>The outer product of the two vector.</returns>\n    public static double[,] OuterProduct(this double[] lhs, double[] rhs)\n    {\n        var result = new double[lhs.Length, rhs.Length];\n        for (var i = 0; i < lhs.Length; i++)\n        {\n            for (var j = 0; j < rhs.Length; j++)\n            {\n                result[i, j] = lhs[i] * rhs[j];\n            }\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Computes the dot product of two vectors.\n    /// </summary>\n    /// <param name=\"lhs\">The LHS vector.</param>\n    /// <param name=\"rhs\">The RHS vector.</param>\n    /// <returns>The dot product of the two vector.</returns>\n    /// <exception cref=\"ArgumentException\">Dimensions of vectors do not match.</exception>\n    public static double Dot(this double[] lhs, double[] rhs)\n    {\n        if (lhs.Length != rhs.Length)\n        {\n            throw new ArgumentException(\"Dot product arguments must have same dimension\");\n        }\n\n        double result = 0;\n        for (var i = 0; i < lhs.Length; i++)\n        {\n            result += lhs[i] * rhs[i];\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Computes the magnitude of a vector.\n    /// </summary>\n    /// <param name=\"vector\">The vector.</param>\n    /// <returns>The magnitude.</returns>\n    public static double Magnitude(this double[] vector)\n    {\n        return Math.Sqrt(Dot(vector, vector));\n    }\n\n    /// <summary>\n    ///     Returns the scaled vector.\n    /// </summary>\n    /// <param name=\"vector\">The vector.</param>\n    /// <param name=\"factor\">Scale factor.</param>\n    /// <returns>The unit vector.</returns>\n    public static double[] Scale(this double[] vector, double factor)\n    {\n        var result = new double[vector.Length];\n        for (var i = 0; i < vector.Length; i++)\n        {\n            result[i] = vector[i] * factor;\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    ///     Transpose 1d row vector to column vector.\n    /// </summary>\n    /// <param name=\"source\">Input 1d vector.</param>\n    /// <returns>Column vector.</returns>\n    public static double[,] ToColumnVector(this double[] source)\n    {\n        var columnVector = new double[source.Length, 1];\n\n        for (var i = 0; i < source.Length; i++)\n        {\n            columnVector[i, 0] = source[i];\n        }\n\n        return columnVector;\n    }\n\n    /// <summary>\n    ///     Transpose column vector to 1d row vector.\n    /// </summary>\n    /// <param name=\"source\">Input column vector.</param>\n    /// <returns>Row vector.</returns>\n    /// <exception cref=\"InvalidOperationException\">The column vector should have only 1 element in width.</exception>\n    public static double[] ToRowVector(this double[,] source)\n    {\n        if (source.GetLength(1) != 1)\n        {\n            throw new InvalidOperationException(\"The column vector should have only 1 element in width.\");\n        }\n\n        var rowVector = new double[source.Length];\n\n        for (var i = 0; i < rowVector.Length; i++)\n        {\n            rowVector[i] = source[i, 0];\n        }\n\n        return rowVector;\n    }\n\n    /// <summary>\n    ///     Generates a diagonal matrix from an specified vector.\n    /// </summary>\n    /// <param name=\"vector\">The input vector.</param>\n    /// <returns>A Diagonal matrix.</returns>\n    public static double[,] ToDiagonalMatrix(this double[] vector)\n    {\n        var len = vector.Length;\n        var result = new double[len, len];\n\n        for (var i = 0; i < len; i++)\n        {\n            result[i, i] = vector[i];\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "Utilities/GlobalUsings.cs",
    "content": "// -----------------------------------------------------------------------------\n// Global using directives for the C-Sharp solution.\n// These namespaces are imported globally so they don’t need to be repeatedly declared\n// in individual files, improving readability and reducing boilerplate.\n//\n// Guidelines:\n// - Keep only the most commonly used namespaces here.\n// - Add project-specific namespaces (e.g., Utilities.Extensions) only if they are\n//   required across the majority of files in the project.\n// - Avoid placing rarely used namespaces here to maintain clarity.\n// -----------------------------------------------------------------------------\n\nglobal using System;                        // Core base classes and fundamental types\nglobal using System.Collections.Generic;    // Generic collection types (List, Dictionary, etc.)\nglobal using System.Linq;                   // LINQ query operators for collections\n"
  },
  {
    "path": "Utilities/Utilities.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <CodeAnalysisRuleSet>..\\stylecop.ruleset</CodeAnalysisRuleSet>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n    <DocumentationFile>./bin/Utilities.xml</DocumentationFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <AdditionalFiles Include=\"..\\stylecop.json\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"StyleCop.Analyzers\" Version=\"1.2.0-beta.556\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Utilities.Tests/Extensions/DictionaryExtensionsTests.cs",
    "content": "namespace Utilities.Tests.Extensions;\n\npublic class DictionaryExtensionsTests\n{\n    [Test]\n    public void AddMany_ShouldThrowArgumentException_WhenKeyAlreadyExists()\n    {\n        var dictionary = new Dictionary<string, int> { [\"one\"] = 1 };\n        var enumerable = new[] { (\"one\", 1), (\"two\", 2) };\n\n        var action = () => dictionary.AddMany(enumerable);\n\n        action.Should().Throw<ArgumentException>();\n    }\n\n    [Test]\n    public void AddMany_ShouldAddAllKeyValuePairs()\n    {\n        var dictionary = new Dictionary<string, int> { [\"one\"] = 1 };\n        var enumerable = new[] { (\"two\", 2), (\"three\", 3) };\n\n        dictionary.AddMany(enumerable);\n\n        dictionary.Should().HaveCount(3);\n\n        dictionary.Should().ContainKey(\"one\").WhoseValue.Should().Be(1);\n        dictionary.Should().ContainKey(\"two\").WhoseValue.Should().Be(2);\n        dictionary.Should().ContainKey(\"three\").WhoseValue.Should().Be(3);\n    }\n\n    [Test]\n    public void AddMany_ShouldNotChangeDictionary_WhenEnumerableIsEmpty()\n    {\n        var dictionary = new Dictionary<string, int> { [\"one\"] = 1 };\n        var enumerable = Array.Empty<(string, int)>();\n\n        dictionary.AddMany(enumerable);\n\n        dictionary.Should().HaveCount(1);\n        dictionary.Should().ContainKey(\"one\").WhoseValue.Should().Be(1);\n    }\n\n    [Test]\n    public void AddMany_ShouldThrowArgumentNullException_WhenDictionaryIsNull()\n    {\n        Dictionary<string, int> dictionary = null!;\n        var enumerable = new[] { (\"one\", 1) };\n\n        var action = () => dictionary.AddMany(enumerable);\n\n        action.Should().Throw<NullReferenceException>();\n    }\n\n    [Test]\n    public void AddMany_ShouldThrowArgumentNullException_WhenEnumerableIsNull()\n    {\n        var dictionary = new Dictionary<string, int> { [\"one\"] = 1 };\n        IEnumerable<(string, int)> enumerable = null!;\n\n        var action = () => dictionary.AddMany(enumerable);\n\n        action.Should().Throw<NullReferenceException>();\n    }\n\n    [Test]\n    public void AddMany_ShouldAllowNullValues_WhenValueTypeIsNullable()\n    {\n        var dictionary = new Dictionary<string, int?> { [\"one\"] = 1 };\n        var enumerable = new[] { (\"two\", (int?)null) };\n\n        dictionary.AddMany(enumerable);\n\n        dictionary.Should().HaveCount(2);\n        dictionary.Should().ContainKey(\"two\").WhoseValue.Should().Be(null);\n    }\n\n\n    [Test]\n    public void AddMany_ShouldAllowNullValue_WhenValueIsNullable()\n    {\n        var dictionary = new Dictionary<int, string?>();  // Key type is int, value type is nullable string\n        var enumerable = new[]\n        {\n                (1, null),  // null value\n                (2, \"banana\")\n            };\n\n        dictionary.AddMany(enumerable);\n\n        dictionary.Should().ContainKey(1).WhoseValue.Should().BeNull();\n        dictionary.Should().ContainKey(2).WhoseValue.Should().Be(\"banana\");\n    }\n\n    [Test]\n    public void AddMany_ShouldThrowArgumentException_WhenAddingDuplicateKey()\n    {\n        var dictionary = new Dictionary<int, string>();  // Key type is int, value type is nullable string\n        var enumerable = new[]\n        {\n                (1, \"Things\"),   // First entry\n                (2, \"Stuff\"),\n                (1, \"That Thing\")   // Duplicate key (should throw exception)\n            };\n\n        var action = () => dictionary.AddMany(enumerable);\n\n        action.Should().Throw<ArgumentException>();  // Adding a duplicate key should throw ArgumentException\n    }\n\n    [Test]\n    public void AddMany_ShouldAddManyKeyValuePairs_WhenAddingLargeEnumerable()\n    {\n        var dictionary = new Dictionary<int, string>();\n        var enumerable = new List<(int, string)>();\n\n        // Create a large enumerable\n        for (int i = 0; i < 10000; i++)\n        {\n            enumerable.Add((i, \"Value\" + i));\n        }\n\n        dictionary.AddMany(enumerable);\n\n        dictionary.Should().HaveCount(10000);\n        dictionary[9999].Should().Be(\"Value9999\");\n    }\n}\n"
  },
  {
    "path": "Utilities.Tests/Extensions/MatrixExtensionsTests.cs",
    "content": "namespace Utilities.Tests.Extensions;\n\npublic class MatrixExtensionsTests\n{\n    private static readonly object[] MatrixMultiplyTestCases =\n    [\n        new object[]\n        {\n            new double[,] { { 2, 2, -1 }, { 0, -2, -1 }, { 0, 0, 5 } },\n            new double[,] { { 2 }, { 2 }, { 3 } },\n            new double[,] { { 5 }, { -7 }, { 15 } },\n        },\n        new object[]\n        {\n            new double[,] { { 5, 8, -4 }, { 6, 9, -5 }, { 4, 7, -3 } },\n            new double[,] { { 3, 2, 5 }, { 4, -1, 3 }, { 9, 6, 5 } },\n            new double[,] { { 11, -22, 29 }, { 9, -27, 32 }, { 13, -17, 26 } },\n        },\n    ];\n\n    private static readonly object[] MatrixTransposeTestCases =\n    [\n        new object[]\n        {\n            new double[,] { { 2, 2, 3 } },\n            new double[,] { { 2 }, { 2 }, { 3 } },\n        },\n        new object[]\n        {\n            new double[,] { { 5, 8 }, { 6, 9 } },\n            new double[,] { { 5, 6 }, { 8, 9 } },\n        },\n    ];\n\n    private static readonly object[] MatrixSubtractTestCases =\n    [\n        new object[]\n        {\n            new double[,] { { 0, 0 }, { 0, 0 } },\n            new double[,] { { 1, 1 }, { 1, 1 } },\n            new double[,] { { -1, -1 }, { -1, -1 } },\n        },\n        new object[]\n        {\n            new double[,] { { 1, 2 }, { 2, 3 }, { 3, 4 } },\n            new double[,] { { 1, 1 }, { 1, 1 }, { 1, 1 } },\n            new double[,] { { 0, 1 }, { 1, 2 }, { 2, 3 } },\n        },\n        new object[]\n        {\n            new double[,] { { -1, -2, 0 }, { 2, -3, 2 }, { 3, 4, 1 } },\n            new double[,] { { 2, 5, 12 }, { 0, 5, 1 }, { 1, 1, 4 } },\n            new double[,] { { -3, -7, -12 }, { 2, -8, 1 }, { 2, 3, -3 } },\n        },\n    ];\n\n    [Test]\n    public void Multiply_ShouldThrowInvalidOperationException_WhenOperandsAreNotCompatible()\n    {\n        // Arrange\n        var source = new double[,] { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } };\n        var operand = new double[,] { { 1 }, { 1 } };\n\n        // Act\n        Action action = () => source.Multiply(operand);\n\n        // Assert\n        action.Should().Throw<InvalidOperationException>()\n            .WithMessage(\"The width of a first operand should match the height of a second.\");\n    }\n\n    [TestCaseSource(nameof(MatrixMultiplyTestCases))]\n    public void Multiply_ShouldCalculateDotProductMultiplicationResult(\n        double[,] source,\n        double[,] operand,\n        double[,] result) =>\n        source.Multiply(operand).Should().BeEquivalentTo(result);\n\n    [Test]\n    public void Copy_ShouldReturnImmutableCopyOfMatrix()\n    {\n        // Arrange\n        var sutMatrix = new double[,] { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } };\n\n        // Act\n        var actualMatrix = sutMatrix.Copy();\n\n        // Assert\n        actualMatrix.Should().NotBeSameAs(sutMatrix);\n        actualMatrix.Should().BeEquivalentTo(sutMatrix);\n    }\n\n    [TestCaseSource(nameof(MatrixTransposeTestCases))]\n    public void Transpose_ShouldReturnTransposedMatrix(\n        double[,] source,\n        double[,] target) =>\n        source.Transpose().Should().BeEquivalentTo(target);\n\n    [Test]\n    public void MultiplyVector_ShouldCalculateDotProductMultiplicationResult()\n    {\n        // Arrange\n        var source = new double[,] { { 2, 2, -1 }, { 0, -2, -1 }, { 0, 0, 5 } };\n        var operand = new double[] { 2, 2, 3 };\n        var result = new double[] { 5, -7, 15 };\n\n        // Act\n        var actualMatrix = source.MultiplyVector(operand);\n\n        // Assert\n        actualMatrix.Should().BeEquivalentTo(result);\n    }\n\n    [Test]\n    public void Subtract_ShouldThrowArgumentException_WhenOperandsAreNotCompatible()\n    {\n        // Arrange\n        var source = new double[,] { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } };\n        var operand = new double[,] { { 1 }, { 1 } };\n\n        // Act\n        Action action = () => source.Subtract(operand);\n\n        // Assert\n        action.Should().Throw<ArgumentException>()\n            .WithMessage(\"Dimensions of matrices must be the same\");\n    }\n\n    [Test]\n    public static void EqualMatricesShouldReturnTrue()\n    {\n        // Arrange\n        var a = new double[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } };\n        var b = new double[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } };\n\n        // Act\n        var result = a.IsEqual(b);\n\n        // Assert\n        Assert.That(result, Is.True);\n    }\n\n    [Test]\n    public static void NonEqualMatricesShouldReturnFalse()\n    {\n        // Arrange\n        var a = new double[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } };\n        var b = new double[,] { { 1, 2, 3 }, { 1, 2, 6 }, { 1, 2, 3 } };\n\n        // Act\n        var result = a.IsEqual(b);\n\n        // Assert\n        Assert.That(result, Is.False);\n    }\n\n    [Test]\n    public static void DifferentSizeMatricesShouldReturnFalse()\n    {\n        // Arrange\n        var a = new double[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } };\n        var b = new double[,] { { 1, 2, 3 }, { 1, 2, 3 } };\n\n        // Act\n        var result = a.IsEqual(b);\n\n        // Assert\n        Assert.That(result, Is.False);\n    }\n\n    [TestCaseSource(nameof(MatrixSubtractTestCases))]\n    public void Subtract_ShouldCalculateSubtractionResult(\n        double[,] source,\n        double[,] operand,\n        double[,] result) =>\n        source.Subtract(operand).Should().BeEquivalentTo(result);\n\n    [Test]\n    public void RoundToNextInt_ShouldReturnRoundedMatrix()\n    {\n        var source = new[,]\n        {\n            { -1.9, 1.9 },\n            { -1.5, 1.5 },\n            { -1.1, 1.1 },\n            { -0.9, 0.9 },\n            { -0.5, 0.5 },\n            { -0.1, 0.1 },\n        };\n\n        var result = new double[,]\n        {\n            { -2, 2 },\n            { -2, 2 },\n            { -1, 1 },\n            { -1, 1 },\n            { 0, 0 },\n            { 0, 0 },\n        };\n\n        var actualResult = source.RoundToNextInt();\n\n        actualResult.Should().BeEquivalentTo(result);\n    }\n}\n"
  },
  {
    "path": "Utilities.Tests/Extensions/RandomExtensionsTests.cs",
    "content": "namespace Utilities.Tests.Extensions;\n\npublic class RandomExtensionsTests\n{\n    [Test]\n    public void NextVector_ShouldReturnNormalizedVector()\n    {\n        var random = new Random(0);\n\n        var result = random.NextVector(10);\n\n        result.Length.Should().Be(10);\n        result.Magnitude().Should().BeApproximately(1.0, 1e-6);\n    }\n}\n"
  },
  {
    "path": "Utilities.Tests/Extensions/VectorExtensionsTests.cs",
    "content": "namespace Utilities.Tests.Extensions;\n\npublic class VectorExtensionsTests\n{\n    [Test]\n    public void Copy_ShouldReturnCopyOfVector()\n    {\n        var vector = new double[] { 0, 1, 2, 3 };\n\n        var vectorCopy = vector.Copy();\n\n        vectorCopy.Should().BeEquivalentTo(vector);\n        vectorCopy.Should().NotBeSameAs(vector);\n    }\n\n    [Test]\n    public void OuterProduct_ShouldCalculateOuterProduct()\n    {\n        var lhs = new double[] { -2, -1, 0, 1, 2 };\n        var rhs = new double[] { 1, 2, 3 };\n\n        var result = new double[,]\n        {\n            { -2, -4, -6 },\n            { -1, -2, -3 },\n            { 0, 0, 0 },\n            { 1, 2, 3 },\n            { 2, 4, 6 },\n        };\n\n        var actualResult = lhs.OuterProduct(rhs);\n\n        actualResult.Should().BeEquivalentTo(result);\n    }\n\n    [Test]\n    public void Dot_ShouldThrowArgumentException_WhenDimensionsDoNotMatch()\n    {\n        var lhs = new double[] { 1, 2, 3 };\n        var rhs = new double[] { 1, 2, 3, 4 };\n\n        var func = () => lhs.Dot(rhs);\n\n        func.Should().Throw<ArgumentException>()\n            .WithMessage(\"Dot product arguments must have same dimension\");\n    }\n\n    [Test]\n    public void Dot_ShouldCalculateDotProduct()\n    {\n        var lhs = new double[] { 1, 2, 3 };\n        var rhs = new double[] { 4, 5, 6 };\n\n        var actualResult = lhs.Dot(rhs);\n\n        actualResult.Should().Be(32);\n    }\n\n    [Test]\n    public void Magnitude_ShouldCalculateMagnitude()\n    {\n        var vector = new double[] { -3, 4 };\n\n        var actualResult = vector.Magnitude();\n\n        actualResult.Should().BeApproximately(5.0, 0.0001);\n    }\n\n    [Test]\n    public void Scale_ShouldCalculateScale()\n    {\n        var vector = new double[] { -1, 0, 1 };\n        var factor = 2;\n\n        var result = new double[] { -2, 0, 2 };\n\n        var actualResult = vector.Scale(factor);\n\n        actualResult.Should().BeEquivalentTo(result);\n    }\n\n    [Test]\n    public void ToColumnVector_ShouldReturnColumnVector()\n    {\n        var vector = new double[] { 1, 2, 3, 4 };\n        var result = new double[,] { { 1 }, { 2 }, { 3 }, { 4 } };\n\n        var actualResult = vector.ToColumnVector();\n\n        actualResult.Should().BeEquivalentTo(result);\n    }\n\n    [Test]\n    public void ToRowVector_ShouldThrowInvalidOperationException_WhenSourceIsNotAColumnVector()\n    {\n        var source = new double[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } };\n\n        var func = () => source.ToRowVector();\n\n        func.Should().Throw<InvalidOperationException>()\n            .WithMessage(\"The column vector should have only 1 element in width.\");\n    }\n\n    [Test]\n    public void ToRowVector_ShouldReturnRowVector()\n    {\n        var source = new double[,] { { 1 }, { 2 }, { 3 }, { 4 } };\n        var result = new double[] { 1, 2, 3, 4 };\n\n        var actualResult = source.ToRowVector();\n\n        actualResult.Should().BeEquivalentTo(result);\n    }\n\n    [Test]\n    public void ToDiagonalMatrix_ShouldReturnDiagonalMatrix()\n    {\n        var source = new double[] { 1, 2, 3, 4 };\n        var result = new double[,]\n        {\n            { 1, 0, 0, 0 },\n            { 0, 2, 0, 0 },\n            { 0, 0, 3, 0 },\n            { 0, 0, 0, 4 },\n        };\n\n        var actualResult = source.ToDiagonalMatrix();\n\n        actualResult.Should().BeEquivalentTo(result);\n    }\n}\n"
  },
  {
    "path": "Utilities.Tests/GlobalUsings.cs",
    "content": "// -----------------------------------------------------------------------------\n// Global using directives for the C-Sharp solution.\n// These namespaces are imported globally so they don’t need to be repeatedly declared\n// in individual files, improving readability and reducing boilerplate.\n//\n// Guidelines:\n// - Keep only the most commonly used namespaces here.\n// - Add project-specific namespaces (e.g., Utilities.Extensions) only if they are\n//   required across the majority of files in the project.\n// - Avoid placing rarely used namespaces here to maintain clarity.\n// -----------------------------------------------------------------------------\n\nglobal using System;                        // Core base classes and fundamental types\nglobal using System.Collections.Generic;    // Generic collection types (List, Dictionary, etc.)\nglobal using FluentAssertions;              // Assertion library for more readable and expressive unit tests\nglobal using NUnit.Framework;               // Testing framework providing attributes and assertions for test cases\nglobal using Utilities.Extensions;          // Common project-specific extension methods reused across multiple files\n"
  },
  {
    "path": "Utilities.Tests/Utilities.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <IsPackable>false</IsPackable>\n    <CodeAnalysisRuleSet>..\\stylecop.ruleset</CodeAnalysisRuleSet>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <AdditionalFiles Include=\"..\\stylecop.json\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.0\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"FluentAssertions\" Version=\"6.12.0\" />\n    <PackageReference Include=\"NUnit\" Version=\"4.0.1\" />\n    <PackageReference Include=\"NUnit3TestAdapter\" Version=\"4.5.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.8.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Utilities\\Utilities.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "stylecop.json",
    "content": "﻿{\n  \"$schema\": \"https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json\",\n  \"settings\": {\n    \"indentation\": {\n      \"useTabs\": false\n    },\n    \"layoutRules\": {\n      \"newlineAtEndOfFile\": \"require\"\n    },\n    \"orderingRules\": {\n      \"blankLinesBetweenUsingGroups\": \"omit\",\n      \"usingDirectivesPlacement\": \"outsideNamespace\"\n    }\n  }\n}\n"
  },
  {
    "path": "stylecop.ruleset",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RuleSet Name=\"Rules for C-Sharp\" Description=\"Code analysis rules for projects in C-Sharp solution\" ToolsVersion=\"16.0\">\n  <Rules AnalyzerId=\"StyleCop.Analyzers\" RuleNamespace=\"StyleCop.Analyzers\">\n    <Rule Id=\"SA1000\" Action=\"None\" />\n    <Rule Id=\"SA1101\" Action=\"None\" />\n    <Rule Id=\"SA1127\" Action=\"None\" />\n    <Rule Id=\"SA1201\" Action=\"None\" />\n    <Rule Id=\"SA1407\" Action=\"None\" />\n    <Rule Id=\"SA1408\" Action=\"None\" />\n    <Rule Id=\"CS1573\" Action=\"None\" />\n    <Rule Id=\"CS1591\" Action=\"None\" />\n    <Rule Id=\"CS1723\" Action=\"None\" />\n    <Rule Id=\"SA1600\" Action=\"None\" />\n    <Rule Id=\"SA1611\" Action=\"None\" />\n    <Rule Id=\"SA1615\" Action=\"None\" />\n    <Rule Id=\"SA1633\" Action=\"None\" />\n  </Rules>\n</RuleSet>\n"
  }
]