From ff36e398b9819c580408eb9b7cffe79f33b7853f Mon Sep 17 00:00:00 2001 From: jvangael Date: Sun, 26 Jul 2009 15:32:02 +0200 Subject: [PATCH] Added the number theory and sorting classes. --- .../Managed.UnitTests.csproj | 1 + src/Managed.UnitTests/SortingTests.cs | 162 +++++ src/Managed/Managed.csproj | 1 + src/Managed/NumberTheory/IntegerTheory.cs | 4 +- src/Managed/Sorting.cs | 574 ++++++++++++++++++ src/Native.UnitTests/Native.UnitTests.csproj | 3 + src/Native/Native.csproj | 3 + 7 files changed, 746 insertions(+), 2 deletions(-) create mode 100644 src/Managed.UnitTests/SortingTests.cs create mode 100644 src/Managed/Sorting.cs diff --git a/src/Managed.UnitTests/Managed.UnitTests.csproj b/src/Managed.UnitTests/Managed.UnitTests.csproj index b82020d4..a1f55975 100644 --- a/src/Managed.UnitTests/Managed.UnitTests.csproj +++ b/src/Managed.UnitTests/Managed.UnitTests.csproj @@ -70,6 +70,7 @@ + diff --git a/src/Managed.UnitTests/SortingTests.cs b/src/Managed.UnitTests/SortingTests.cs new file mode 100644 index 00000000..d623e62d --- /dev/null +++ b/src/Managed.UnitTests/SortingTests.cs @@ -0,0 +1,162 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests +{ + using System; + using System.Collections.Generic; + using System.Text; + + using MbUnit.Framework; + + using MathNet.Numerics; + + [TestFixture] + public class SortingTests + { + [Test] + public void TestRandomTupleArraySorting() + { + const int Len = 0x1 << 10; + var random = new Random(); + + int[] keys = new int[Len]; + int[] items = new int[Len]; + int[] keysCopy = new int[Len]; + + for(int i = 0; i < keys.Length; i++) + { + keys[i] = random.Next(); + keysCopy[i] = keys[i]; + items[i] = -keys[i]; + } + + Sorting.Sort(keys, items); + + for(int i = 1; i < keys.Length; i++) + { + Assert.IsTrue(keys[i] >= keys[i - 1], "Sort Order - " + i.ToString()); + Assert.AreEqual(items[i], -keys[i], "Items Permutation - " + i.ToString()); + } + + for(int i = 0; i < keysCopy.Length; i++) + { + Assert.IsTrue(Array.IndexOf(keys, keysCopy[i]) >= 0, "All keys still there - " + i.ToString()); + } + } + + [Test] + public void TestRandomTupleListSorting() + { + const int Len = 0x1 << 10; + var random = new Random(); + + List keys = new List(Len); + List items = new List(Len); + int[] keysCopy = new int[Len]; + + for(int i = 0; i < Len; i++) + { + int value = random.Next(); + keys.Add(value); + keysCopy[i] = value; + items.Add(-value); + } + + Sorting.Sort(keys, items); + + for(int i = 1; i < Len; i++) + { + Assert.IsTrue(keys[i] >= keys[i - 1], "Sort Order - " + i.ToString()); + Assert.AreEqual(items[i], -keys[i], "Items Permutation - " + i.ToString()); + } + + for(int i = 0; i < keysCopy.Length; i++) + { + Assert.IsTrue(keys.IndexOf(keysCopy[i]) >= 0, "All keys still there - " + i.ToString()); + } + } + + [Test] + public void TestRandomTripleArraySorting() + { + const int Len = 0x1 << 10; + var random = new Random(); + + int[] keys = new int[Len]; + int[] items1 = new int[Len]; + int[] items2 = new int[Len]; + int[] keysCopy = new int[Len]; + + for(int i = 0; i < keys.Length; i++) + { + keys[i] = random.Next(); + keysCopy[i] = keys[i]; + items1[i] = -keys[i]; + items2[i] = keys[i] >> 2; + } + + Sorting.Sort(keys, items1, items2); + + for(int i = 1; i < keys.Length; i++) + { + Assert.IsTrue(keys[i] >= keys[i - 1], "Sort Order - " + i.ToString()); + Assert.AreEqual(items1[i], -keys[i], "Items1 Permutation - " + i.ToString()); + Assert.AreEqual(items2[i], keys[i] >> 2, "Items2 Permutation - " + i.ToString()); + } + + for(int i = 0; i < keysCopy.Length; i++) + { + Assert.IsTrue(Array.IndexOf(keys, keysCopy[i]) >= 0, "All keys still there - " + i.ToString()); + } + } + + [Test] + public void TestAppliedListSorting() + { + const int Len = 0x1 << 10; + var random = new Random(); + + List list = new List(); + + for(int i = 0; i < Len; i++) + { + list.Add(random.Next()); + } + + // default sorting (Ascending) + list.Sort(); + + // just check that the order is as expected, not that the items are correct + for(int i = 1; i < list.Count; i++) + { + Assert.IsTrue(list[i] >= list[i - 1], "Sort Order - " + i.ToString()); + } + } + } +} diff --git a/src/Managed/Managed.csproj b/src/Managed/Managed.csproj index afbb4012..cc486c32 100644 --- a/src/Managed/Managed.csproj +++ b/src/Managed/Managed.csproj @@ -79,6 +79,7 @@ + diff --git a/src/Managed/NumberTheory/IntegerTheory.cs b/src/Managed/NumberTheory/IntegerTheory.cs index f801b5c2..b14a5eed 100644 --- a/src/Managed/NumberTheory/IntegerTheory.cs +++ b/src/Managed/NumberTheory/IntegerTheory.cs @@ -1,4 +1,4 @@ -// +// // Math.NET Numerics, part of the Math.NET Project // http://mathnet.opensourcedotnet.info // @@ -31,7 +31,7 @@ namespace MathNet.Numerics.NumberTheory using System; /// - /// Number Theory for Integers + /// Number theory utility functions for integers. /// public static class IntegerTheory { diff --git a/src/Managed/Sorting.cs b/src/Managed/Sorting.cs new file mode 100644 index 00000000..65796790 --- /dev/null +++ b/src/Managed/Sorting.cs @@ -0,0 +1,574 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics +{ + using System; + using System.Collections.Generic; + using System.Text; + + /// + /// Sorting algorithms for single, tuple and triple lists. + /// + public static class Sorting + { + /// + /// Sort a list of keys, inplace using the quick sort algorithm. + /// + /// The type of elements stored in the list. + /// List to sort. + public static void Sort(IList keys) + { + Sort(keys, Comparer.Default); + } + + /// + /// Sort a list of keys and items with respect to the keys, inplace using the quick sort algorithm. + /// + /// The type of elements stored in the key list. + /// The type of elements stored in the item list. + /// List to sort. + /// List to permutate the same way as the key list. + public static void Sort(IList keys, IList items) + { + Sort(keys, items, Comparer.Default); + } + + /// + /// Sort a list of keys, items1 and items2 with respect to the keys, inplace using the quick sort algorithm. + /// + /// The type of elements stored in the key list. + /// The type of elements stored in the first item list. + /// The type of elements stored in the second item list. + /// List to sort. + /// First list to permutate the same way as the key list. + /// Second list to permutate the same way as the key list. + public static void Sort(IList keys, IList items1, IList items2) + { + Sort(keys, items1, items2, Comparer.Default); + } + + /// + /// Sort a range of a list of keys, inplace using the quick sort algorithm. + /// + /// The type of elements in the key list. + /// List to sort. + /// The zero-based starting index of the range to sort. + /// The length of the range to sort. + public static void Sort(IList keys, int index, int count) + { + Sort(keys, index, count, Comparer.Default); + } + + /// + /// Sort a list of keys, inplace using the quick sort algorithm using the quick sort algorithm. + /// + /// The type of elements in the key list. + /// List to sort. + /// Comparison, defining the sort order. + public static void Sort(IList keys, IComparer comparer) + { + if(null == keys) + { + throw new ArgumentNullException("keys"); + } + + if(null == comparer) + { + throw new ArgumentNullException("comparer"); + } + + // basic cases + if(keys.Count <= 1) + { + return; + } + + if(keys.Count == 2) + { + if(comparer.Compare(keys[0], keys[1]) > 0) + { + Swap(keys, 0, 1); + } + + return; + } + + // generic list case + List list = keys as List; + if(null != list) + { + list.Sort(comparer); + return; + } + + // array case + T[] array = keys as T[]; + if(null != array) + { + Array.Sort(array, comparer); + return; + } + + // local sort implementation + QuickSort(keys, comparer, 0, keys.Count - 1); + } + + /// + /// Sort a list of keys and items with respect to the keys, inplace using the quick sort algorithm. + /// + /// The type of elements in the key list. + /// The type of elements in the item list. + /// List to sort. + /// List to permutate the same way as the key list. + /// Comparison, defining the sort order. + public static void Sort(IList keys, IList items, IComparer comparer) + { + if(null == keys) + { + throw new ArgumentNullException("keys"); + } + + if(null == items) + { + throw new ArgumentNullException("items"); + } + + if(null == comparer) + { + throw new ArgumentNullException("comparer"); + } + + // array case + TKey[] keysArray = keys as TKey[]; + TItem[] itemsArray = items as TItem[]; + if((null != keysArray) && (null != itemsArray)) + { + Array.Sort(keysArray, itemsArray, comparer); + return; + } + + // local sort implementation + QuickSort(keys, items, comparer, 0, keys.Count - 1); + } + + /// + /// Sort a list of keys, items1 and items2 with respect to the keys, inplace using the quick sort algorithm. + /// + /// The type of elements in the key list. + /// The type of elements in the first item list. + /// The type of elements in the second item list. + /// List to sort. + /// First list to permutate the same way as the key list. + /// Second list to permutate the same way as the key list. + /// Comparison, defining the sort order. + public static void Sort( + IList keys, IList items1, IList items2, IComparer comparer) + { + if(null == keys) + { + throw new ArgumentNullException("keys"); + } + + if(null == items1) + { + throw new ArgumentNullException("items1"); + } + + if(null == items2) + { + throw new ArgumentNullException("items2"); + } + + if(null == comparer) + { + throw new ArgumentNullException("comparer"); + } + + // local sort implementation + QuickSort(keys, items1, items2, comparer, 0, keys.Count - 1); + } + + /// + /// Sort a range of a list of keys, inplace using the quick sort algorithm. + /// + /// The type of element in the list. + /// List to sort. + /// The zero-based starting index of the range to sort. + /// The length of the range to sort. + /// Comparison, defining the sort order. + public static void Sort(IList keys, int index, int count, IComparer comparer) + { + if(null == keys) + { + throw new ArgumentNullException("keys"); + } + + if(null == comparer) + { + throw new ArgumentNullException("comparer"); + } + + if(index < 0 || index >= keys.Count) + { + throw new ArgumentOutOfRangeException("index"); + } + + if(count < 0 || index + count > keys.Count) + { + throw new ArgumentOutOfRangeException("count"); + } + + // basic cases + if(count <= 1) + { + return; + } + + if(count == 2) + { + if(comparer.Compare(keys[index], keys[index + 1]) > 0) + { + Swap(keys, index, index + 1); + } + + return; + } + + // generic list case + List list = keys as List; + if(null != list) + { + list.Sort(index, count, comparer); + return; + } + + // array case + T[] array = keys as T[]; + if(null != array) + { + Array.Sort(array, index, count, comparer); + return; + } + + // local sort implementation + QuickSort(keys, comparer, index, count - 1); + } + + /// + /// Recursive implementation for an inplace quick sort on a list. + /// + /// The type of the list on which the quick sort is performed. + /// The list which is sorted using quick sort. + /// The method with which to compare two elements of the quick sort. + /// The left boundary of the quick sort. + /// The right boundary of the quick sort. + private static void QuickSort(IList keys, IComparer comparer, int left, int right) + { + do + { + // Pivoting + int a = left; + int b = right; + int p = a + ((b - a) >> 1); // midpoint + + if(comparer.Compare(keys[a], keys[p]) > 0) + { + Swap(keys, a, p); + } + + if(comparer.Compare(keys[a], keys[b]) > 0) + { + Swap(keys, a, b); + } + + if(comparer.Compare(keys[p], keys[b]) > 0) + { + Swap(keys, p, b); + } + + T pivot = keys[p]; + + // Hoare Partitioning + do + { + while(comparer.Compare(keys[a], pivot) < 0) + { + a++; + } + + while(comparer.Compare(pivot, keys[b]) < 0) + { + b--; + } + + if(a > b) + { + break; + } + + if(a < b) + { + Swap(keys, a, b); + } + + a++; + b--; + } + while(a <= b); + + // In order to limit the recusion depth to log(n), we sort the + // shorter partition recusively and the longer partition iteratively. + if((b - left) <= (right - a)) + { + if(left < b) + { + QuickSort(keys, comparer, left, b); + } + + left = a; + } + else + { + if(a < right) + { + QuickSort(keys, comparer, a, right); + } + + right = b; + } + } + while(left < right); + } + + /// + /// Recursive implementation for an inplace quick sort on a list while reordering one other list accordingly. + /// + /// The type of the list on which the quick sort is performed. + /// The type of the list which is automatically reordered accordingly. + /// The list which is sorted using quick sort. + /// The list which is automatically reordered accordingly. + /// The method with which to compare two elements of the quick sort. + /// The left boundary of the quick sort. + /// The right boundary of the quick sort. + private static void QuickSort(IList keys, IList items, IComparer comparer, int left, int right) + { + do + { + // Pivoting + int a = left; + int b = right; + int p = a + ((b - a) >> 1); // midpoint + + if(comparer.Compare(keys[a], keys[p]) > 0) + { + Swap(keys, a, p); + Swap(items, a, p); + } + + if(comparer.Compare(keys[a], keys[b]) > 0) + { + Swap(keys, a, b); + Swap(items, a, b); + } + + if(comparer.Compare(keys[p], keys[b]) > 0) + { + Swap(keys, p, b); + Swap(items, p, b); + } + + T pivot = keys[p]; + + // Hoare Partitioning + do + { + while(comparer.Compare(keys[a], pivot) < 0) + { + a++; + } + + while(comparer.Compare(pivot, keys[b]) < 0) + { + b--; + } + + if(a > b) + { + break; + } + + if(a < b) + { + Swap(keys, a, b); + Swap(items, a, b); + } + + a++; + b--; + } + while(a <= b); + + // In order to limit the recusion depth to log(n), we sort the + // shorter partition recusively and the longer partition iteratively. + if((b - left) <= (right - a)) + { + if(left < b) + { + QuickSort(keys, items, comparer, left, b); + } + + left = a; + } + else + { + if(a < right) + { + QuickSort(keys, items, comparer, a, right); + } + + right = b; + } + } + while(left < right); + } + + /// + /// Recursive implementation for an inplace quick sort on one list while reordering two other lists accordingly. + /// + /// The type of the list on which the quick sort is performed. + /// The type of the first list which is automatically reordered accordingly. + /// The type of the second list which is automatically reordered accordingly. + /// The list which is sorted using quick sort. + /// The first list which is automatically reordered accordingly. + /// The second list which is automatically reordered accordingly. + /// The method with which to compare two elements of the quick sort. + /// The left boundary of the quick sort. + /// The right boundary of the quick sort. + private static void QuickSort( + IList keys, IList items1, IList items2, IComparer comparer, int left, int right) + { + do + { + // Pivoting + int a = left; + int b = right; + int p = a + ((b - a) >> 1); // midpoint + + if(comparer.Compare(keys[a], keys[p]) > 0) + { + Swap(keys, a, p); + Swap(items1, a, p); + Swap(items2, a, p); + } + + if(comparer.Compare(keys[a], keys[b]) > 0) + { + Swap(keys, a, b); + Swap(items1, a, b); + Swap(items2, a, b); + } + + if(comparer.Compare(keys[p], keys[b]) > 0) + { + Swap(keys, p, b); + Swap(items1, p, b); + Swap(items2, p, b); + } + + T pivot = keys[p]; + + // Hoare Partitioning + do + { + while(comparer.Compare(keys[a], pivot) < 0) + { + a++; + } + + while(comparer.Compare(pivot, keys[b]) < 0) + { + b--; + } + + if(a > b) + { + break; + } + + if(a < b) + { + Swap(keys, a, b); + Swap(items1, a, b); + Swap(items2, a, b); + } + + a++; + b--; + } + while(a <= b); + + // In order to limit the recusion depth to log(n), we sort the + // shorter partition recusively and the longer partition iteratively. + if((b - left) <= (right - a)) + { + if(left < b) + { + QuickSort(keys, items1, items2, comparer, left, b); + } + + left = a; + } + else + { + if(a < right) + { + QuickSort(keys, items1, items2, comparer, a, right); + } + + right = b; + } + } + while(left < right); + } + + /// + /// Performs an in place swap of two elements in a list. + /// + /// The type of elements stored in the list. + /// The list in which the elements are stored. + /// The index of the first element of the swap. + /// The index of the second element of the swap. + internal static void Swap(IList keys, int a, int b) + { + T local = keys[a]; + keys[a] = keys[b]; + keys[b] = local; + } + } +} diff --git a/src/Native.UnitTests/Native.UnitTests.csproj b/src/Native.UnitTests/Native.UnitTests.csproj index 38c98b47..8422f4e0 100644 --- a/src/Native.UnitTests/Native.UnitTests.csproj +++ b/src/Native.UnitTests/Native.UnitTests.csproj @@ -89,6 +89,9 @@ PrecisionTest.cs + + SortingTests.cs + SpecialFunctionsTest\ErfTests.cs diff --git a/src/Native/Native.csproj b/src/Native/Native.csproj index 63fca844..889aa344 100644 --- a/src/Native/Native.csproj +++ b/src/Native/Native.csproj @@ -131,6 +131,9 @@ SiPrefixes.cs + + Sorting.cs + SpecialFunctions.cs