Skip to content

Commit 6d77d64

Browse files
authored
Dev/start5 (#68)
* Change to .NET Standard 2.0. Make structs readonly. Start to rip out statistics container classes. Add ChebyshevU. Add Benford and SkewNormal distributions. * Beta use unit interval. no Sample, and other cleanup. * Many mostly small improvements to accuracy and added tests. * Final changes to prep for release.
1 parent 99ac036 commit 6d77d64

26 files changed

+412
-86
lines changed

Numerics/Core/ComplexMath.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,5 +592,38 @@ public static Complex Pow (Complex z, int n) {
592592

593593
}
594594

595+
596+
597+
598+
/// <summary>
599+
/// Computes the nth roots of unity.
600+
/// </summary>
601+
/// <param name="n">The order of roots to be computed, which must be positive.</param>
602+
/// <returns>The n complex numbers x such that x<sup>n</sup> = 1.</returns>
603+
/// <remarks>
604+
/// <para>The roots are listed in the usual anti-clockwise order, starting from 1.</para>
605+
/// <para>This method ensures that 1 and -1 (when it appears) are exact, and that conjugate roots are exactly conjugate.</para>
606+
/// </remarks>
607+
public static Complex[] RootsOfUnity(int n) {
608+
if (n < 1) throw new ArgumentOutOfRangeException(nameof(n));
609+
Complex[] roots = new Complex[n];
610+
roots[0] = Complex.One;
611+
double delta = Global.TwoPI / n;
612+
int half_n = (n + 1) / 2; // This computes n/2 rounded up rather than down.
613+
for (int i = 1; i < half_n; i++) {
614+
double theta = delta * i;
615+
roots[i] = new Complex(MoreMath.Cos(theta), MoreMath.Sin(theta));
616+
roots[n - i] = roots[i].Conjugate;
617+
}
618+
if (n % 2 == 0) roots[half_n] = -Complex.One;
619+
return roots;
620+
}
621+
622+
// This computation of the complex roots of unity is careful to ensure
623+
// +1 and -1 (when it appears) are always exact
624+
// conjugate roots are always exactly conjugate
625+
// Using CosPi and SinPi is not necessary since the arguments are never reducable.
626+
// I notice for n=8 not all components are exactly equal; look into this.
627+
595628
}
596629
}

Numerics/Core/DiscreteInterval.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public int RightEndpoint {
6363
/// This is one less than the number of integers in the interval. Thus an interval with equal left and right endpoints
6464
/// has width 0, not width 1. And and the interval {0 .. MaxValue} has width MaxValue, not MaxValue + 1.</para>
6565
/// </remarks>
66-
internal uint Width {
66+
public uint Width {
6767
get {
6868
return (uint) (max - min);
6969
}

Numerics/Core/MoreMath.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ internal static double ReducedExpMinusOne (double x, double e) {
238238
/// <param name="x">The argument.</param>
239239
/// <returns>The value of log(1+x).</returns>
240240
/// <remarks>
241-
/// <para>If x is close to 0, computing log(1+x) by <tt>Math.Log(1.0 + x)</tt> can result in a
241+
/// <para>If x is close to 0, computing log(1+x) by <c>Math.Log(1.0 + x)</c> can result in a
242242
/// significant loss of accuracy.
243243
/// This function maintains full precision of all values of x by switching to a series expansion
244244
/// for values of x near zero.</para>
@@ -416,9 +416,8 @@ public static double Cos (double x) {
416416
/// that arise from the finite precision of the stored constant <see cref="Math.PI"/>.</para>
417417
/// <para>Suppose, for example, x = 1.0E6. Since x is an integer, sin(&#x3C0;x) = 0.0.
418418
/// However, due to the finite accuracy of Math.PI, Math.PI * x is not a perfect multiple of &#x3C0;, and
419-
/// Math.Sin(Math.PI * x) = -2.2318717360358953E-10. But MoreMath.SinPi(x) = 0.0 exactly. Even for
420-
/// arguments that are not exact integers, the accurary of MoreMath.SinPi will be better (because
421-
/// it is possible to do argument reductions by integers exactly.)
419+
/// <c>Math.Sin(Math.PI * x)</c> = -2.2318717360358953E-10. But <c>MoreMath.SinPi(x)</c> = 0.0 exactly. Even for
420+
/// arguments that are not exact integers, the accurary of MoreMath.SinPi will be better.
422421
/// </para>
423422
/// </remarks>
424423
/// <seealso cref="CosPi(double)"/>

Numerics/Core/NamespaceDoc.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Runtime.CompilerServices;
2+
3+
namespace Meta.Numerics {
4+
5+
/// <summary>
6+
/// Contains types used throughout the Meta.Numerics library.
7+
/// </summary>
8+
[CompilerGenerated]
9+
internal class NamespaceDoc {
10+
}
11+
}

Numerics/Core/Point.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Meta.Numerics {
88
/// <summary>
99
/// Represents a two-dimensional point.
1010
/// </summary>
11-
public struct XY : IEquatable<XY> {
11+
public readonly struct XY : IEquatable<XY> {
1212

1313
/// <summary>
1414
/// Initializes a new point with the given coordinates.
@@ -20,7 +20,7 @@ public XY (double x, double y) {
2020
this.y = y;
2121
}
2222

23-
private double x, y;
23+
private readonly double x, y;
2424

2525
/// <summary>
2626
/// Gets the X-coordinate of the point.

Numerics/Data/FrameView.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public enum SortOrder {
5050
/// <see cref="this[string]"/> accessor to get a column, together with the <see cref="FrameColumn.As{T}"/>
5151
/// caster to expose it as a collection of the required type.
5252
/// For example, to obtain a estimate of the mean of the population from the sample in the
53-
/// column named "heights", write <tt>view["height"].As&lt;double&gt;().PopulationMean()</tt>.
53+
/// column named "heights", write <c>view["height"].As&lt;double&gt;().PopulationMean()</c>.
5454
/// Note that, for this to succeed, the underlying storage type of the heights column need not be double. As
5555
/// long as the data are convertible to the target type, no problems will arise. For example,
5656
/// the underlying storage type might be int, or double? as long as no null values are present in the view.</para>

Numerics/Functions/AdvancedMath_Elliptic.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,13 @@ public static double EllipticPi (double n, double k) {
558558
/// </summary>
559559
/// <param name="k">The elliptic modulus.</param>
560560
/// <returns>The corresponding Jacobi nome q.</returns>
561+
/// <remarks>
562+
/// <para>The elliptic nome q(k) = e<sup>&#x3C0; K'/ K</sup>, where K is the elliptic integral of the first kind
563+
/// for the modulus k, and K' is the elliptic integral of the first kind for its complement k'.</para>
564+
/// </remarks>
565+
/// <seealso cref="EllipticK(double)"/>
566+
/// <seealso href="https://en.wikipedia.org/wiki/Nome_(mathematics)"/>
567+
/// <seealso href="https://mathworld.wolfram.com/Nome.html"/>
561568
public static double EllipticNome (double k) {
562569

563570
if (k < 0.0 || k > 1.0) throw new ArgumentOutOfRangeException(nameof(k));

Numerics/Functions/AdvancedMath_Exponential.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Diagnostics;
3+
using static System.Net.WebRequestMethods;
34

45

56
namespace Meta.Numerics.Functions {
@@ -260,6 +261,8 @@ public static double IntegralCin (double x) {
260261
/// </summary>
261262
/// <param name="x">The argument.</param>
262263
/// <returns>The value of Chi(x).</returns>
264+
/// <seealso href="https://en.wikipedia.org/wiki/Trigonometric_integral#Hyperbolic_cosine_integral"/>
265+
/// <seealso href="https://mathworld.wolfram.com/Chi.html"/>
263266
public static double IntegralChi (double x) {
264267
if (x < 0.0) {
265268
throw new ArgumentOutOfRangeException(nameof(x));
@@ -285,6 +288,7 @@ public static double IntegralChi (double x) {
285288
/// <img src="../images/SiIntegral.png" />
286289
/// <para>The sine integral is zero at the origin and executes a damped oscillation around &#x3C0;/2 as its argument increases.</para>
287290
/// </remarks>
291+
/// <seealso cref="IntegralLittleSi(double)"/>
288292
/// <seealso href="https://en.wikipedia.org/wiki/Trigonometric_integral"/>
289293
/// <seealso href="http://mathworld.wolfram.com/SineIntegral.html"/>
290294
/// <seealso href="https://dlmf.nist.gov/6"/>
@@ -308,6 +312,15 @@ public static double IntegralSi (double x) {
308312
/// </summary>
309313
/// <param name="x">The argument.</param>
310314
/// <returns>The value of si(x).</returns>
315+
/// <remarks>
316+
/// <para>The value of the little sine integral is offset from the value of the big sine integral by &#x3C0;/2.
317+
/// Thus at the orgin it has the value -&#x3C0;/2, but asymptotically it oscialtes around zero. Thus its
318+
/// better to use this function for large values when you want to accurate know the amplitude of these oscilations.</para>
319+
/// </remarks>
320+
/// <seealso cref="IntegralSi(double)"/>
321+
/// <seealso href="https://en.wikipedia.org/wiki/Trigonometric_integral"/>
322+
/// <seealso href="http://mathworld.wolfram.com/SineIntegral.html"/>
323+
/// <seealso href="https://dlmf.nist.gov/6"/>
311324
public static double IntegralLittleSi (double x) {
312325
if (x < 0.0) {
313326
throw new ArgumentOutOfRangeException(nameof(x));

Numerics/Functions/OrthogonalPolynomials.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ public static double ChebyshevT (int n, double x) {
353353
/// <remarks>
354354
/// <para>Chebyshev polynomials of the second kind are orthogonal on the interval [-1,1] with the weight (1-x<sup>2</sup>)<sup>1/2</sup>.</para>
355355
/// <para>Values returned are fully accurate (14-16 decimal digits) over the full range of argument for orders up to thousands.
356-
/// By orders up to a million, ~11 decimal digits remain accurate.</para>
356+
/// For orders up to a million, ~11 decimal digits remain accurate.</para>
357357
/// </remarks>
358358
/// <exception cref="ArgumentOutOfRangeException"><paramref name="n"/> is negative, or <paramref name="x"/> lies outside [-1,+1].</exception>
359359
/// <seealso href="https://en.wikipedia.org/wiki/Chebyshev_polynomials"/>

Numerics/Functions/Permutation.cs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Copyright 2014 by David Wright.
33
// All rights reserved.
44

5+
using Meta.Numerics.Matrices;
56
using System;
67
using System.Collections.Generic;
78
using System.Diagnostics;
@@ -119,8 +120,7 @@ public static bool TryParse (string text, out PermutationAsCycles result) {
119120
int[] cycle = new int[cycleText.Length];
120121
dimension += cycle.Length;
121122
for (int k = 0; k < cycle.Length; k++) {
122-
int value;
123-
if (!Int32.TryParse(cycleText[k], out value)) return (false);
123+
if (!Int32.TryParse(cycleText[k], out int value)) return (false);
124124
cycle[k] = value;
125125
}
126126
cyclesList.Add(cycle);
@@ -217,8 +217,7 @@ public static bool TryParse (string text, out PermutationAsMap result) {
217217
int[] map = new int[mapText.Length];
218218
bool[] flags = new bool[mapText.Length];
219219
for (int i = 0; i < map.Length; i++) {
220-
int value;
221-
if (!Int32.TryParse(mapText[i], out value)) return (false);
220+
if (!Int32.TryParse(mapText[i], out int value)) return (false);
222221
if ((value < 0) || (value > (map.Length - 1))) return (false);
223222
if (flags[value]) return (false);
224223
map[i] = value;
@@ -411,9 +410,8 @@ public string ToString (string format, IFormatProvider formatProvider) {
411410
/// <exception cref="FormatException"><paramref name="text"/> is not a valid text representation of a permutation.</exception>
412411
public static Permutation Parse (string text) {
413412
if (text == null) throw new ArgumentNullException(nameof(text));
414-
Permutation output;
415-
if (TryParse(text, out output)) {
416-
return (output);
413+
if (TryParse(text, out Permutation output)) {
414+
return output;
417415
} else {
418416
throw new FormatException();
419417
}
@@ -437,13 +435,11 @@ public static bool TryParse (string text, out Permutation output) {
437435
bool success = false;
438436
if ((text.Length > 0) && (text[0] == '[')) {
439437
// try to parse as ordering
440-
PermutationAsMap map;
441-
success = PermutationAsMap.TryParse(text, out map);
438+
success = PermutationAsMap.TryParse(text, out PermutationAsMap map);
442439
if (success) output = new Permutation(map);
443440
} else {
444441
// try to parse as cycles
445-
PermutationAsCycles cycles;
446-
success = PermutationAsCycles.TryParse(text, out cycles);
442+
success = PermutationAsCycles.TryParse(text, out PermutationAsCycles cycles);
447443
if (success) output = new Permutation(cycles);
448444
}
449445

@@ -494,6 +490,19 @@ private void ComputeMap () {
494490
map = new PermutationAsMap(FromCyclesToMap(cycles.cycles));
495491
}
496492

493+
internal int[] Map {
494+
get {
495+
if (map == null) ComputeMap();
496+
return map.map;
497+
}
498+
}
499+
500+
internal int[][] Cycles {
501+
get {
502+
if (cycles == null) ComputeCycles();
503+
return cycles.cycles;
504+
}
505+
}
497506

498507
/// <summary>
499508
/// Applies the permutation to a list.
@@ -798,6 +807,13 @@ public static Permutation GetRandomPermutation (int dimension, Random rng) {
798807
return (new Permutation(PermutationAsMap.GetRandomPermutation(dimension, rng)));
799808
}
800809

810+
/// <summary>
811+
/// Get a matrix representation of the permuation.
812+
/// </summary>
813+
/// <returns>A matrix representation of the permutation.</returns>
814+
public PermutationMatrix ToMatrix () {
815+
return new PermutationMatrix(this);
816+
}
801817
}
802818

803819
}

0 commit comments

Comments
 (0)