Popularity
5.3
Growing
Activity
0.0
Declining
696
28
52

Programming language: C#
License: MIT License

Towel alternatives and similar packages

Based on the "Algorithms and Data structures" category.
Alternatively, view Towel alternatives based on common mentions on social networks and blogs.

Do you think we are missing an alternative of Towel or a related project?

Add another 'Algorithms and Data structures' Package

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

:page_facing_up: Run The Included Examples [Expand]

Towel has Examples included in this repository.

Download 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:

:page_facing_up: Visual Studio [Expand]

  1. Install Visual Studio if not already installed.

  2. Open the Towel.sln file in Visual Studio.

:page_facing_up: Visual Studio Code [Expand]

  1. Install the .NET SDK if not already installed.

  2. Install Visual Studio Code 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

:page_facing_up: 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. 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:

    <a href="https://github.com/ZacharyPatten/Towel"><img src="https://github.com/ZacharyPatten/Towel/blob/main/.github/Resources/UsingTowel.svg?raw=true" title="Go To Towel"></a>
    
  • Share your work. If you use Towel in one of your projects we want to hear about it. :)

:page_facing_up: View Documentation [Expand]

Relevant Articles:

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 workflows
    • Continuous Integration.yml workflow for checking that code compiles and unit tests pass
    • Towel Deployment.yml workflow to manage releases and deploy nuget packages
    • Documentation.yml workflow that runs docfx + Coverlet + ReportGenerator to output GitHub Pages 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
  • 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 project (used in Documentation.yml)
    • articles root folder for all articless of the docfx generated GitHub Pages website
    • apidoc root folder for all api overrides of the docfx generated GitHub Pages website
    • docfx.json configuration file that controls docfx
    • index.md home page of the docfx generated GitHub Pages website
    • toc.yml primary navigation for the docfx generated GitHub Pages 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)

:page_facing_up: 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.

  • If you notice anything in Towel that may be improved, please create a new issue. 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

:page_facing_up: Algorithms [Expand]

// supports System.Span<T> and any (non ref struct) int-indexed type
IsPalindrome<...>(...);

// supports System.ReadOnlySpan<T>
IsInterleavedRecursive<...>(...);
IsInterleavedIterative<...>(...);

IsReorderOf<...>(...); // aka "anagrams"

// supports System.Span<T> and any (non ref struct) int-indexed type
SortShuffle<T>(...);
SortBubble<T>(...);
SortSelection<T>(...);
SortInsertion<T>(...);
SortQuick<T>(...);
SortMerge<T>(...);
SortHeap<T>(...);
SortOddEven<T>(...);
SortCocktail<T>(...);
SortComb<T>(...);
SortGnome<T>(...);
SortShell<T>(...);
SortBogo<T>(...);
SortSlow<T>(...);
SortCycle<T>(...);
SortPancake<T>(...);
SortStooge<T>(...);
SortTim<T>(...);
SortIntro<T>(...);
SortCounting<T>(...); // uint-based (non-comparative sort)
SortRadix<T>(...); // uint-based (non-comparative sort)
SortPidgeonHole<T>(...); // int-based (non-comparative sort)

// supports System.ReadOnlySpan<T> and any (non ref struct) int-indexed type
SearchBinary<T>(...);

// supports System.ReadOnlySpan<T> and any (non ref struct) int-indexed type
int HammingDistanceIterative<...>(...);
int LevenshteinDistanceRecursive<...>(...);
int LevenshteinDistanceIterative<...>(...);

// Permutations of sequences
// supports System.Span<T> 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<T>(IEnumerable<(T A, T B)> ranges)

Sorting Algorithm Benchmarks Note: not all permuations of the input are benchmarked, so take with a grain of salt. Permute Benchmarks

:page_facing_up: Extensions [Expand]

// 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<T> 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<T> excluded); // unique values with exclusions
T Next<T>(this Random random, IEnumerable<(T Value, double Weight)> pool); // weighted values
void Shuffle<T>(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<int>) -> "System.Collections.Generic.List<int>"

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 Random With Exclusions Benchmarks decimal To English Words Benchmarks

:page_facing_up: Data Structures [Expand]

:page_facing_up: Heap [Expand]

// 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<T> heap = HeapArray.New<T>();

// 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

:page_facing_up: AVL Tree [Expand]

// 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<T> avlTree = AvlTreeLinked.New<T>();

// 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

:page_facing_up: Red Black Tree [Expand]

// 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<T> redBlackTree = RedBlackTreeLinked.New<T>();

// 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

:page_facing_up: Omnitree [Expand]

// 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<T, A1, A2, A3...> omnitreePoints =
    new OmnitreePointsLinked<T, A1, A2, A3...>(
        (T value, out A1 a1, out A2 a2, out A3 a3...) => { ... });

IOmnitreeBounds<T, A1, A2, A3...> omnitreeBounds =
    new OmnitreeBoundsLinked<T, A1, A2, A3...>(
        (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.

:page_facing_up: B-Tree [Expand]

// 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<int> tree = new BTree<int>(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]

:page_facing_up: Tree [Expand]

ITree<T> treeMap = TreeMap.New<T>(...);

:page_facing_up: Graph [Expand]

// 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<int> graph = GraphSetOmnitree.New<int>();
// 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

:page_facing_up: SkipList [Expand]

// 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<int, SFunc<int, int, CompareResult>>? list = SkipList.New<int>(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

:page_facing_up: Trie [Expand]

// 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<T>)
// and one that stores the values of the trie plus an additional generic value
// on the leaves (ITrie<T, D>).

ITrie<T> trie = TrieLinkedHashLinked.New<T>();

ITrie<T, D> trie = TrieLinkedHashLinked.New<T, D>();

:page_facing_up: Generic Mathematics & Logic [Expand]

:page_facing_up: How It Works [Expand]

public static T Addition<T>(T a, T b)
{
    return AdditionImplementation<T>.Function(a, b);
}

internal static class AdditionImplementation<T>
{
    internal static Func<T, T, T> 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<Func<T, T, T>>(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.

// Logic Fundamentals
bool Equate<T>(T a , T b);
bool LessThan<T>(T a, T b);
bool GreaterThan<T>(T a, T b);
CompareResult Compare<T>(T a, T b);

// Mathematics Fundamentals
T Negation<T>(T a);
T Addition<T>(T a, T b);
T Subtraction<T>(T a, T b);
T Multiplication<T>(T a, T b);
T Division<T>(T a, T b);
T Remainder<T>(T a, T b);

// More Logic
bool IsPrime<T>(T a);
bool IsEven<T>(T a);
bool IsOdd<T>(T a);
T Minimum<T>(T a, T b);
T Maximum<T>(T a, T b);
T Clamp<T>(T value, T floor, T ceiling);
T AbsoluteValue<T>(T a);
bool EqualityLeniency<T>(T a, T b, T leniency);

// More Numerics
void FactorPrimes<T>(T a, ...);
T Factorial<T>(T a);
T LinearInterpolation<T>(T x, T x0, T x1, T y0, T y1);
T LeastCommonMultiple<T>(T a, T b, params T[] c);
T GreatestCommonFactor<T>(T a, T b, params T[] c);
LinearRegression2D<T>(..., out T slope, out T y_intercept);

// Statistics
T Mean<T>(T a, params T[] b);
T Median<T>(params T[] values);
Heap<Link<T, int>> Mode<T>(T a, params T[] b);
void Range<T>(out T minimum, out T maximum, ...);
T[] Quantiles<T>(int quantiles, ...);
T GeometricMean<T>(...);
T Variance<T>(...);
T StandardDeviation<T>(...);
T MeanDeviation<T>(...);

// Vectors
Vector<T> V1 = new Vector<T>(params T[] vector);
Vector<T> V2 = new Vector<T>(params T[] vector);
Vector<T> 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<T> M1 = new Matrix<T>(int rows, int columns);
Matrix<T> M2 = new Matrix<T>(int rows, int columns);
Matrix<T> M3;
Vector<T> V2 = new Vector<T>(params T[] vector);
Vector<T> 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

:page_facing_up: Symbolic Mathematics [Expand]

// Parsing From Linq Expression
Expression<Func<double, double>> 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);

:page_facing_up: Measurement Mathematics [Expand]

:page_facing_up: Supported Measurements [Expand]

Here are the currently supported measurement types:

//    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.

// Towel has measurement types to help write scientific code: Acceleration<T>, Angle<T>, Area<T>, 
// Density<T>, Length<T>, Mass<T>, Speed<T>, Time<T>, Volume<T>, 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<T>").
Angle<double> angle1 = (90d, Degrees);
Angle<double> angle2 = (.5d, Turns);
Angle<double> 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<T>" to "Angle<T>" because that is mathematically invalid (no operator exists).
Length<double> 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<float>; // at top of file
Speedf speed1 = (5, Meters / Seconds);

// Vector + Measurements
// You can use the measurement types inside Towel Vectors.
Vector<Speed<float>> velocity1 = new Vector<Speed<float>>(
  (1f, Meters / Seconds),
  (2f, Meters / Seconds),
  (3f, Meters / Seconds));
Vector<Speedf> velocity2 = new Vector<Speedf>(
  (1f, Centimeters / Seconds),
  (2f, Centimeters / Seconds),
  (3f, Centimeters / Seconds));
Vector<Speed<float>> 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<double>.Convert(7d,
  Radians,  // from
  Degrees); // to
double speed2 = Speed<double>.Convert(8d,
  Meters / Seconds, // from
  Miles / Hours);   // to
double force1 = Force<double>.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<float>.TryParse("20.5 Meters / Seconds",
  out Speed<float> parsedSpeed);
Force<decimal>.TryParse(".1234 Kilograms * Meters / Seconds / Seconds",
  out Force<decimal> parsedForce);

:page_facing_up: Console Helpers [Expand]

// 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<T>(...);
// 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();

:page_facing_up: TagAttribute [Expand]

// 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 { }

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

// SLazy<T> is a faster Lazy<T> when using the default
// LazyThreadSafetyMode.ExecutionAndPublication setting.

SLazy<string> slazy = new(() => "hello world");
Console.WriteLine(slazy.IsValueCreated); // False
Console.WriteLine(slazy.Value);          // hello world
Console.WriteLine(slazy.IsValueCreated); // True

// ValueLazy<T> is even faster than SLazy<T> but it 
// is unsafe as it will potentially call the factory
// delegate multiple times if the struct is copied.
// So please use ValueLazy<T> with caution.

// There are various types for supporting no multithread lock,
// no exception caching, and publication only locks.

Initialization Benchmarks Caching Benchmarks Construction Benchmarks

:page_facing_up: SpanBuilder<T> + SStringBuilder [Expand]

// SpanBuilder<char> is a small helper for initializing
// stack allocated spans.
SpanBuilder<char> 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<T> does.
SStringBuilder<char> span = stackalloc char[10];
span.AppendLine("abcdefghijklmnopqrstuvwxyz");

:page_facing_up: Command Line Parser [Expand]

// 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


*Note that all licence references and agreements mentioned in the Towel README section above are relevant to that project's source code only.