Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/ZacharyPatten/Towel

Throw in the towel.
https://github.com/ZacharyPatten/Towel

algorithm avl-tree command-line console csharp data-structures dotnet extensions framework functional library mathematics measurements random red-black-trees sorting towel xml

Last synced: 18 days ago
JSON representation

Throw in the towel.

Lists

README

        




Towel


A .NET library intended to make coding a bit more towelerable: data structures, algorithms, mathematics, metadata, extensions, console, and more. :)

> "It's a tough galaxy. If you want to survive, you've gotta know... where your towel is." - Ford Prefect











> _**Note** This project has a goal of keeping up-to-date on modern coding practices rather than maintaining backwards compatibility such as targetting the latest non-preview version of .NET and embracing favorable breaking changes ("Semantic Versioning" is not being respected at this time)._

## Getting Started

Run The Included Examples [Expand]

> Towel has [Examples](https://github.com/ZacharyPatten/Towel/tree/main/Examples) included in this repository.
>
> [Download](https://github.com/ZacharyPatten/Towel/archive/main.zip) this repository and unzip the contents.
>
> There are no custom build processes. Towel should build with any standard .NET build process, but one of the following is recommended:
>
>
>
> Visual Studio [Expand]
>
>


>
> > 1. Install [Visual Studio](https://visualstudio.microsoft.com/) if not already installed.
> >
> > 2. Open the **`Towel.sln`** file in Visual Studio.
> >
> > - _(optional) [Here are some settings you change in Visual Studio](https://gist.github.com/ZacharyPatten/693f35653f6c21fbe6c85444792e524b)._
>
>


>
>
>
>
> Visual Studio Code [Expand]
>
>


>
> > 1. Install the [.NET SDK](https://dotnet.microsoft.com/download) if not already installed.
> >
> > 2. Install [Visual Studio Code](https://visualstudio.microsoft.com/) if not already installed.
> >
> > 3. Open the **`root folder`** of the repository in Visual Studio Code.
> >
> > _The following files are included in the repository:_
> > - `.vscode/extensions.json` recommends Vistual Studio Code extension dependencies
> > - `.vscode/launch.json` includes the configurations for debugging the examples
> > - `.vscode/settings.json` automatically applies settings to the workspace
> > - `.vscode/tasks.json` includes the commands to build the projects
> >
> > _Visual Studio Code Extensions (will be prompted to install these when you open the folder):_
> > - `ms-vscode.csharp` C# support
> > - `formulahendry.dotnet-test-explorer` _(optional)_ MSTest unit testing support
> > - `aisoftware.tt-processor` _(optional)_ T4 Template support
> > - `zbecknell.t4-support` _(optional)_ T4 Template syntax highlighting
>
>


>

Use Towel In Your .NET Projects [Expand]

> - Your project must target the same or newer version of .NET as Towel. [See this documentation on how to check the current target of your project](https://docs.microsoft.com/en-us/dotnet/standard/frameworks). Towel targets the following version of .NET:
>
> - Towel has a nuget package:
Instructions on how to reference the package are included on nuget.org _(click the badge)_.
>
> - If you use Towel and would be willing to show it, here is a badge you can copy-paste into your readme:
> ```html
>
> ```
>
> - Share your work. If you use Towel in one of your projects we want to hear about it. :)

View Documentation [Expand]

> - Change Log: https://github.com/ZacharyPatten/Towel/releases
> - [docfx](https://github.com/dotnet/docfx) generated API documentation reference:
> - [Coverlet](https://github.com/coverlet-coverage/coverlet) + [ReportGenerator](https://github.com/danielpalme/ReportGenerator) generated test coverage report:
> - [BenchmarkDotNet](https://github.com/dotnet/BenchmarkDotNet) generated benchmarking: https://zacharypatten.github.io/Towel/articles/benchmarks.html
>
> Relevant Articles:
>
> - [MSDN Accessing XML Documentation Via Reflection](https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/october/csharp-accessing-xml-documentation-via-reflection)
> - [Beginner's Guide To Console Input In C#](https://gist.github.com/ZacharyPatten/798ed612d692a560bdd529367b6a7dbd)
> - [Generating Unique Random Data](https://gist.github.com/ZacharyPatten/c9b43a2c9e8a5a5523883e77410f742d)
> - [Random Generation (with efficient exclusions)](https://gist.github.com/ZacharyPatten/8de188b2bd358ab5c3517cbb55e83632)
> - [Omnitree](https://gist.github.com/ZacharyPatten/f21fc5c6835faea9be8ae4baab4e294e)
> - [C# Generic Math](https://gist.github.com/ZacharyPatten/8e1395a94928f2c7715cf939b0d0389c)
>
> File Structure Overview _(except for `gh-pages`)_:
>
> - `.github` content regarding the GitHub repoistory.
> - `ISSUE_TEMPLATE` templates for issue submissions to the GitHub repository
> - `Resources` resources such as image files
> - `workflows` [GitHub Actions](https://github.com/ZacharyPatten/Towel/actions) workflows
> - `Continuous Integration.yml` workflow for checking that code compiles and unit tests pass
> - `Towel Deployment.yml` workflow to manage [releases](https://github.com/ZacharyPatten/Towel/releases) and deploy [nuget packages](https://www.nuget.org/packages/Towel)
> - `Documentation.yml` workflow that runs [docfx](https://github.com/dotnet/docfx) + [Coverlet](https://github.com/coverlet-coverage/coverlet) + [ReportGenerator](https://github.com/danielpalme/ReportGenerator) to output [GitHub Pages](https://pages.github.com/) to `gh-pages`
> - `pull_request_template.md` template for when pull requests are created
> - `.vscode` confirguration files for if the code is opened in [Visual Studio Code](https://visualstudio.microsoft.com/)
> - `Examples` root folder for all the example projects
> - `Sources` root folder for the source code of released nuget packages
> - **`Towel` the root folder for all source code in the Towel nuget package**
> - `Tools` root folder for all support projects (not included in nuget packages)
> - `docfx_project` root folder for [docfx](https://github.com/dotnet/docfx) project (used in `Documentation.yml`)
> - `articles` root folder for all articless of the [docfx](https://github.com/dotnet/docfx) generated [GitHub Pages](https://pages.github.com/) website
> - `apidoc` root folder for all api overrides of the [docfx](https://github.com/dotnet/docfx) generated [GitHub Pages](https://pages.github.com/) website
> - `docfx.json` configuration file that controls [docfx](https://github.com/dotnet/docfx)
> - `index.md` home page of the [docfx](https://github.com/dotnet/docfx) generated [GitHub Pages](https://pages.github.com/) website
> - `toc.yml` primary navigation for the [docfx](https://github.com/dotnet/docfx) generated [GitHub Pages](https://pages.github.com/) website
> - `Towel_Benchmarking` project with all the benchmarking for the Towel project
> - `Towel_Generating` project with code generation for the Towel Project
> - `Towel_Testing` project with all unit tests for the Towel project (used in `Continuous Integration.yml` and `Documentation.yml`)

Get Involved [Expand]

> - The easiest way to support Towel is to star the github repository.
>
> - If you have any questions, you can [start a new discussion](https://github.com/ZacharyPatten/Towel/discussions/new).
>
> - If you notice anything in Towel that may be improved, please [create a new issue](https://github.com/ZacharyPatten/Towel/issues/new/choose).

> Feature requests are welcome.
>
> - You can chat with the developer(s) on discord:
>
> - If you want to contribute to Towel:
  1. Fork this repository
  2. Make some changes
  3. Open a pull request

## Overview

Algorithms [Expand]

> ```cs
> // supports System.Span and any (non ref struct) int-indexed type
> IsPalindrome<...>(...);
>
> // supports System.ReadOnlySpan
> IsInterleavedRecursive<...>(...);
> IsInterleavedIterative<...>(...);
>
> IsReorderOf<...>(...); // aka "anagrams"
>
> // supports System.Span and any (non ref struct) int-indexed type
> SortShuffle(...);
> SortBubble(...);
> SortSelection(...);
> SortInsertion(...);
> SortQuick(...);
> SortMerge(...);
> SortHeap(...);
> SortOddEven(...);
> SortCocktail(...);
> SortComb(...);
> SortGnome(...);
> SortShell(...);
> SortBogo(...);
> SortSlow(...);
> SortCycle(...);
> SortPancake(...);
> SortStooge(...);
> SortTim(...);
> SortIntro(...);
> SortCounting(...); // uint-based (non-comparative sort)
> SortRadix(...); // uint-based (non-comparative sort)
> SortPidgeonHole(...); // int-based (non-comparative sort)
>
> // supports System.ReadOnlySpan and any (non ref struct) int-indexed type
> SearchBinary(...);
>
> // supports System.ReadOnlySpan and any (non ref struct) int-indexed type
> int HammingDistanceIterative<...>(...);
> int LevenshteinDistanceRecursive<...>(...);
> int LevenshteinDistanceIterative<...>(...);
>
> // Permutations of sequences
> // supports System.Span and any (non ref struct) int-indexed type
> void PermuteRecursive<...>(...);
> void PermuteIterative<...>(...);
>
> // Combinations of sequences
> void Combinations<...>(...);
>
> // Path Finding (Graph Search)
> // overloads for A*, Dijkstra, and Breadth-First-Search algorithms
> SearchGraph<...>(...);
>
> // Combines ranges without gaps between them
> IEnumerable<(T A, T B)> CombineRanges(IEnumerable<(T A, T B)> ranges)
> ```
>
> > [Sorting Algorithm Benchmarks](https://zacharypatten.github.io/Towel/benchmarks/SortBenchmarks.html) Note: not all permuations of the input are benchmarked, so take with a grain of salt.

> > [Permute Benchmarks](https://zacharypatten.github.io/Towel/benchmarks/PermuteBenchmarks.html)

Extensions [Expand]

> ```cs
> // System.Random extensions to generate more random types
> // there are overloads to specify possible ranges
> string NextString(this Random random, int length);
> char NextChar(this Random random);
> decimal NextDecimal(this Random random);
> DateTime DateTime(this Random random);
> TimeSpan TimeSpan(this Random random);
> long NextLong(this Random random);
> int[] Next(this Random random, int count, int minValue, int maxValue, Span excluded); // with exclusions
> int[] NextUnique(this Random random, int count, int minValue, int maxValue); // unique values
> int[] NextUnique(this Random random, int count, int minValue, int maxValue, Span excluded); // unique values with exclusions
> T Next(this Random random, IEnumerable<(T Value, double Weight)> pool); // weighted values
> void Shuffle(this Random random, T[] array); // randomize arrays
>
> // Type conversion to string definition as appears in C# source code
> string ConvertToCSharpSourceDefinition(this Type type);
> // Example: typeof(List) -> "System.Collections.Generic.List"
>
> string ToEnglishWords(this decimal @decimal);
> // Example: 42 -> "Forty-Two"
> (bool Success, decimal Value) TryParseEnglishWordsToDecimal(string words);
> // Example: "Forty-Two" -> 42
>
> int TryParseRomanNumeral(string @string);
> // Example: "XLII" -> 42
> int TryToRomanNumeral(int value);
> // Example: 42 -> "XLII"
>
> // Reflection Extensions To Access XML Documentation
> string GetDocumentation(this Type type);
> string GetDocumentation(this FieldInfo fieldInfo);
> string GetDocumentation(this PropertyInfo propertyInfo);
> string GetDocumentation(this EventInfo eventInfo);
> string GetDocumentation(this ConstructorInfo constructorInfo);
> string GetDocumentation(this MethodInfo methodInfo);
> string GetDocumentation(this MemberInfo memberInfo);
> string GetDocumentation(this ParameterInfo parameterInfo);
> ```
>
> > [Weighted Random Benchmarks](https://zacharypatten.github.io/Towel/benchmarks/WeightedRandomBenchmarks.html)

> > [Random With Exclusions Benchmarks](https://zacharypatten.github.io/Towel/benchmarks/RandomWithExclusionsBenchmarks.html)

> > [decimal To English Words Benchmarks](https://zacharypatten.github.io/Towel/benchmarks/ToEnglishWordsBenchmarks.html)

Data Structures [Expand]

>
>
> Heap [Expand]
>
>


>
> > ```cs
> > // A heap is a binary tree that is sorted vertically using comparison methods. This is different
> > // from AVL Trees or Red-Black Trees that keep their contents stored horizontally. The rule
> > // of a heap is that no parent can be less than either of its children. A Heap using "sifting up"
> > // and "sifting down" algorithms to move values vertically through the tree to keep items sorted.
> >
> > IHeap heap = HeapArray.New();
> >
> > // Visualization:
> > //
> > // Binary Tree
> > //
> > // -7
> > // / \
> > // / \
> > // / \
> > // / \
> > // / \
> > // / \
> > // / \
> > // / \
> > // -4 1
> > // / \ / \
> > // / \ / \
> > // / \ / \
> > // -1 3 6 4
> > // / \ / \ / \ / \
> > // 30 10 17 51 45 22 19 7
> > //
> > // Flattened into an Array
> > //
> > // Root = 1
> > // Left Child = 2 * Index
> > // Right Child = 2* Index + 1
> > // __________________________________________________________________________
> > // |0 |-7 |-4 |1 |-1 |3 |6 |4 |30 |10 |17 |51 |45 |22 |19 |7 |0 |0 |0 ...
> > // ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
> > // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
> > ```
>
>


>
>
>
>
> AVL Tree [Expand]
>
>


>
> > ```cs
> > // An AVL tree is a binary tree that is sorted using comparison methods and automatically balances
> > // itself by tracking the heights of nodes and performing one of four specific algorithms: rotate
> > // right, rotate left, double rotate right, or double rotate left. Any parent in an AVL Tree must
> > // be greater than its left child but less than its right child (if the children exist). An AVL
> > // tree is sorted in the same manor as a Red-Black Tree, but uses different algorithms to maintain
> > // the balance of the tree.
> >
> > IAvlTree avlTree = AvlTreeLinked.New();
> >
> > // Visualization:
> > //
> > // Binary Tree
> > //
> > // Depth 0 ------------------> 7
> > // / \
> > // / \
> > // / \
> > // / \
> > // / \
> > // / \
> > // / \
> > // / \
> > // Depth 1 ---------> 1 22
> > // / \ / \
> > // / \ / \
> > // / \ / \
> > // Depth 2 ----> -4 4 17 45
> > // / \ / \ / \ / \
> > // Depth 3 ---> -7 -1 3 6 10 19 30 51
> > //
> > // Flattened into an Array
> > //
> > // Root = 1
> > // Left Child = 2 * Index
> > // Right Child = 2* Index + 1
> > // __________________________________________________________________________
> > // |0 |7 |1 |22 |-4 |4 |17 |45 |-7 |-1 |3 |6 |10 |19 |30 |51 |0 |0 |0 ...
> > // ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
> > // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
> > ```
>
>


>
>
>
>
> Red Black Tree [Expand]
>
>


>
> > ```cs
> > // A Red-Black treeis a binary tree that is sorted using comparison methods and automatically
> > // balances itself. Any parent in an Red-Black Tree must be greater than its left child but less
> > // than its right child (if the children exist). A Red-Black tree is sorted in the same manor as
> > // an AVL Tree, but uses different algorithms to maintain the balance of the tree.
> >
> > IRedBlackTree redBlackTree = RedBlackTreeLinked.New();
> >
> > // Visualization:
> > //
> > // Binary Tree
> > //
> > // Color Black ----------------> 7
> > // / \
> > // / \
> > // / \
> > // / \
> > // / \
> > // / \
> > // / \
> > // / \
> > // Color Red ---------> 1 22
> > // / \ / \
> > // / \ / \
> > // / \ / \
> > // Color Black ---> -4 4 17 45
> > // / \ / \ / \ / \
> > // Color Red ---> -7 -1 3 6 10 19 30 51
> > //
> > // Flattened into an Array
> > //
> > // Root = 1
> > // Left Child = 2 * Index
> > // Right Child = 2* Index + 1
> > // __________________________________________________________________________
> > // |0 |7 |1 |22 |-4 |4 |17 |45 |-7 |-1 |3 |6 |10 |19 |30 |51 |0 |0 |0 ...
> > // ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
> > // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
> > ```
>
>


>
>
>
>
> Omnitree [Expand]
>
>


>
> > ```cs
> > // An Omnitree is a Spacial Partitioning Tree (SPT) that works on an arbitrary number of dimensions.
> > // It stores items sorted along multiple dimensions by dividing spaces into sub-spaces. A 3D
> > // version of an SPT is often called an "Octree" and a 2D version of an SPT is often called a
> > // "Quadtree." There are two versions of the Omnitree: Points and Bounds. The Points version stores
> > // vectors while the Bounds version stores spaces with a minimum and maximum vector.
> >
> > IOmnitreePoints omnitreePoints =
> > new OmnitreePointsLinked(
> > (T value, out A1 a1, out A2 a2, out A3 a3...) => { ... });
> >
> > IOmnitreeBounds omnitreeBounds =
> > new OmnitreeBoundsLinked(
> > (T value,
> > out A1 min1, out A1 max1,
> > out A2 min2, out A2 max2,
> > out A3 min3, out A3 max3...) => { ... });
> >
> > // The maximum number of children any node can have is 2 ^ N where N is the number
> > // of dimensions of the tree.
> > //
> > // -------------------------------
> > // | Dimensions | Max # Children |
> > // |============|================|
> > // | 1 | 2 ^ 1 = 2 |
> > // | 2 | 2 ^ 2 = 4 |
> > // | 3 | 2 ^ 3 = 8 |
> > // | 4 | 2 ^ 4 = 16 |
> > // | ... | ... |
> > // -------------------------------
> > //
> > // Visualizations
> > //
> > // 1 Dimensional:
> > //
> > // -1D |-----------|-----------| +1D Children Indexes:
> > // -1D: 0
> > // <--- 0 ---> <--- 1 ---> +1D: 1
> > //
> > // 2 Dimensional:
> > // _____________________
> > // | | | +2D
> > // | | | ^
> > // | 2 | 3 | | Children Indexes:
> > // | | | | -2D -1D: 0
> > // |----------|----------| | -2D +1D: 1
> > // | | | | +2D -1D: 2
> > // | | | | +2D +1D: 3
> > // | 0 | 1 | |
> > // | | | v
> > // |__________|__________| -2D
> > //
> > // -1D <-----------> +1D
> > //
> > // 3 Dimensional:
> > //
> > // +3D _____________________
> > // 7 / / /|
> > // / / 6 / 7 / |
> > // / /---------/----------/ | Children Indexes:
> > // / / 2 / 3 /| | -3D -2D -1D: 0
> > // L /_________/__________/ | | -3D -2D +1D: 1
> > // -3D | | | | /| +2D -3D +2D -1D: 2
> > // | | | |/ | ^ -3D +2D +1D: 3
> > // | 2 | 3 | / | | +3D -2D -1D: 4
> > // | | |/| | <-- 5 | +3D -2D +1D: 5
> > // |----------|----------| | | | +3D +2D -1D: 6
> > // | | | | / | +3D +2D +1D: 7
> > // | | | | / |
> > // | 0 | 1 | |/ |
> > // | | | / v
> > // |__________|__________|/ -2D
> > //
> > // ^
> > // |
> > // 4 (behind 0)
> > //
> > // -1D <-----------> +1D
> > //
> > // 4 Dimensional:
> > //
> > // +1D +2D +3D +4D Children Indexes:
> > // ^ ^ ^ ^
> > // | | | | -4D -3D -2D -1D: 0 +4D -3D -2D -1D: 8
> > // | | | | -4D -3D -2D +1D: 1 +4D -3D -2D +1D: 9
> > // | | | | -4D -3D +2D -1D: 2 +4D -3D +2D -1D: 10
> > // | | | | -4D -3D +2D +1D: 3 +4D -3D +2D +1D: 11
> > // | | | | -4D +3D -2D -1D: 4 +4D +3D -2D -1D: 12
> > // --- --- --- --- -4D +3D -2D +1D: 5 +4D +3D -2D +1D: 13
> > // | | | | -4D +3D +2D -1D: 6 +4D +3D +2D -1D: 14
> > // | | | | -4D +3D +2D +1D: 7 +4D +3D +2D +1D: 15
> > // | | | |
> > // | | | |
> > // | | | |
> > // v v v v
> > // -1D -2D -3D -4D
> > //
> > // With a value that is in the (+1D, -2D, -3D, +4D)[Index 9] child:
> > //
> > // +1D +2D +3D +4D
> > // ^ ^ ^ ^
> > // | | | |
> > // | | | |
> > // O--- | | ---O
> > // | \ | | / |
> > // | \ | | / |
> > // --- \ --- --- / ---
> > // | \ | | / |
> > // | \ | | / |
> > // | ---O-----------O--- |
> > // | | | |
> > // | | | |
> > // v v v v
> > // -1D -2D -3D -4D
> >
> > // By default, the omnitree will sort items along each axis and use the median algorithm to determine
> > // the point of divisions. However, you can override the subdivision algorithm. For numerical values,
> > // the mean algorithm can be used (and is much faster than median). If you know the data set will be
> > // relatively evenly distributed within a sub-space, you can even set the subdivision algorithm to
> > // calculate the subdivision from parent spaces rather than looking at the current contents of the
> > // space.
> >
> > // The depth of the omnitree is bounded by "ln(count)" the natural log of the current count. When adding
> > // and item to the tree, if the number of items in the respective child is greater than ln(count) and
> > // the depth bounding has not been reached, then the child will be subdivided. The goal is to achieve
> > // Ω(ln(count)) runtime complexity when looking up values.
> > ```
>
>


>
>
>
>
> B-Tree [Expand]
>
>


>
> > ```cs
> > // a B-tree is a self-balancing tree data structure that maintains
> > // sorted data and allows searches, sequential access, insertions,
> > // and deletions in logarithmic time. The B-tree generalizes the
> > // binary search tree, allowing for nodes with more than two children.
> >
> > // There are two ways to Add and Remove elements in a B-Tree
> > // 1) Pre-emptive: Search the tree from top to bottom (for place to add/
> > // node to delete) and perform fixing of the B-Tree (Splitting
> > // or Merging) in a single pass
> > // 2) Non Pre-emptive: Add/Remove the required node and go up the tree to
> > // fix the tree as needed
> > //
> > // Pre-emptive methods are optimal, especially if the Maximum Degree of
> > // a node is set to an even number. This implementation of B-Tree
> > // uses Pre-emptive modes of Add/Removal methods and therefore the
> > // value of Maximum Degree is mandated to be even
> >
> > // This implementation is taken from Thomas H. Cormen's book "Introduction
> > // to Algorithms, 3rd edition", Chapter 18: B-Trees
> >
> > BTree tree = new BTree(4);
> >
> > tree.Add(20);
> > tree.Add(10);
> > tree.Add(30);
> > tree.Add(50);
> > tree.Add(40);
> > tree.Add(5);
> > tree.Add(15);
> > //
> > // [20]
> > // / \
> > // / \
> > // [5, 10, 15] [30, 40, 50]
> > //
> > // All elements added in the BTree, where each node can have a maximum
> > // of 4 children (and therefore, a maximum of 3 elements)
> >
> > bool r1 = tree.TryRemove(50).Success; // r1 = true
> > bool r2 = tree.TryRemove(50).Success; // r2 = false, 50 is no longer in the tree
> >
> > //
> > // [20]
> > // / \
> > // / \
> > // [5, 10, 15] [30, 40]
> >
> > int[] array = tree.ToArray(); // array = [5, 10, 15, 20, 30, 40]
> > ```
> >
>


>
>
>
>
> Tree [Expand]
>
>


>
> > ```cs
> > ITree treeMap = TreeMap.New(...);
> > ```
>
>


>
>
>
>
> Graph [Expand]
>
>


>
> > ```cs
> > // A graph is a data structure that contains nodes and edges. They are useful
> > // when you need to model real world scenarios. They also are generally used
> > // for particular algorithms such as path finding. The GraphSetOmnitree is a
> > // graph that stores nodes in a hashed set and the edges in a 2D omnitree (aka
> > // quadtree).
> >
> > IGraph graph = GraphSetOmnitree.New();
> > // add nodes
> > graph.Add(0);
> > graph.Add(1);
> > graph.Add(2);
> > graph.Add(3);
> > // add edges
> > graph.Add(0, 1);
> > graph.Add(1, 2);
> > graph.Add(2, 3);
> > graph.Add(0, 3);
> > // visualization
> > //
> > // 0 --------> 1
> > // | |
> > // | |
> > // | |
> > // v v
> > // 3 <-------- 2
> > ```
>
>


>
>
>
>
> SkipList [Expand]
>
>


>
> > ```cs
> > // A skip list is a probabilistic data structure that stores data
> > // similar to a Linked List, but has additional layers which allow
> > // the list to perform basic operations (add/search/delete) in
> > // O(log n) average complexity
> >
> > SkipList>? list = SkipList.New(5); // create a list with 5 levels
> > list.Add(60);
> > list.Add(20);
> > list.Add(30);
> > list.Add(40);
> > list.Add(20);
> > list.Add(90);
> > list.Add(80);
> > // #-------------------->| |--------------------------------->NULL
> > // #-------------------->| |--------------------------->| |->NULL
> > // # ------------------->| |------------------->| |--->| |->NULL
> > // # ----------->| |--->| |--->| |----------->| |--->| |->NULL
> > // # --->|20|--->|20|--->|30|--->|40|--->|60|--->|80|--->|90|->NULL
> > //
> > // PS: SkipList nodes are assigned levels randomly, so this is one of the possible configurations obtainable
> > bool result;
> > result = list.Contains(40); //result = true
> > result = list.Remove(40).Suceess; // result = true
> > result = list.Contains(40); //result = false
> > ```
>
>


>
>
>
>
> Trie [Expand]
>
>


>
> > ```cs
> > // A trie is a tree that stores values in a way that partial keys may be shared
> > // amongst values to reduce redundant memory usage. They are generally used with
> > // large data sets such as storing all the words in the English language. For
> > // example, the words "farm" and "fart" both have the letters "far" in common.
> > // A trie takes advantage of that and only stores the necessary letters for
> > // those words ['f'->'a'->'r'->('t'||'m')]. A trie is not limited to string
> > // values though. Any key type that can be broken into pieces (and shared),
> > // could be used in a trie.
> > //
> > // There are two versions. One that only stores the values of the trie (ITrie)
> > // and one that stores the values of the trie plus an additional generic value
> > // on the leaves (ITrie).
> >
> > ITrie trie = TrieLinkedHashLinked.New();
> >
> > ITrie trie = TrieLinkedHashLinked.New();
> > ```
>
>


>

Generic Mathematics & Logic [Expand]

>
>
> How It Works [Expand]
>
>


>
> > ```cs
> > public static T Addition(T a, T b)
> > {
> > return AdditionImplementation.Function(a, b);
> > }
> >
> > internal static class AdditionImplementation
> > {
> > internal static Func Function = (T a, T b) =>
> > {
> > var A = Expression.Parameter(typeof(T));
> > var B = Expression.Parameter(typeof(T));
> > var BODY = Expression.Add(A, B);
> > Function = Expression.Lambda>(BODY, A, B).Compile();
> > return Function(a, b);
> > };
> > }
> > ```
> >
> > You can break type safe-ness using generic types and runtime compilation, and you can store the runtime compilation in a delegate so the only overhead is the invocation of the delegate.
>
>


>
>
> ```cs
> // Logic Fundamentals
> bool Equate(T a , T b);
> bool LessThan(T a, T b);
> bool GreaterThan(T a, T b);
> CompareResult Compare(T a, T b);
>
> // Mathematics Fundamentals
> T Negation(T a);
> T Addition(T a, T b);
> T Subtraction(T a, T b);
> T Multiplication(T a, T b);
> T Division(T a, T b);
> T Remainder(T a, T b);
>
> // More Logic
> bool IsPrime(T a);
> bool IsEven(T a);
> bool IsOdd(T a);
> T Minimum(T a, T b);
> T Maximum(T a, T b);
> T Clamp(T value, T floor, T ceiling);
> T AbsoluteValue(T a);
> bool EqualityLeniency(T a, T b, T leniency);
>
> // More Numerics
> void FactorPrimes(T a, ...);
> T Factorial(T a);
> T LinearInterpolation(T x, T x0, T x1, T y0, T y1);
> T LeastCommonMultiple(T a, T b, params T[] c);
> T GreatestCommonFactor(T a, T b, params T[] c);
> LinearRegression2D(..., out T slope, out T y_intercept);
>
> // Statistics
> T Mean(T a, params T[] b);
> T Median(params T[] values);
> Heap> Mode(T a, params T[] b);
> void Range(out T minimum, out T maximum, ...);
> T[] Quantiles(int quantiles, ...);
> T GeometricMean(...);
> T Variance(...);
> T StandardDeviation(...);
> T MeanDeviation(...);
>
> // Vectors
> Vector V1 = new Vector(params T[] vector);
> Vector V2 = new Vector(params T[] vector);
> Vector V3;
> T scalar;
> V3 = -V1; // Negate
> V3 = V1 + V2; // Add
> V3 = V1 - V2; // Subtract
> V3 = V1 * scalar; // Multiply
> V3 = V1 / scalar; // Divide
> scalar = V1.DotProduct(V2); // Dot Product
> V3 = V1.CrossProduct(V2); // Cross Product
> V1.Magnitude; // Magnitude
> V3 = V1.Normalize(); // Normalize
> bool equal = V1 == V2; // Equal
>
> // Matrices
> Matrix M1 = new Matrix(int rows, int columns);
> Matrix M2 = new Matrix(int rows, int columns);
> Matrix M3;
> Vector V2 = new Vector(params T[] vector);
> Vector V3;
> T scalar;
> M3 = -M1; // Negate
> M3 = M1 + M2; // Add
> M3 = M1 - M2; // Subtract
> M3 = M1 * M2; // Multiply
> V3 = M1 * V2; // Multiply (vector)
> M3 = M1 * scalar; // Multiply (scalar)
> M3 = M1 / scalar; // Divide
> M3 = M1 ^ 3; // Power
> scalar = M1.Determinent(); // Determinent
> M3 = M1.Minor(int row, int column); // Minor
> M3 = M1.Echelon(); // Echelon Form (REF)
> M3 = M1.ReducedEchelon(); // Reduced Echelon Form (RREF)
> M3 = M1.Inverse(); // Inverse
> M1.DecomposeLowerUpper(ref M2, ref M3); // Lower Upper Decomposition
> bool equal = M1 == M2; // Equal
> ```

Symbolic Mathematics [Expand]

> ```cs
> // Parsing From Linq Expression
> Expression> exp1 = (x) => 2 * (x / 7);
> Symbolics.Expression symExp1 = Symbolics.Parse(exp1);
>
> // Parsing From String
> Symbolics.Expression symExp2 = Symbolics.Parse("2 * ([x] / 7)");
>
> // Mathematical Simplification
> Symbolics.Expression simplified = symExp1.Simplify();
>
> // Variable Substitution
> symExp1.Substitute("x", 5);
> ```

Measurement Mathematics [Expand]

>
>
> Supported Measurements [Expand]
>
>


>
> > Here are the currently supported measurement types:
> >
> > ```cs
> > // Acceleration: Length/Time/Time
> > // AngularAcceleration: Angle/Time/Time
> > // Angle: Angle
> > // AngularSpeed: Angle/Time
> > // Area: Length*Length
> > // AreaDensity: Mass/Length/Length
> > // Density: Mass/Length/Length/Length
> > // ElectricCharge: ElectricCharge
> > // ElectricCurrent: ElectricCharge/Time
> > // Energy: Mass*Length*Length/Time/Time
> > // Force: Mass*Length/Time/Time
> > // Length: Length
> > // LinearDensity: Mass/Length
> > // LinearMass: Mass*Length
> > // LinearMassFlow: Mass*Length/Time
> > // Mass: Mass
> > // MassRate: Mass/Time
> > // Power: Mass*Length*Length/Time/Time/Time
> > // Pressure: Mass/Length/Time/Time
> > // Speed: Length/Time
> > // Tempurature: Tempurature
> > // Time: Time
> > // TimeArea: Time*Time
> > // Volume: Length*Length*Length
> > // VolumeRate: Length*Length*Length/Time
> > ```
> >
> > The measurement types are generated in the *Towel/Measurements/MeasurementTypes.tt* T4 text template file. The unit (enum) definitions are in the *Towel/Measurements/MeasurementUnitDefinitions.cs* file. Both measurment types and unit definitions can be easily added. If you think a measurement type or unit type should be added, please [submit an enhancement issue](https://github.com/ZacharyPatten/Towel/issues/new/choose).
>
>


>
>
> ```cs
> // Towel has measurement types to help write scientific code: Acceleration, Angle, Area,
> // Density, Length, Mass, Speed, Time, Volume, etc.
>
> // Automatic Unit Conversion
> // When you perform mathematical operations on measurements, any necessary unit conversions will
> // be automatically performed by the relative measurement type (in this case "Angle").
> Angle angle1 = (90d, Degrees);
> Angle angle2 = (.5d, Turns);
> Angle result1 = angle1 + angle2; // 270°
>
> // Type Safeness
> // The type safe-ness of the measurement types prevents the miss-use of the measurements. You cannot
> // add "Length" to "Angle" because that is mathematically invalid (no operator exists).
> Length length1 = (2d, Yards);
> object result2 = angle1 + length1; // WILL NOT COMPILE!!!
>
> // Simplify The Syntax Even Further
> // You can use alias to remove the generic type if you want to simplify the syntax even further.
> using Speedf = Towel.Measurements.Speed; // at top of file
> Speedf speed1 = (5, Meters / Seconds);
>
> // Vector + Measurements
> // You can use the measurement types inside Towel Vectors.
> Vector> velocity1 = new Vector>(
> (1f, Meters / Seconds),
> (2f, Meters / Seconds),
> (3f, Meters / Seconds));
> Vector velocity2 = new Vector(
> (1f, Centimeters / Seconds),
> (2f, Centimeters / Seconds),
> (3f, Centimeters / Seconds));
> Vector> velocity3 = velocity1 + velocity2;
>
> // Manual Unit Conversions
> // 1. Index Operator On Measurement Type
> double angle1_inRadians = angle1[Radians];
> float speed1_inMilesPerHour = speed1[Miles / Hours];
> // 2. Static Conversion Methods
> double angle3 = Angle.Convert(7d,
> Radians, // from
> Degrees); // to
> double speed2 = Speed.Convert(8d,
> Meters / Seconds, // from
> Miles / Hours); // to
> double force1 = Force.Convert(9d,
> Kilograms * Meters / Seconds / Seconds, // from
> Grams * Miles / Hours / Hours); // to
> double angle4 = Measurement.Convert(10d,
> Radians, // from
> Degrees); // to
> // The unit conversion on the Measurement class
> // is still compile-time-safe.
>
> // Measurement Parsing
> Speed.TryParse("20.5 Meters / Seconds",
> out Speed parsedSpeed);
> Force.TryParse(".1234 Kilograms * Meters / Seconds / Seconds",
> out Force parsedForce);
> ```

Console Helpers [Expand]

> ```cs
> // Just some helper methods for console applications...
>
> // wait for keypress to continue an intercept input
> ConsoleHelper.PromptPressToContinue(...);
> // generic method for retrieving validated console input
> ConsoleHelper.GetInput(...);
> // animated ellipsis character to show processing
> ConsoleHelper.AnimatedEllipsis(...);
> // render progress bar in console
> ConsoleHelper.ProgressBar(...);
> // Console.ReadLine() with hidden input characters
> ConsoleHelper.HiddenReadLine();
> // easily manage int-based console menus
> ConsoleHelper.IntMenu(...);
> // preventing console input
> ConsoleHelper.FlushInputBuffer();
> ```

TagAttribute [Expand]

> ```cs
> // With TagAttribute's you can make value-based attributes so
> // you don't always have to make your own custom attribute types.
> // Just "tag" a code member with constant values.
>
> using System;
> using Towel;
>
> var (Found, Value) = typeof(MyClass).GetTag("My Tag");
> Console.WriteLine("My Tag...");
> Console.WriteLine("Found: " + Found);
> Console.WriteLine("Value: " + Value);
>
> [Tag("My Tag", "hello world")]
> public class MyClass { }
> ```

SLazy<T> + ValueLazy<T> [Expand]

> ```cs
> // SLazy is a faster Lazy when using the default
> // LazyThreadSafetyMode.ExecutionAndPublication setting.
>
> SLazy slazy = new(() => "hello world");
> Console.WriteLine(slazy.IsValueCreated); // False
> Console.WriteLine(slazy.Value); // hello world
> Console.WriteLine(slazy.IsValueCreated); // True
>
> // ValueLazy is even faster than SLazy but it
> // is unsafe as it will potentially call the factory
> // delegate multiple times if the struct is copied.
> // So please use ValueLazy with caution.
>
> // There are various types for supporting no multithread lock,
> // no exception caching, and publication only locks.
> ```
>
> > [Initialization Benchmarks](https://zacharypatten.github.io/Towel/benchmarks/LazyInitializationBenchmarks.html)

> > [Caching Benchmarks](https://zacharypatten.github.io/Towel/benchmarks/LazyCachingBenchmarks.html)

> > [Construction Benchmarks](https://zacharypatten.github.io/Towel/benchmarks/LazyConstructionBenchmarks.html)

SpanBuilder<T> + SStringBuilder [Expand]

> ```cs
> // SpanBuilder is a small helper for initializing
> // stack allocated spans.
> SpanBuilder span = stackalloc char[10];
> span.AppendLine("ab");
>
> // SStringBuilder is a small helper for initializing strings.
> // It will append to the span until the capacity is reached
> // and then it will revert to a StringBuilder if necessary
> // rather than throwing like SpanBuilder does.
> SStringBuilder span = stackalloc char[10];
> span.AppendLine("abcdefghijklmnopqrstuvwxyz");
> ```

Command Line Parser [Expand]

> ```cs
> // Just put the [Command] attribute on any method you want to call
> // from the command line, and call the "HandleArguments" method.
>
> using System;
> using static Towel.CommandLine;
>
> public static class Program
> {
> public static void Main(string[] args)
> {
> HandleArguments(args);
> }
>
> [Command]
> public static void A(int a)
> {
> Console.WriteLine(nameof(A) + " called");
> Console.WriteLine(nameof(a) + ": " + a);
> }
> }
>
> // output:
> // dotnet run A --a 7
> // A called
> // a: 7
> ```