Fixed Rand.Sample, Vector.MaxDiff and GreaterThan (#440)

* Fixed a bug in Rand.Sample that could cause it to return a value that should have zero probability.
* Added MMath.AbsDiffAllowingNaNs
* Fixed SparseVector.MaxDiff
* DependencyGraphView, ModelView, TaskGraphView implement IDisposable
* Added missing evidence methods
* Added Vector.All(Vector, Func)
This commit is contained in:
Tom Minka 2023-05-20 18:25:36 +01:00 коммит произвёл GitHub
Родитель 968e3b2e8a
Коммит 5bd86ece6b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 516 добавлений и 834 удалений

Просмотреть файл

@ -455,7 +455,7 @@ namespace Microsoft.ML.Probabilistic.Math
convergenceCheck = System.Math.Sqrt(invDim * currentDeriv.Inner(currentDeriv));
break;
case ConvergenceCriteria.Objective:
convergenceCheck = System.Math.Abs(prevObj - currentObj) / System.Math.Max(1, System.Math.Max(prevObj, currentObj));
convergenceCheck = MMath.AbsDiff(prevObj, currentObj, 1);
break;
}
prevObj = currentObj;

Просмотреть файл

@ -269,12 +269,8 @@ namespace Microsoft.ML.Probabilistic.Math
#region LINQ-like operators
/// <summary>
/// Tests if all elements in the vector satisfy the specified condition.
/// </summary>
/// <param name="fun"></param>
/// <returns></returns>
public override bool All(Converter<double, bool> fun)
/// <inheritdoc/>
public override bool All(Func<double, bool> fun)
{
int end = start + count;
for (int i = start; i < end; ++i)
@ -285,12 +281,8 @@ namespace Microsoft.ML.Probabilistic.Math
return true;
}
/// <summary>
/// Tests if any elements in the vector satisfy the specified condition.
/// </summary>
/// <param name="fun"></param>
/// <returns></returns>
public override bool Any(Converter<double, bool> fun)
/// <inheritdoc/>
public override bool Any(Func<double, bool> fun)
{
int end = start + count;
for (int i = start; i < end; ++i)
@ -301,6 +293,7 @@ namespace Microsoft.ML.Probabilistic.Math
return false;
}
/// <inheritdoc/>
public override bool Any(Vector that, Func<double, double, bool> fun)
{
if (that.Sparsity == Sparsity.Dense)
@ -328,13 +321,8 @@ namespace Microsoft.ML.Probabilistic.Math
return false;
}
/// <summary>
/// Returns an enumeration over the indices and values of all the elements which satisfy the specified condition.
/// Indices are returned in sorted order.
/// </summary>
/// <param name="fun">A function to check if the condition is satisfied.</param>
/// <returns>An enumeration over the indices and values of all the elements which satisfy the specified condition.</returns>
public override IEnumerable<ValueAtIndex<double>> FindAll(Converter<double, bool> fun)
/// <inheritdoc/>
public override IEnumerable<ValueAtIndex<double>> FindAll(Func<double, bool> fun)
{
if (fun == null)
{
@ -351,12 +339,8 @@ namespace Microsoft.ML.Probabilistic.Math
}
}
/// <summary>
/// Returns the number of elements in the vector which satisfy a given condition.
/// </summary>
/// <param name="fun">The condition for the elements to satisfy.</param>
/// <returns>The number of elements in the vector which satisfy the condition.</returns>
public override int CountAll(Converter<double, bool> fun)
/// <inheritdoc/>
public override int CountAll(Func<double, bool> fun)
{
if (fun == null)
{
@ -376,22 +360,14 @@ namespace Microsoft.ML.Probabilistic.Math
return result;
}
/// <summary>
/// Returns the index of the first element that satisfies a given condition.
/// </summary>
/// <param name="fun">The condition for the element to satisfy.</param>
/// <returns>The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.</returns>
public override int FindFirstIndex(Converter<double, bool> fun)
/// <inheritdoc/>
public override int FindFirstIndex(Func<double, bool> fun)
{
return Array.FindIndex(this.data, elt => fun(elt));
}
/// <summary>
/// Returns the index of the last element that satisfies a given condition.
/// </summary>
/// <param name="fun">The condition for the element to satisfy.</param>
/// <returns>The zero-based index of the last occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.</returns>
public override int FindLastIndex(Converter<double, bool> fun)
/// <inheritdoc/>
public override int FindLastIndex(Func<double, bool> fun)
{
return Array.FindLastIndex(this.data, elt => fun(elt));
}
@ -1906,12 +1882,7 @@ namespace Microsoft.ML.Probabilistic.Math
#region Object overrides
/// <summary>
/// Determines object equality.
/// </summary>
/// <param name="obj">Another (DenseVector) object.</param>
/// <returns>True if equal.</returns>
/// <exclude/>
/// <inheritdoc/>
public override bool Equals(object obj)
{
Vector that = obj as Vector;
@ -1945,11 +1916,7 @@ namespace Microsoft.ML.Probabilistic.Math
return true;
}
/// <summary>
/// Tests if all elements are equal to a given value.
/// </summary>
/// <param name="value">The value to test against.</param>
/// <returns>True if all elements are equal to <paramref name="value"/>.</returns>
/// <inheritdoc/>
public override bool EqualsAll(double value)
{
int end = start + count;
@ -1960,11 +1927,7 @@ namespace Microsoft.ML.Probabilistic.Math
return true;
}
/// <summary>
/// Tests if all elements are strictly greater than a given value.
/// </summary>
/// <param name="value">The value to test against.</param>
/// <returns>True if all elements are strictly greater than <paramref name="value"/>.</returns>
/// <inheritdoc/>
public override bool GreaterThan(double value)
{
int end = start + count;
@ -1975,11 +1938,7 @@ namespace Microsoft.ML.Probabilistic.Math
return true;
}
/// <summary>
/// Tests if all elements are strictly less than a given value.
/// </summary>
/// <param name="value">The value to test against.</param>
/// <returns>True if all elements are strictly less than <paramref name="value"/>.</returns>
/// <inheritdoc/>
public override bool LessThan(double value)
{
int end = start + count;
@ -1990,11 +1949,7 @@ namespace Microsoft.ML.Probabilistic.Math
return true;
}
/// <summary>
/// Tests if this vector is strictly greater than a second vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is strictly greater than the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc/>
public override bool GreaterThan(Vector that)
{
if (that.Sparsity == Sparsity.Dense)
@ -2012,11 +1967,7 @@ namespace Microsoft.ML.Probabilistic.Math
return (true);
}
/// <summary>
/// Tests if this dense vector is strictly greater than a second dense vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is strictly greater than the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc cref="GreaterThan(Vector)"/>
public bool GreaterThan(DenseVector that)
{
int end = start + count;
@ -2026,11 +1977,7 @@ namespace Microsoft.ML.Probabilistic.Math
return (true);
}
/// <summary>
/// Tests if this vector is strictly less than a second vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is strictly less than the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc/>
public override bool LessThan(Vector that)
{
if (that.Sparsity == Sparsity.Dense)
@ -2048,11 +1995,7 @@ namespace Microsoft.ML.Probabilistic.Math
return (true);
}
/// <summary>
/// Tests if this dense vector is strictly less than a second dense vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is strictly less than the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc cref="LessThan(Vector)"/>
public bool LessThan(DenseVector that)
{
int end = start + count;
@ -2062,11 +2005,7 @@ namespace Microsoft.ML.Probabilistic.Math
return (true);
}
/// <summary>
/// Tests if all elements are greater than or equal to a given value.
/// </summary>
/// <param name="value">The value to test against.</param>
/// <returns>True if all elements are greater than or equal to <paramref name="value"/>.</returns>
/// <inheritdoc/>
public override bool GreaterThanOrEqual(double value)
{
int end = start + count;
@ -2077,11 +2016,7 @@ namespace Microsoft.ML.Probabilistic.Math
return true;
}
/// <summary>
/// Tests if all elements are less than or equal to a given value.
/// </summary>
/// <param name="value">The value to test against.</param>
/// <returns>True if all elements are less than or equal to <paramref name="value"/>.</returns>
/// <inheritdoc/>
public override bool LessThanOrEqual(double value)
{
int end = start + count;
@ -2092,11 +2027,7 @@ namespace Microsoft.ML.Probabilistic.Math
return true;
}
/// <summary>
/// Tests if this vector is greater than or equal to a second vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is greater than or equal to the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc/>
public override bool GreaterThanOrEqual(Vector that)
{
if (that.Sparsity == Sparsity.Dense)
@ -2114,11 +2045,7 @@ namespace Microsoft.ML.Probabilistic.Math
return true;
}
/// <summary>
/// Tests if this dense vector is greater than or equal to a second dense vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is greater than or equal to the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc cref="GreaterThanOrEqual(Vector)"/>
public bool GreaterThanOrEqual(DenseVector that)
{
int end = start + count;
@ -2128,11 +2055,7 @@ namespace Microsoft.ML.Probabilistic.Math
return (true);
}
/// <summary>
/// Tests if this vector is less than or equal to a second vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is strictly less than or equal to the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc/>
public override bool LessThanOrEqual(Vector that)
{
if (that.Sparsity == Sparsity.Dense)
@ -2150,11 +2073,7 @@ namespace Microsoft.ML.Probabilistic.Math
return (true);
}
/// <summary>
/// Tests if this dense vector is less than or equal to a second dense vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is strictly less than or equal to the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc cref="LessThanOrEqual(Vector)"/>
public bool LessThanOrEqual(DenseVector that)
{
int end = start + count;
@ -2164,15 +2083,7 @@ namespace Microsoft.ML.Probabilistic.Math
return (true);
}
/// <summary>
/// Returns the maximum absolute difference between this vector and another vector.
/// </summary>
/// <param name="that">The second vector.</param>
/// <returns><c>max(abs(this[i] - that[i]))</c>.
/// Matching infinities or NaNs do not count.
/// If <c>this</c> and <paramref name="that"/> are not the same size, returns infinity.</returns>
/// <remarks>This routine is typically used instead of <c>Equals</c>, since <c>Equals</c> is susceptible to roundoff errors.
/// </remarks>
/// <inheritdoc/>
public override double MaxDiff(Vector that)
{
if (that.Sparsity == Sparsity.Dense)
@ -2194,13 +2105,9 @@ namespace Microsoft.ML.Probabilistic.Math
bool ynan = Double.IsNaN(y);
if (xnan != ynan)
return Double.PositiveInfinity;
else if (x == y)
{
// catches infinities
// do nothing
}
else
{
// matching infinities or NaNs will not change max
double diff = System.Math.Abs(x - y);
if (diff > max)
{
@ -2212,15 +2119,7 @@ namespace Microsoft.ML.Probabilistic.Math
return max;
}
/// <summary>
/// Returns the maximum absolute difference between this dense vector and another dense vector.
/// </summary>
/// <param name="that">The second vector.</param>
/// <returns><c>max(abs(this[i] - that[i]))</c>.
/// Matching infinities or NaNs do not count.
/// If <c>this</c> and <paramref name="that"/> are not the same size, returns infinity.</returns>
/// <remarks>This routine is typically used instead of <c>Equals</c>, since <c>Equals</c> is susceptible to roundoff errors.
/// </remarks>
/// <inheritdoc cref="MaxDiff(Vector)"/>
public double MaxDiff(DenseVector that)
{
if (count != that.Count)
@ -2238,13 +2137,9 @@ namespace Microsoft.ML.Probabilistic.Math
bool ynan = Double.IsNaN(y);
if (xnan != ynan)
return Double.PositiveInfinity;
else if (x == y)
{
// catches infinities
// do nothing
}
else
{
// matching infinities or NaNs will not change max
double diff = System.Math.Abs(x - y);
if (diff > max)
{
@ -2255,16 +2150,7 @@ namespace Microsoft.ML.Probabilistic.Math
return max;
}
/// <summary>
/// Returns the maximum relative difference between this vector and another.
/// </summary>
/// <param name="that">The second vector.</param>
/// <param name="rel">An offset to avoid division by zero.</param>
/// <returns><c>max(abs(this[i] - that[i])/(abs(this[i]) + rel))</c>.
/// Matching infinities or NaNs do not count.
/// If <c>this</c> and <paramref name="that"/> are not the same size, returns infinity.</returns>
/// <remarks>This routine is typically used instead of <c>Equals</c>, since <c>Equals</c> is susceptible to roundoff errors.
/// </remarks>
/// <inheritdoc/>
public override double MaxDiff(Vector that, double rel)
{
if (that.Sparsity == Sparsity.Dense)
@ -2286,14 +2172,10 @@ namespace Microsoft.ML.Probabilistic.Math
bool ynan = Double.IsNaN(y);
if (xnan != ynan)
return Double.PositiveInfinity;
else if (x == y)
{
// catches infinities
// do nothing
}
else
{
double diff = System.Math.Abs(x - y) / (System.Math.Abs(x) + rel);
// matching infinities or NaNs will not change max
double diff = MMath.AbsDiff(x, y, rel);
if (diff > max)
{
max = diff;
@ -2304,16 +2186,7 @@ namespace Microsoft.ML.Probabilistic.Math
return max;
}
/// <summary>
/// Returns the maximum relative difference between this dense vector and another.
/// </summary>
/// <param name="that">The second vector.</param>
/// <param name="rel">An offset to avoid division by zero.</param>
/// <returns><c>max(abs(this[i] - that[i])/(abs(this[i]) + rel))</c>.
/// Matching infinities or NaNs do not count.
/// If <c>this</c> and <paramref name="that"/> are not the same size, returns infinity.</returns>
/// <remarks>This routine is typically used instead of <c>Equals</c>, since <c>Equals</c> is susceptible to roundoff errors.
/// </remarks>
/// <inheritdoc cref="MaxDiff(Vector, double)"/>
public double MaxDiff(DenseVector that, double rel)
{
if (count != that.Count)
@ -2323,7 +2196,6 @@ namespace Microsoft.ML.Probabilistic.Math
double max = 0.0;
int end = start + count;
DenseVector thatd = (DenseVector)that;
for (int i = start, j = that.start; i < end;)
{
double x = this.data[i++];
@ -2332,14 +2204,10 @@ namespace Microsoft.ML.Probabilistic.Math
bool ynan = Double.IsNaN(y);
if (xnan != ynan)
return Double.PositiveInfinity;
else if (x == y)
{
// catches infinities
// do nothing
}
else
{
double diff = System.Math.Abs(x - y) / (System.Math.Abs(x) + rel);
// matching infinities or NaNs will not change max
double diff = MMath.AbsDiff(x, y, rel);
if (diff > max)
{
max = diff;

Просмотреть файл

@ -195,7 +195,7 @@ namespace Microsoft.ML.Probabilistic.Math
convergenceCheck = System.Math.Sqrt(invDim * currentDeriv.Inner(currentDeriv));
break;
case ConvergenceCriteria.Objective:
convergenceCheck = System.Math.Abs(prevObj - currentObj) / System.Math.Max(1, System.Math.Max(prevObj, currentObj));
convergenceCheck = MMath.AbsDiff(prevObj, currentObj, 1);
break;
}
prevObj = currentObj;
@ -429,7 +429,7 @@ namespace Microsoft.ML.Probabilistic.Math
convergenceCheck = System.Math.Sqrt(invDim * currentDeriv.Select(o => o.Inner(o)).Sum());
break;
case ConvergenceCriteria.Objective:
convergenceCheck = System.Math.Abs(prevObj - currentObj) / System.Math.Max(1, System.Math.Max(prevObj, currentObj));
convergenceCheck = MMath.AbsDiff(prevObj, currentObj, 1);
break;
}
prevObj = currentObj;

Просмотреть файл

@ -429,9 +429,9 @@ namespace Microsoft.ML.Probabilistic.Math
{
return Double.PositiveInfinity;
}
else if (x != y)
else
{
// catches infinities
// matching infinities will not change max
double diff = System.Math.Abs(x - y);
if (diff > max) max = diff;
}

Просмотреть файл

@ -759,22 +759,14 @@ namespace Microsoft.ML.Probabilistic.Math
#region Equality
/// <summary>
/// Determines object equality.
/// </summary>
/// <param name="obj">Another (vector) object.</param>
/// <returns>True if equal.</returns>
/// <exclude/>
/// <inheritdoc/>
public override bool Equals(object obj)
{
var that = obj as Vector;
if (ReferenceEquals(this, that)) return true;
if (ReferenceEquals(that, null))
return false;
if (ReferenceEquals(that, null)) return false;
if (Count != that.Count) return false;
// TODO: change to maxdiff?
Vector diff = this - that;
return diff.EqualsAll(0.0);
return this.MaxDiff(that) == 0;
}
/// <summary>
@ -790,86 +782,45 @@ namespace Microsoft.ML.Probabilistic.Math
return hash;
}
/// <summary>
/// Tests if this vector is strictly greater than a second vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is strictly greater than the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc/>
public override bool GreaterThan(Vector that)
{
return (this - that).GreaterThan(0);
return this.All(that, (x, y) => x > y);
}
/// <summary>
/// Tests if this vector is strictly less than a second vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is strictly less than the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc/>
public override bool LessThan(Vector that)
{
return (this - that).LessThan(0);
return this.All(that, (x, y) => x < y);
}
/// <summary>
/// Tests if this vector is than or equal to a second vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is greater than or equal to the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc/>
public override bool GreaterThanOrEqual(Vector that)
{
return (this - that).GreaterThanOrEqual(0);
return this.All(that, (x, y) => x >= y);
}
/// <summary>
/// Tests if this vector is less than or equal to a second vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is strictly less than or equal to the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc/>
public override bool LessThanOrEqual(Vector that)
{
return (this - that).LessThanOrEqual(0);
return this.All(that, (x, y) => x <= y);
}
/// <summary>
/// Returns the maximum absolute difference between this vector and another vector.
/// </summary>
/// <param name="that">The second vector.</param>
/// <returns><c>max(abs(this[i] - that[i]))</c>.
/// Matching infinities or NaNs do not count.
/// If <c>this</c> and <paramref name="that"/> are not the same size, returns infinity.</returns>
/// <remarks>This routine is typically used instead of <c>Equals</c>, since <c>Equals</c> is susceptible to roundoff errors.
/// </remarks>
/// <inheritdoc/>
public override double MaxDiff(Vector that)
{
if (Count != that.Count) return Double.PositiveInfinity;
var absdiff = new PiecewiseVector(Count);
absdiff.SetToFunction(this, that, (a, b) => a == b ? 0 : System.Math.Abs(a - b));
// TODO: consider copying behaviour of Vector, which is roughly:
//bool xnan = Double.IsNaN(x);
//bool ynan = Double.IsNaN(y);
//if (xnan != ynan) return Double.PositiveInfinity;
//else if (x != y)
//{
// double diff = Math.Abs(x - y);
//}
absdiff.SetToFunction(this, that, (a, b) => MMath.AbsDiffAllowingNaNs(a, b));
return absdiff.Max();
}
/// <summary>
/// Returns the maximum relative difference between this vector and another.
/// </summary>
/// <param name="that">The second vector.</param>
/// <param name="rel">An offset to avoid division by zero.</param>
/// <returns><c>max(abs(this[i] - that[i])/(abs(this[i]) + rel))</c>.
/// Matching infinities or NaNs do not count.
/// If <c>this</c> and <paramref name="that"/> are not the same size, returns infinity.</returns>
/// <remarks>This routine is typically used instead of <c>Equals</c>, since <c>Equals</c> is susceptible to roundoff errors.
/// </remarks>
/// <inheritdoc/>
public override double MaxDiff(Vector that, double rel)
{
var absdiff = new PiecewiseVector(Count);
absdiff.SetToFunction(this, that, (a, b) => System.Math.Abs(a - b)/(System.Math.Abs(a) + rel));
absdiff.SetToFunction(this, that, (a, b) => MMath.AbsDiffAllowingNaNs(a, b, rel));
return absdiff.Max();
}
@ -877,12 +828,8 @@ namespace Microsoft.ML.Probabilistic.Math
#region LINQ-like operators (All, Any, FindAll etc.)
/// <summary>
/// Tests if all elements in the vector satisfy the specified condition.
/// </summary>
/// <param name="fun">The condition for the elements to satisfy.</param>
/// <returns>True if all elements satisfy the condition, false otherwise.</returns>
public override bool All(Converter<double, bool> fun)
/// <inheritdoc/>
public override bool All(Func<double, bool> fun)
{
if (this.HasCommonElements() && !fun(this.CommonValue))
{
@ -900,12 +847,8 @@ namespace Microsoft.ML.Probabilistic.Math
return true;
}
/// <summary>
/// Tests if any elements in the vector satisfy the specified condition.
/// </summary>
/// <param name="fun">The condition for the elements to satisfy.</param>
/// <returns>True if any elements satisfy the condition, false otherwise.</returns>
public override bool Any(Converter<double, bool> fun)
/// <inheritdoc/>
public override bool Any(Func<double, bool> fun)
{
if (this.HasCommonElements() && fun(this.CommonValue))
{
@ -923,6 +866,7 @@ namespace Microsoft.ML.Probabilistic.Math
return false;
}
/// <inheritdoc/>
public override bool Any(Vector that, Func<double, double, bool> fun)
{
if (that.Sparsity.IsPiecewise)
@ -933,6 +877,7 @@ namespace Microsoft.ML.Probabilistic.Math
return base.Any(that, fun);
}
/// <inheritdoc cref="Any(Vector, Func{double, double, bool})"/>
public bool Any(PiecewiseVector that, Func<double, double, bool> fun)
{
bool any = false;
@ -940,13 +885,8 @@ namespace Microsoft.ML.Probabilistic.Math
return any;
}
/// <summary>
/// Returns an enumeration over the indices and values of all the elements which satisfy the specified condition.
/// Indices are returned in sorted order.
/// </summary>
/// <param name="fun">A function to check if the condition is satisfied.</param>
/// <returns>An enumeration over the indices and values of all the elements which satisfy the specified condition.</returns>
public override IEnumerable<ValueAtIndex<double>> FindAll(Converter<double, bool> fun)
/// <inheritdoc/>
public override IEnumerable<ValueAtIndex<double>> FindAll(Func<double, bool> fun)
{
if (fun == null)
{
@ -979,12 +919,8 @@ namespace Microsoft.ML.Probabilistic.Math
}
}
/// <summary>
/// Returns the number of elements in the vector which satisfy a given condition.
/// </summary>
/// <param name="fun">The condition for the elements to satisfy.</param>
/// <returns>The number of elements in the vector which satisfy the condition.</returns>
public override int CountAll(Converter<double, bool> fun)
/// <inheritdoc/>
public override int CountAll(Func<double, bool> fun)
{
if (fun == null)
{
@ -1011,12 +947,8 @@ namespace Microsoft.ML.Probabilistic.Math
return result;
}
/// <summary>
/// Returns the index of the first element that satisfies a given condition.
/// </summary>
/// <param name="fun">The condition for the element to satisfy.</param>
/// <returns>The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.</returns>
public override int FindFirstIndex(Converter<double, bool> fun)
/// <inheritdoc/>
public override int FindFirstIndex(Func<double, bool> fun)
{
if (fun == null)
{
@ -1051,12 +983,8 @@ namespace Microsoft.ML.Probabilistic.Math
return firstIndex;
}
/// <summary>
/// Returns the index of the last element that satisfies a given condition.
/// </summary>
/// <param name="fun">The condition for the element to satisfy.</param>
/// <returns>The last index.</returns>
public override int FindLastIndex(Converter<double, bool> fun)
/// <inheritdoc/>
public override int FindLastIndex(Func<double, bool> fun)
{
if (fun == null)
{

Просмотреть файл

@ -273,7 +273,8 @@ namespace Microsoft.ML.Probabilistic.Math
double cumsum = prob[x];
Assert.IsTrue(prob[x] >= 0, "negative probability");
Assert.IsTrue(sum > 0, "sum is not positive");
double u = gen.NextDouble()*sum;
double u = gen.NextDouble() * sum;
u = System.Math.Max(u, double.Epsilon);
while (u > cumsum)
{
++x;
@ -297,7 +298,8 @@ namespace Microsoft.ML.Probabilistic.Math
double cumsum = prob[x];
Assert.IsTrue(prob[x] >= 0, "negative probability");
Assert.IsTrue(sum > 0, "sum is not positive");
double u = gen.NextDouble()*sum;
double u = gen.NextDouble() * sum;
u = System.Math.Max(u, double.Epsilon);
while (u > cumsum)
{
++x;
@ -326,15 +328,15 @@ namespace Microsoft.ML.Probabilistic.Math
/* Generate a random point inside the unit circle */
do
{
x1 = 2.0*gen.NextDouble() - 1.0;
x2 = 2.0*gen.NextDouble() - 1.0;
w = (x1*x1) + (x2*x2);
x1 = 2.0 * gen.NextDouble() - 1.0;
x2 = 2.0 * gen.NextDouble() - 1.0;
w = (x1 * x1) + (x2 * x2);
} while ((w >= 1.0) || (w == 0.0));
/* Apply the Box-Muller formula */
w = System.Math.Sqrt(-2.0* System.Math.Log(w) / w);
x1 = w*x1;
x2 = w*x2;
w = System.Math.Sqrt(-2.0 * System.Math.Log(w) / w);
x1 = w * x1;
x2 = w * x2;
usePreviousSample = true;
previousSample = x2;
@ -350,7 +352,7 @@ namespace Microsoft.ML.Probabilistic.Math
[Stochastic]
public static double Normal(double mean, double stdDev)
{
return mean + stdDev*Normal();
return mean + stdDev * Normal();
}
/// <summary>
@ -454,28 +456,28 @@ namespace Microsoft.ML.Probabilistic.Math
{
// Devroye's (Ch.9) rejection sampler with x ~ Exp(lowerBound)
// requires lowerBound > 0
double c = 2*lowerBound*lowerBound;
double c = 2 * lowerBound * lowerBound;
while (true)
{
// note it is possible to generate two exponential r.v.s with a single logarithm (Devroye Ch.9 sec.2.1)
double E = -System.Math.Log(Rand.Double());
double E2 = -System.Math.Log(Rand.Double());
if (E*E <= c*E2) return lowerBound + E/lowerBound;
if (E * E <= c * E2) return lowerBound + E / lowerBound;
}
}
else
{
// Marsaglia's (1964) rejection sampler (Devroye Ch.9)
// Reference: "Non-Uniform Random Variate Generation" by Luc Devroye (1986)
double c = lowerBound*lowerBound*0.5;
double c = lowerBound * lowerBound * 0.5;
while (true)
{
double U = Rand.Double();
double V = Rand.Double();
double x = c - System.Math.Log(U);
if (V*V*x <= c)
if (V * V * x <= c)
{
return System.Math.Sqrt(2* x);
return System.Math.Sqrt(2 * x);
}
}
}
@ -535,13 +537,13 @@ namespace Microsoft.ML.Probabilistic.Math
{
// Rejection sampler using truncated exponential proposal
double lambda = lowerBound;
double s = MMath.ExpMinus1(-lambda*delta);
double c = 2*lambda*lambda;
double s = MMath.ExpMinus1(-lambda * delta);
double c = 2 * lambda * lambda;
while (true)
{
double x = -MMath.Log1Plus(s * Rand.Double());
double u = -System.Math.Log(Rand.Double());
if (c*u > x*x) return x/lambda + lowerBound;
if (c * u > x * x) return x / lambda + lowerBound;
}
throw new InferRuntimeException("failed to sample");
}
@ -554,9 +556,9 @@ namespace Microsoft.ML.Probabilistic.Math
// Uniform rejection
while (true)
{
double x = Rand.Double()*delta + lowerBound;
double x = Rand.Double() * delta + lowerBound;
double u = -System.Math.Log(Rand.Double());
if (2*u > x*x) return x;
if (2 * u > x * x) return x;
}
}
else
@ -577,7 +579,7 @@ namespace Microsoft.ML.Probabilistic.Math
// http://portal.acm.org/citation.cfm?id=358414
private static double GammaShapeGE1(double a)
{
double d = a - 1.0/3, c = 1.0/ System.Math.Sqrt(9* d);
double d = a - 1.0 / 3, c = 1.0 / System.Math.Sqrt(9 * d);
double v;
while (true)
{
@ -585,10 +587,10 @@ namespace Microsoft.ML.Probabilistic.Math
do
{
x = Normal();
v = 1 + c*x;
v = 1 + c * x;
} while (v <= 0);
v = v*v*v;
x = x*x;
v = v * v * v;
x = x * x;
double u = gen.NextDouble();
#if false
// first version
@ -598,13 +600,13 @@ namespace Microsoft.ML.Probabilistic.Math
}
#else
// faster version
if ((u < 1 - .0331* x * x) || (System.Math.Log(u) < 0.5* x + d*(1 - v + System.Math.Log(v))))
if ((u < 1 - .0331 * x * x) || (System.Math.Log(u) < 0.5 * x + d * (1 - v + System.Math.Log(v))))
{
break;
}
#endif
}
return d*v;
return d * v;
}
/// <summary>
@ -672,10 +674,10 @@ namespace Microsoft.ML.Probabilistic.Math
{
for (int j = 0; j < i; ++j)
{
result[i, j] = Normal()*MMath.SqrtHalf;
result[i, j] = Normal() * MMath.SqrtHalf;
result[j, i] = 0;
}
result[i, i] = System.Math.Sqrt(Gamma(a - i*0.5));
result[i, i] = System.Math.Sqrt(Gamma(a - i * 0.5));
}
}
@ -693,9 +695,9 @@ namespace Microsoft.ML.Probabilistic.Math
{
// To handle small counts, use Stuart's (1962) theorem:
// gamma(a) has the same distribution as gamma(a+1)*exp(log(U)/a)
double boost1 = System.Math.Log(gen.NextDouble())/ trueCount;
double boost1 = System.Math.Log(gen.NextDouble()) / trueCount;
trueCount++;
double boost2 = System.Math.Log(gen.NextDouble())/ falseCount;
double boost2 = System.Math.Log(gen.NextDouble()) / falseCount;
falseCount++;
if (boost1 > boost2)
{
@ -715,7 +717,7 @@ namespace Microsoft.ML.Probabilistic.Math
gTrue = Rand.Gamma(trueCount);
gFalse = Rand.Gamma(falseCount);
}
return gTrue/(gTrue + gFalse);
return gTrue / (gTrue + gFalse);
}
/// <summary>
@ -734,7 +736,7 @@ namespace Microsoft.ML.Probabilistic.Math
// If pseudo-count is sparse and its common value is not 0, we need
// to process it as a dense vector so that samples from common value
// are allowed to differ
if (pseudoCount.IsSparse && ((SparseVector) pseudoCount).CommonValue != 0.0)
if (pseudoCount.IsSparse && ((SparseVector)pseudoCount).CommonValue != 0.0)
pseudoCount = DenseVector.Copy(pseudoCount);
if (pseudoCount.Max() < 1)
@ -742,16 +744,16 @@ namespace Microsoft.ML.Probabilistic.Math
// To handle small counts, use Stuart's (1962) theorem:
// gamma(a) has the same distribution as gamma(a+1)*exp(log(U)/a)
Vector boost = Vector.Copy(pseudoCount);
boost.SetToFunction(pseudoCount, a => System.Math.Log(gen.NextDouble())/ a);
boost.SetToFunction(pseudoCount, a => System.Math.Log(gen.NextDouble()) / a);
double maxBoost = boost.Max();
result.SetToFunction(pseudoCount, boost, (a, b) => Rand.Gamma(a + 1)* System.Math.Exp(b - maxBoost));
result.SetToFunction(pseudoCount, boost, (a, b) => Rand.Gamma(a + 1) * System.Math.Exp(b - maxBoost));
}
else
{
result.SetToFunction(pseudoCount, a => Rand.Gamma(a));
}
double sum = result.Sum();
result.Scale(1.0/sum);
result.Scale(1.0 / sum);
return result;
}
@ -770,7 +772,7 @@ namespace Microsoft.ML.Probabilistic.Math
[Stochastic]
public static int Binomial(int n, double p)
{
if (p*(n + 1) == n + 1) return n;
if (p * (n + 1) == n + 1) return n;
if (n < 15)
{
// coin flip method
@ -782,20 +784,20 @@ namespace Microsoft.ML.Probabilistic.Math
}
return result;
}
else if (n*p < 150)
else if (n * p < 150)
{
// waiting time method
// this takes O(np) time
double q = -System.Math.Log(1 - p);
int r = n;
double e = -System.Math.Log(Rand.Double());
double s = e/r;
double s = e / r;
while (s <= q)
{
r--;
if (r == 0) break;
e = -System.Math.Log(Rand.Double());
s = s + e/r;
s = s + e / r;
}
return n - r;
}
@ -803,12 +805,12 @@ namespace Microsoft.ML.Probabilistic.Math
{
// recursive method
// this makes O(log(log(n))) recursive calls
int i = (int) (p*(n + 1));
int i = (int)(p * (n + 1));
double b = Rand.Beta(i, n + 1 - i);
if (b <= p)
return i + Rand.Binomial(n - i, (p - b)/(1 - b));
return i + Rand.Binomial(n - i, (p - b) / (1 - b));
else
return i - 1 - Rand.Binomial(i - 1, (b - p)/b);
return i - 1 - Rand.Binomial(i - 1, (b - p) / b);
}
}
@ -821,7 +823,7 @@ namespace Microsoft.ML.Probabilistic.Math
[Stochastic]
public static int[] Multinomial(int trialCount, Vector probs)
{
return Multinomial(trialCount, (DenseVector) probs);
return Multinomial(trialCount, (DenseVector)probs);
}
/// <summary>
@ -838,7 +840,7 @@ namespace Microsoft.ML.Probabilistic.Math
double remainingProb = 1;
for (int dim = 0; dim < result.Length - 1; dim++)
{
int sample = Binomial(trialCount, probs[dim]/remainingProb);
int sample = Binomial(trialCount, probs[dim] / remainingProb);
result[dim] = sample;
trialCount -= sample;
remainingProb -= probs[dim];
@ -879,15 +881,15 @@ namespace Microsoft.ML.Probabilistic.Math
double mu = System.Math.Floor(mean);
double muLogFact = MMath.GammaLn(mu + 1);
double logMeanMu = System.Math.Log(mean / mu);
double delta = System.Math.Max(6, System.Math.Min(mu, System.Math.Sqrt(2* mu * System.Math.Log(128* mu / System.Math.PI))));
double c1 = System.Math.Sqrt(System.Math.PI* mu / 2);
double c2 = c1 + System.Math.Sqrt(System.Math.PI*(mu + delta/2)/2)* System.Math.Exp(1/(2* mu + delta));
double delta = System.Math.Max(6, System.Math.Min(mu, System.Math.Sqrt(2 * mu * System.Math.Log(128 * mu / System.Math.PI))));
double c1 = System.Math.Sqrt(System.Math.PI * mu / 2);
double c2 = c1 + System.Math.Sqrt(System.Math.PI * (mu + delta / 2) / 2) * System.Math.Exp(1 / (2 * mu + delta));
double c3 = c2 + 2;
double c4 = c3 + System.Math.Exp(1.0/78);
double c = c4 + 2/ delta * (2* mu + delta)* System.Math.Exp(-delta / (2* mu + delta)*(1 + delta/2));
double c4 = c3 + System.Math.Exp(1.0 / 78);
double c = c4 + 2 / delta * (2 * mu + delta) * System.Math.Exp(-delta / (2 * mu + delta) * (1 + delta / 2));
while (true)
{
double u = Rand.Double()*c;
double u = Rand.Double() * c;
double x, w;
if (u <= c1)
{
@ -895,15 +897,15 @@ namespace Microsoft.ML.Probabilistic.Math
double y = -System.Math.Abs(n) * System.Math.Sqrt(mu) - 1;
x = System.Math.Floor(y);
if (x < -mu) continue;
w = -n*n/2;
w = -n * n / 2;
}
else if (u <= c2)
{
double n = Rand.Normal();
double y = 1 + System.Math.Abs(n) * System.Math.Sqrt(mu + delta/2);
double y = 1 + System.Math.Abs(n) * System.Math.Sqrt(mu + delta / 2);
x = System.Math.Ceiling(y);
if (x > delta) continue;
w = (2 - y)*y/(2*mu + delta);
w = (2 - y) * y / (2 * mu + delta);
}
else if (u <= c3)
{
@ -918,13 +920,13 @@ namespace Microsoft.ML.Probabilistic.Math
else
{
double v = -System.Math.Log(Rand.Double());
double y = delta + v*2/delta*(2*mu + delta);
double y = delta + v * 2 / delta * (2 * mu + delta);
x = System.Math.Ceiling(y);
w = -delta/(2*mu + delta)*(1 + y/2);
w = -delta / (2 * mu + delta) * (1 + y / 2);
}
double e = -System.Math.Log(Rand.Double());
w -= e + x*logMeanMu;
double qx = x* System.Math.Log(mu) - MMath.GammaLn(mu + x + 1) + muLogFact;
w -= e + x * logMeanMu;
double qx = x * System.Math.Log(mu) - MMath.GammaLn(mu + x + 1) + muLogFact;
if (w <= qx) return (int)System.Math.Round(x + mu);
}
}

Просмотреть файл

@ -564,12 +564,7 @@ namespace Microsoft.ML.Probabilistic.Math
#region Equality
/// <summary>
/// Determines object equality.
/// </summary>
/// <param name="obj">Another (vector) object.</param>
/// <returns>True if equal.</returns>
/// <exclude/>
/// <inheritdoc/>
public override bool Equals(object obj)
{
var that = obj as Vector;
@ -577,9 +572,7 @@ namespace Microsoft.ML.Probabilistic.Math
if (ReferenceEquals(that, null))
return false;
if (this.Count != that.Count) return false;
// TODO: change to maxdiff?
Vector diff = this - that;
return diff.EqualsAll(0.0);
return this.MaxDiff(that) == 0;
}
/// <summary>
@ -595,86 +588,45 @@ namespace Microsoft.ML.Probabilistic.Math
return hash;
}
/// <summary>
/// Tests if this vector is strictly greater than a second vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is strictly greater than the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc/>
public override bool GreaterThan(Vector that)
{
return (this - that).GreaterThan(0);
return this.All(that, (x, y) => x > y);
}
/// <summary>
/// Tests if this vector is strictly less than a second vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is strictly less than the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc/>
public override bool LessThan(Vector that)
{
return (this - that).LessThan(0);
return this.All(that, (x, y) => x < y);
}
/// <summary>
/// Tests if this vector is than or equal to a second vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is greater than or equal to the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc/>
public override bool GreaterThanOrEqual(Vector that)
{
return (this - that).GreaterThanOrEqual(0);
return this.All(that, (x, y) => x >= y);
}
/// <summary>
/// Tests if this vector is less than or equal to a second vector.
/// </summary>
/// <param name="that">The value to test against.</param>
/// <returns>True if each element is strictly less than or equal to the corresponding element of <paramref name="that"/>.</returns>
/// <inheritdoc/>
public override bool LessThanOrEqual(Vector that)
{
return (this - that).LessThanOrEqual(0);
return this.All(that, (x, y) => x <= y);
}
/// <summary>
/// Returns the maximum absolute difference between this vector and another vector.
/// </summary>
/// <param name="that">The second vector.</param>
/// <returns><c>max(abs(this[i] - that[i]))</c>.
/// Matching infinities or NaNs do not count.
/// If <c>this</c> and <paramref name="that"/> are not the same size, returns infinity.</returns>
/// <remarks>This routine is typically used instead of <c>Equals</c>, since <c>Equals</c> is susceptible to roundoff errors.
/// </remarks>
/// <inheritdoc/>
public override double MaxDiff(Vector that)
{
if (Count != that.Count) return Double.PositiveInfinity;
var absdiff = new SparseVector(Count);
absdiff.SetToFunction(this, that, (a, b) => System.Math.Abs(a - b));
// TODO: consider copying behaviour of Vector, which is roughly:
//bool xnan = Double.IsNaN(x);
//bool ynan = Double.IsNaN(y);
//if (xnan != ynan) return Double.PositiveInfinity;
//else if (x != y)
//{
// double diff = Math.Abs(x - y);
//}
absdiff.SetToFunction(this, that, (a, b) => MMath.AbsDiffAllowingNaNs(a, b));
return absdiff.Max();
}
/// <summary>
/// Returns the maximum relative difference between this vector and another.
/// </summary>
/// <param name="that">The second vector.</param>
/// <param name="rel">An offset to avoid division by zero.</param>
/// <returns><c>max(abs(this[i] - that[i])/(abs(this[i]) + rel))</c>.
/// Matching infinities or NaNs do not count.
/// If <c>this</c> and <paramref name="that"/> are not the same size, returns infinity.</returns>
/// <remarks>This routine is typically used instead of <c>Equals</c>, since <c>Equals</c> is susceptible to roundoff errors.
/// </remarks>
/// <inheritdoc/>
public override double MaxDiff(Vector that, double rel)
{
var absdiff = new SparseVector(Count);
absdiff.SetToFunction(this, that, (a, b) => System.Math.Abs(a - b)/(System.Math.Abs(a) + rel));
absdiff.SetToFunction(this, that, (a, b) => MMath.AbsDiffAllowingNaNs(a, b, rel));
return absdiff.Max();
}
@ -682,12 +634,8 @@ namespace Microsoft.ML.Probabilistic.Math
#region LINQ-like operators (All, Any, FindAll etc.)
/// <summary>
/// Tests if all elements in the vector satisfy the specified condition.
/// </summary>
/// <param name="fun"></param>
/// <returns></returns>
public override bool All(Converter<double, bool> fun)
/// <inheritdoc/>
public override bool All(Func<double, bool> fun)
{
if (HasCommonElements)
{
@ -701,12 +649,8 @@ namespace Microsoft.ML.Probabilistic.Math
return true;
}
/// <summary>
/// Tests if any elements in the vector satisfy the specified condition.
/// </summary>
/// <param name="fun"></param>
/// <returns></returns>
public override bool Any(Converter<double, bool> fun)
/// <inheritdoc/>
public override bool Any(Func<double, bool> fun)
{
if (HasCommonElements)
{
@ -719,12 +663,7 @@ namespace Microsoft.ML.Probabilistic.Math
return false;
}
/// <summary>
/// Test if any corresponding elements in this and that vector satisfy a condition
/// </summary>
/// <param name="that"></param>
/// <param name="fun"></param>
/// <returns></returns>
/// <inheritdoc/>
public override bool Any(Vector that, Func<double, double, bool> fun)
{
if (that.IsSparse)
@ -734,12 +673,7 @@ namespace Microsoft.ML.Probabilistic.Math
return base.Any(that, fun);
}
/// <summary>
/// Test if any corresponding elements in this and that vector satisfy a condition
/// </summary>
/// <param name="that"></param>
/// <param name="fun"></param>
/// <returns></returns>
/// <inheritdoc cref="Any(Vector, Func{double, double, bool})"/>
public bool Any(SparseVector that, Func<double, double, bool> fun)
{
CheckCompatible(that, nameof(that));
@ -791,13 +725,8 @@ namespace Microsoft.ML.Probabilistic.Math
return false;
}
/// <summary>
/// Returns an enumeration over the indices of all elements which satisfy the specified condition.
/// Indices are returned in sorted order.
/// </summary>
/// <param name="fun">A function to check if the condition is satisfied.</param>
/// <returns>An enumeration over the indices and values of all the elements which satisfy the specified condition.</returns>
public override IEnumerable<ValueAtIndex<double>> FindAll(Converter<double, bool> fun)
/// <inheritdoc/>
public override IEnumerable<SparseElement> FindAll(Func<double, bool> fun)
{
if (fun == null)
{
@ -810,12 +739,12 @@ namespace Microsoft.ML.Probabilistic.Math
{
for (; index < sparseElement.Index && funIsTrueForCommonValue; ++index)
{
yield return new ValueAtIndex<double>(index, this.CommonValue);
yield return new SparseElement(index, this.CommonValue);
}
if (fun(sparseElement.Value))
{
yield return new ValueAtIndex<double>(sparseElement.Index, sparseElement.Value);
yield return new SparseElement(sparseElement.Index, sparseElement.Value);
}
index = sparseElement.Index + 1;
@ -823,16 +752,12 @@ namespace Microsoft.ML.Probabilistic.Math
for (; index < this.Count && funIsTrueForCommonValue; ++index)
{
yield return new ValueAtIndex<double>(index, this.CommonValue);
yield return new SparseElement(index, this.CommonValue);
}
}
/// <summary>
/// Returns the number of elements in the vector which satisfy a given condition.
/// </summary>
/// <param name="fun">The condition for the elements to satisfy.</param>
/// <returns>The number of elements in the vector which satisfy the condition.</returns>
public override int CountAll(Converter<double, bool> fun)
/// <inheritdoc/>
public override int CountAll(Func<double, bool> fun)
{
if (fun == null)
{
@ -858,12 +783,8 @@ namespace Microsoft.ML.Probabilistic.Math
return result;
}
/// <summary>
/// Returns the index of the first element that satisfies a given condition.
/// </summary>
/// <param name="fun">The condition for the element to satisfy.</param>
/// <returns>The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.</returns>
public override int FindFirstIndex(Converter<double, bool> fun)
/// <inheritdoc/>
public override int FindFirstIndex(Func<double, bool> fun)
{
if (fun == null)
{
@ -898,12 +819,8 @@ namespace Microsoft.ML.Probabilistic.Math
return firstIndex;
}
/// <summary>
/// Returns the index of the last element that satisfies a given condition.
/// </summary>
/// <param name="fun">The condition for the element to satisfy.</param>
/// <returns>The last index.</returns>
public override int FindLastIndex(Converter<double, bool> fun)
/// <inheritdoc/>
public override int FindLastIndex(Func<double, bool> fun)
{
if (fun == null)
{
@ -2729,38 +2646,21 @@ namespace Microsoft.ML.Probabilistic.Math
return hash;
}
/// <summary>
/// Returns the maximum absolute difference between this vector and another vector.
/// </summary>
/// <param name="that">The second vector.</param>
/// <returns><c>max(abs(this[i] - that[i]))</c>.
/// Matching infinities or NaNs do not count.
/// If <c>this</c> and <paramref name="that"/> are not the same size, returns infinity.</returns>
/// <remarks>This routine is typically used instead of <c>Equals</c>, since <c>Equals</c> is susceptible to roundoff errors.
/// </remarks>
/// <inheritdoc/>
public override double MaxDiff(Vector that)
{
if (Count != that.Count) return Double.PositiveInfinity;
var absdiff = new ApproximateSparseVector(Count);
absdiff.SetToFunction(this, that, (a, b) => System.Math.Abs(a - b));
absdiff.SetToFunction(this, that, (a, b) => MMath.AbsDiffAllowingNaNs(a, b));
return absdiff.Max();
}
/// <summary>
/// Returns the maximum relative difference between this vector and another.
/// </summary>
/// <param name="that">The second vector.</param>
/// <param name="rel">An offset to avoid division by zero.</param>
/// <returns><c>max(abs(this[i] - that[i])/(abs(this[i]) + rel))</c>.
/// Matching infinities or NaNs do not count.
/// If <c>this</c> and <paramref name="that"/> are not the same size, returns infinity.</returns>
/// <remarks>This routine is typically used instead of <c>Equals</c>, since <c>Equals</c> is susceptible to roundoff errors.
/// </remarks>
/// <inheritdoc/>
public override double MaxDiff(Vector that, double rel)
{
var absdiff = new ApproximateSparseVector(Count);
absdiff.SetToFunction(this, that, (a, b) => System.Math.Abs(a - b)/(System.Math.Abs(a) + rel));
absdiff.SetToFunction(this, that, (a, b) => MMath.AbsDiffAllowingNaNs(a, b, rel));
return absdiff.Max();
}

Просмотреть файл

@ -4782,8 +4782,8 @@ rr = mpf('-0.99999824265582826');
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="rel">An offset to avoid division by zero.</param>
/// <returns><c>abs(x - y)/(abs(x) + rel)</c>.
/// Matching infinities give zero.
/// <returns><c>abs(x - y)/(min(abs(x),abs(y)) + rel)</c>.
/// Matching infinities give zero. Any NaN gives NaN.
/// </returns>
/// <remarks>
/// This routine is often used to measure the error of y in estimating x.
@ -4795,13 +4795,32 @@ rr = mpf('-0.99999824265582826');
return Math.Abs(x - y) / (Math.Min(Math.Abs(x), Math.Abs(y)) + rel);
}
/// <summary>
/// Returns the relative distance between two numbers.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="rel">An offset to avoid division by zero.</param>
/// <returns><c>abs(x - y)/(min(abs(x),abs(y)) + rel)</c>.
/// Matching infinities or NaNs give zero.
/// </returns>
/// <remarks>
/// This routine is often used to measure the error of y in estimating x.
/// </remarks>
public static double AbsDiffAllowingNaNs(double x, double y, double rel)
{
if (double.IsNaN(x)) return double.IsNaN(y) ? 0 : double.PositiveInfinity;
if (double.IsNaN(y)) return double.PositiveInfinity;
return AbsDiff(x, y, rel);
}
/// <summary>
/// Returns the distance between two numbers.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns><c>abs(x - y)</c>.
/// Matching infinities give zero.
/// Matching infinities give zero. Any NaN gives NaN.
/// </returns>
public static double AbsDiff(double x, double y)
{
@ -4810,6 +4829,21 @@ rr = mpf('-0.99999824265582826');
return Math.Abs(x - y);
}
/// <summary>
/// Returns the distance between two numbers.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns><c>abs(x - y)</c>.
/// Matching infinities or NaNs give zero.
/// </returns>
public static double AbsDiffAllowingNaNs(double x, double y)
{
if (double.IsNaN(x)) return double.IsNaN(y) ? 0 : double.PositiveInfinity;
if (double.IsNaN(y)) return double.PositiveInfinity;
return AbsDiff(x, y);
}
/// <summary>
/// Returns true if two numbers are equal when represented in double precision.
/// </summary>

Просмотреть файл

@ -645,16 +645,27 @@ namespace Microsoft.ML.Probabilistic.Math
/// <summary>
/// Tests if all elements in the vector satisfy the specified condition.
/// </summary>
/// <param name="fun">The condition for the elements to satisfy.</param>
/// <returns>True if all elements satisfy the condition, false otherwise.</returns>
public abstract bool All(Func<double, bool> fun);
/// <summary>
/// Test if all corresponding elements in this and that vector satisfy a condition
/// </summary>
/// <param name="that"></param>
/// <param name="fun"></param>
/// <returns></returns>
public abstract bool All(Converter<double, bool> fun);
public bool All(Vector that, Func<double, double, bool> fun)
{
return !Any(that, (x, y) => !fun(x, y));
}
/// <summary>
/// Tests if any elements in the vector satisfy the specified condition.
/// </summary>
/// <param name="fun"></param>
/// <returns></returns>
public abstract bool Any(Converter<double, bool> fun);
/// <param name="fun">The condition for the elements to satisfy.</param>
/// <returns>True if any elements satisfy the condition, false otherwise.</returns>
public abstract bool Any(Func<double, bool> fun);
/// <summary>
/// Test if any corresponding elements in this and that vector satisfy a condition
@ -664,7 +675,7 @@ namespace Microsoft.ML.Probabilistic.Math
/// <returns></returns>
public virtual bool Any(Vector that, Func<double, double, bool> fun)
{
if (that is DenseVector) return ((DenseVector) that).Any(this, (x, y) => fun(y, x));
if (that is DenseVector denseVector) return denseVector.Any(this, (x, y) => fun(y, x));
throw new NotImplementedException();
}
@ -674,7 +685,7 @@ namespace Microsoft.ML.Probabilistic.Math
/// </summary>
/// <param name="fun">A function to check if the condition is satisfied.</param>
/// <returns>An enumeration over the indices of all elements which satisfy the specified condition.</returns>
public IEnumerable<int> IndexOfAll(Converter<double, bool> fun)
public IEnumerable<int> IndexOfAll(Func<double, bool> fun)
{
return this.FindAll(fun).Select(valueAtIndex => valueAtIndex.Index);
}
@ -685,28 +696,28 @@ namespace Microsoft.ML.Probabilistic.Math
/// </summary>
/// <param name="fun">A function to check if the condition is satisfied.</param>
/// <returns>An enumeration over the indices and values of all elements which satisfy the specified condition.</returns>
public abstract IEnumerable<ValueAtIndex<double>> FindAll(Converter<double, bool> fun);
public abstract IEnumerable<ValueAtIndex<double>> FindAll(Func<double, bool> fun);
/// <summary>
/// Returns the number of elements in the vector which satisfy a given condition.
/// </summary>
/// <param name="fun">The condition for the elements to satisfy.</param>
/// <returns>The number of elements in the vector which satisfy the condition.</returns>
public abstract int CountAll(Converter<double, bool> fun);
public abstract int CountAll(Func<double, bool> fun);
/// <summary>
/// Returns the index of the first element that satisfies satisfy a given condition.
/// Returns the index of the first element that satisfies a given condition.
/// </summary>
/// <param name="fun">The condition for the element to satisfy.</param>
/// <returns>The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, <EFBFBD>1.</returns>
public abstract int FindFirstIndex(Converter<double, bool> fun);
/// <returns>The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, -1.</returns>
public abstract int FindFirstIndex(Func<double, bool> fun);
/// <summary>
/// Returns the index of the last element that satisfiessatisfy a given condition.
/// Returns the index of the last element that satisfies a given condition.
/// </summary>
/// <param name="fun">The condition for the element to satisfy.</param>
/// <returns>The zero-based index of the last occurrence of an element that matches the conditions defined by match, if found; otherwise, <EFBFBD>1.</returns>
public abstract int FindLastIndex(Converter<double, bool> fun);
/// <returns>The zero-based index of the last occurrence of an element that matches the conditions defined by match, if found; otherwise, -1.</returns>
public abstract int FindLastIndex(Func<double, bool> fun);
#endregion
@ -1418,12 +1429,12 @@ namespace Microsoft.ML.Probabilistic.Math
/// <returns>True if the vectors have the same size and element values.</returns>
public static bool operator ==(Vector a, Vector b)
{
if (Object.ReferenceEquals(a, b))
if (ReferenceEquals(a, b))
{
return (true);
return true;
}
if (Object.ReferenceEquals(a, null) || Object.ReferenceEquals(b, null))
return (false);
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
return false;
return a.Equals(b);
}
@ -1436,21 +1447,21 @@ namespace Microsoft.ML.Probabilistic.Math
/// <returns>True if vectors are not equal.</returns>
public static bool operator !=(Vector a, Vector b)
{
return (!(a == b));
return !(a == b);
}
/// <summary>
/// Determines object equality.
/// </summary>
/// <param name="obj">Another (DenseVector) object.</param>
/// <param name="obj">Another vector.</param>
/// <returns>True if equal.</returns>
/// <exclude/>
public override bool Equals(object obj)
{
Vector that = obj as Vector;
if (Object.ReferenceEquals(that, null))
if (ReferenceEquals(that, null))
return false;
if (Object.ReferenceEquals(this, that))
if (ReferenceEquals(this, that))
return true;
if (this.Count != that.Count)
return false;
@ -1657,7 +1668,7 @@ namespace Microsoft.ML.Probabilistic.Math
/// </summary>
/// <param name="that">The second vector.</param>
/// <param name="rel">An offset to avoid division by zero.</param>
/// <returns><c>max(abs(this[i] - that[i])/(abs(this[i]) + rel))</c>.
/// <returns><c>max(abs(this[i] - that[i])/(min(abs(this[i]),abs(that[i])) + rel))</c>.
/// Matching infinities or NaNs do not count.
/// If <c>this</c> and <paramref name="that"/> are not the same size, returns infinity.</returns>
/// <remarks>This routine is typically used instead of <c>Equals</c>, since <c>Equals</c> is susceptible to roundoff errors.

Просмотреть файл

@ -202,7 +202,7 @@ namespace Microsoft.ML.Probabilistic.Distributions
{
if (IsPointMass)
{
return power*that.GetLogProb(Point);
return power * that.GetLogProb(Point);
}
else if (that.IsPointMass)
{
@ -211,8 +211,8 @@ namespace Microsoft.ML.Probabilistic.Distributions
}
else
{
var product = this*(that ^ power);
return product.GetLogNormalizer() - this.GetLogNormalizer() - power*that.GetLogNormalizer();
var product = this * (that ^ power);
return product.GetLogNormalizer() - this.GetLogNormalizer() - power * that.GetLogNormalizer();
}
}
@ -230,7 +230,7 @@ namespace Microsoft.ML.Probabilistic.Distributions
{
// p must not be 0 or 1.
double p = GetProbTrue();
return p*that.GetLogProbTrue() + (1 - p)*that.GetLogProbFalse();
return p * that.GetLogProbTrue() + (1 - p) * that.GetLogProbFalse();
}
}
@ -299,7 +299,7 @@ namespace Microsoft.ML.Probabilistic.Distributions
{
if (IsPointMass) return 0.0;
double p = GetProbTrue();
return p*(1 - p);
return p * (1 - p);
}
#if class
@ -452,7 +452,7 @@ namespace Microsoft.ML.Probabilistic.Distributions
{
if (exponent < 0 && dist.IsPointMass)
throw new DivideByZeroException($"The {nameof(exponent)} is negative and the distribution is a point mass");
LogOdds = dist.LogOdds*exponent;
LogOdds = dist.LogOdds * exponent;
}
}
@ -494,7 +494,7 @@ namespace Microsoft.ML.Probabilistic.Distributions
throw new ArgumentException($"{nameof(weight1)} ({weight1}) + {nameof(weight2)} ({weight2}) < 0");
else if (weight1 == 0) SetTo(dist2);
else if (weight2 == 0) SetTo(dist1);
// if dist1 == dist2 then we must return dist1, with no roundoff error
// if dist1 == dist2 then we must return dist1, with no roundoff error
else if (dist1.LogOdds == dist2.LogOdds) LogOdds = dist1.LogOdds;
else if (double.IsPositiveInfinity(weight1))
{
@ -510,7 +510,7 @@ namespace Microsoft.ML.Probabilistic.Distributions
else if (double.IsPositiveInfinity(weight2)) SetTo(dist2);
else
{
SetProbTrue((weight1*dist1.GetProbTrue() + weight2*dist2.GetProbTrue())/(weight1 + weight2));
SetProbTrue((weight1 * dist1.GetProbTrue() + weight2 * dist2.GetProbTrue()) / (weight1 + weight2));
}
}
@ -545,7 +545,7 @@ namespace Microsoft.ML.Probabilistic.Distributions
public double MaxDiff(object thatd)
{
if (!(thatd is Bernoulli)) return Double.PositiveInfinity;
Bernoulli that = (Bernoulli) thatd;
Bernoulli that = (Bernoulli)thatd;
return MMath.AbsDiff(LogOdds, that.LogOdds);
}
@ -558,7 +558,7 @@ namespace Microsoft.ML.Probabilistic.Distributions
public override bool Equals(object thatd)
{
if (!(thatd is Bernoulli)) return false;
Bernoulli that = (Bernoulli) thatd;
Bernoulli that = (Bernoulli)thatd;
return (LogOdds == that.LogOdds);
}
@ -627,8 +627,8 @@ namespace Microsoft.ML.Probabilistic.Distributions
if (x == y) diff = 0; // in case x and y are Inf
//double min = 0.5 * (sum - diff); // same as Math.Min(x,y)
double min = System.Math.Min(x, y);
double result = min + System.Math.Log((1 + System.Math.Exp(-sum))/(1 + System.Math.Exp(-diff)));
return result*sign;
double result = min + System.Math.Log((1 + System.Math.Exp(-sum)) / (1 + System.Math.Exp(-diff)));
return result * sign;
}
/// <summary>

Просмотреть файл

@ -1458,7 +1458,7 @@ namespace Microsoft.ML.Probabilistic.Distributions
}
/// <summary>
/// Replaces the current distribution with an improper distribution which assigns the probability of 1 to every sequence.
/// Replaces the current distribution with an improper distribution which assigns the probability of 1 to every sequence, or a different value if <see cref="SetLogValueOverride"/> was previously called.
/// Sequence elements are restricted to be non-zero probability elements from a given distribution.
/// </summary>
/// <param name="allowedElements">The distribution representing allowed sequence elements.</param>
@ -1468,7 +1468,7 @@ namespace Microsoft.ML.Probabilistic.Distributions
}
/// <summary>
/// Replaces the current distribution with an improper distribution which assigns the probability of 1 to every sequence.
/// Replaces the current distribution with an improper distribution which assigns the probability of 1 to every sequence, or a different value if <see cref="SetLogValueOverride"/> was previously called.
/// </summary>
public void SetToUniform()
{

Просмотреть файл

@ -12,6 +12,16 @@ namespace Microsoft.ML.Probabilistic.Factors
[Quality(QualityBand.Preview)]
public static class MaxGammaOp
{
public static double LogEvidenceRatio(double max, Gamma a, double b)
{
return MaxAverageConditional(a, b).GetLogProb(max);
}
public static double LogEvidenceRatio(double max, double a, Gamma b)
{
return LogEvidenceRatio(max, b, a);
}
[Skip]
public static double LogEvidenceRatio(TruncatedGamma max)
{
@ -46,10 +56,14 @@ namespace Microsoft.ML.Probabilistic.Factors
[Quality(QualityBand.Preview)]
public static class MaxTruncatedGammaOp
{
[Skip]
public static double LogEvidenceRatio2(TruncatedGamma max)
public static double LogEvidenceRatio(double max, TruncatedGamma a, double b)
{
return 0.0;
return MaxAverageConditional(a, b).GetLogProb(max);
}
public static double LogEvidenceRatio(double max, double a, TruncatedGamma b)
{
return LogEvidenceRatio(max, b, a);
}
public static TruncatedGamma MaxAverageConditional(TruncatedGamma a, double b)

Просмотреть файл

@ -17,15 +17,15 @@ using System.Windows.Forms;
namespace Microsoft.ML.Probabilistic.Compiler.Visualizers
{
internal class DependencyGraphView
internal class DependencyGraphView : IDisposable
{
private Panel panel = new Panel();
private GViewer gviewer = new GViewer();
private IndexedGraph dg;
private IndexedProperty<NodeIndex, Node> nodeOf;
private Func<NodeIndex, string> nodeName;
private Func<EdgeIndex, string> edgeName;
private IEnumerable<EdgeStylePredicate> edgeStyles;
private readonly Panel panel = new Panel();
private readonly GViewer gviewer = new GViewer();
private readonly IndexedGraph dg;
private readonly IndexedProperty<NodeIndex, Node> nodeOf;
private readonly Func<NodeIndex, string> nodeName;
private readonly Func<EdgeIndex, string> edgeName;
private readonly IEnumerable<EdgeStylePredicate> edgeStyles;
internal DependencyGraphView(IndexedGraph dg, IEnumerable<EdgeStylePredicate> edgeStyles = null,
Func<NodeIndex, string> nodeName = null,
@ -168,5 +168,11 @@ namespace Microsoft.ML.Probabilistic.Compiler.Visualizers
{
WindowsVisualizer.FormHelper.RunInForm(panel, title, false);
}
public void Dispose()
{
panel.Dispose();
gviewer.Dispose();
}
}
}

Просмотреть файл

@ -15,9 +15,9 @@ using Microsoft.Msagl.Drawing;
namespace Microsoft.ML.Probabilistic.Compiler.Visualizers
{
internal class ModelView
internal class ModelView : IDisposable
{
private GViewer gviewer = new GViewer();
private readonly GViewer gviewer = new GViewer();
internal ModelBuilder modelBuilder;
@ -57,6 +57,11 @@ namespace Microsoft.ML.Probabilistic.Compiler.Visualizers
Form f = WindowsVisualizer.FormHelper.ShowInForm(gviewer, title, maximise);
Application.Run(f);
}
public void Dispose()
{
gviewer.Dispose();
}
}
internal class MsaglWriter : GraphViews.GraphWriter

Просмотреть файл

@ -10,7 +10,6 @@ using Microsoft.Msagl.GraphViewerGdi;
using Microsoft.Msagl.Drawing;
using Microsoft.ML.Probabilistic.Compiler.Attributes;
using Node = Microsoft.Msagl.Drawing.Node;
using Microsoft.ML.Probabilistic.Compiler;
using Microsoft.ML.Probabilistic.Compiler.Transforms;
using Microsoft.ML.Probabilistic.Compiler.CodeModel;
using Microsoft.ML.Probabilistic.Collections;
@ -20,9 +19,9 @@ namespace Microsoft.ML.Probabilistic.Compiler.Visualizers
/// <summary>
/// A view of a task graph, which is a schedule when the tasks are message computations.
/// </summary>
internal class TaskGraphView
internal class TaskGraphView : IDisposable
{
private GViewer gviewer = new GViewer();
private readonly GViewer gviewer = new GViewer();
protected enum Stage
{
@ -33,7 +32,7 @@ namespace Microsoft.ML.Probabilistic.Compiler.Visualizers
/// <summary>
/// Helps build class declarations
/// </summary>
private static CodeBuilder Builder = CodeBuilder.Instance;
private static readonly CodeBuilder Builder = CodeBuilder.Instance;
internal IList<IStatement> pretasks;
internal IList<IStatement> looptasks;
@ -48,9 +47,9 @@ namespace Microsoft.ML.Probabilistic.Compiler.Visualizers
if (!context.InputAttributes.Has<OperatorMethod>(imd)) continue;
foreach (IStatement ist in imd.Body.Statements)
{
if (ist is IWhileStatement)
if (ist is IWhileStatement iws)
{
looptasks.AddRange(((IWhileStatement) ist).Body.Statements);
looptasks.AddRange(iws.Body.Statements);
continue;
}
if (context.InputAttributes.Has<OperatorStatement>(ist)) pretasks.Add(ist);
@ -150,18 +149,16 @@ namespace Microsoft.ML.Probabilistic.Compiler.Visualizers
//if (di.IsOutput) nd.Attr.Fillcolor = Color.LightBlue;
nd.LabelText = s;
if (stage == Stage.Initialisation) nd.Attr.FillColor = Color.LightGray;
if (ist is IExpressionStatement)
if (ist is IExpressionStatement ies)
{
IExpressionStatement ies = (IExpressionStatement) ist;
IAssignExpression iae = ies.Expression as IAssignExpression;
if ((iae != null) && (iae.Target is IVariableDeclarationExpression)) nd.Attr.LineWidth = 2;
if ((ies.Expression is IAssignExpression iae) && (iae.Target is IVariableDeclarationExpression)) nd.Attr.LineWidth = 2;
}
nd.Attr.Shape = Shape.Box;
nd.Label.FontSize = 9;
return nd;
}
private Dictionary<Stage, Dictionary<IStatement, Node>> stmtNodeMap = new Dictionary<Stage, Dictionary<IStatement, Node>>();
private readonly Dictionary<Stage, Dictionary<IStatement, Node>> stmtNodeMap = new Dictionary<Stage, Dictionary<IStatement, Node>>();
protected Node GetNodeForStatement(IStatement ist, Stage stg)
{
@ -176,44 +173,36 @@ namespace Microsoft.ML.Probabilistic.Compiler.Visualizers
stmtNodeMap[stg][ist] = nd;
}
protected bool ReferenceContains(IList<IStatement> list, object value)
{
foreach (object obj in list) if (object.ReferenceEquals(obj, value)) return true;
return false;
}
protected string StatementLabel(IStatement ist)
{
if (ist is IExpressionStatement)
if (ist is IExpressionStatement ies)
{
IExpressionStatement ies = (IExpressionStatement) ist;
string s;
if (ies.Expression is IAssignExpression)
if (ies.Expression is IAssignExpression iae)
{
s = ExpressionToString(((IAssignExpression) ies.Expression).Target);
s = ExpressionToString(iae.Target);
}
else s = ExpressionToString(ies.Expression);
if (s.StartsWith("this.")) s = s.Substring(5);
//if (s.EndsWith("[0]")) s = s.Substring(0, s.Length - 3);
return s;
}
if (ist is IForStatement)
if (ist is IForStatement ifs)
{
return StatementLabel(((IForStatement) ist).Body.Statements[0]);
return StatementLabel(ifs.Body.Statements[0]);
}
if (ist is IConditionStatement)
if (ist is IConditionStatement ics)
{
return String.Format("if ({0}) {1}", ((IConditionStatement) ist).Condition.ToString(),
StatementLabel(((IConditionStatement) ist).Then));
return String.Format("if ({0}) {1}", ics.Condition.ToString(),
StatementLabel(ics.Then));
}
if (ist is IBlockStatement)
if (ist is IBlockStatement ibs)
{
int blockSize = ((IBlockStatement) ist).Statements.Count;
int blockSize = ibs.Statements.Count;
string s;
if (blockSize > 0)
{
s = StatementLabel(((IBlockStatement) ist).Statements[0]);
s = StatementLabel(ibs.Statements[0]);
}
else
{
@ -239,5 +228,10 @@ namespace Microsoft.ML.Probabilistic.Compiler.Visualizers
{
WindowsVisualizer.FormHelper.RunInForm(gviewer, "Infer.NET Schedule Viewer", false);
}
public void Dispose()
{
gviewer.Dispose();
}
}
}

Просмотреть файл

@ -273,7 +273,7 @@ namespace Microsoft.ML.Probabilistic.Tests
Assert.Equal(1, v.IndexOf(commonValue));
// Test IndexOfAll/FindAll
Converter<double, bool> filter = x => x >= commonValue && x < v[2];
Func<double, bool> filter = x => x >= commonValue && x < v[2];
int[] indexOfAll = v.IndexOfAll(filter).ToArray();
ValueAtIndex<double>[] all = v.FindAll(filter).ToArray();
int allCount = v.CountAll(filter);
@ -1567,109 +1567,40 @@ namespace Microsoft.ML.Probabilistic.Tests
}
}
private void VectorEquality(Vector a)
{
Rand.Restart(12347);
Vector aCopy = Vector.Copy(a);
Vector aPlusNoise = a.Clone();
for (int i = 0; i < a.Count; i++)
aPlusNoise[i] += Rand.Double();
Assert.True(a == aCopy);
Assert.False(a != aCopy);
Assert.Equal(a, aCopy);
Assert.Equal(0.0, a.MaxDiff(aCopy));
Assert.False(a == aPlusNoise);
Assert.True(a != aPlusNoise);
Assert.NotEqual(Vector.Zero(aPlusNoise.Count), aPlusNoise);
double diff = 0.0;
for (int i = 0; i < a.Count; i++)
{
double d = System.Math.Abs(a[i] - aPlusNoise[i]) / (System.Math.Abs(a[i]) + TOLERANCE);
if (d > diff) diff = d;
}
double diff1 = a.MaxDiff(aPlusNoise, TOLERANCE);
Assert.Equal(diff, diff1);
}
[Fact]
public void VectorEqualityTests()
{
double[] a = new double[] { 1.2, 2.3, 3.4, 1.2, 1.2, 2.3 };
double[] a = new double[] { 1.2, 2.3, 3.4, 1.2, 1.2, 2.3, double.PositiveInfinity, double.NegativeInfinity };
double[] aExt = new double[] { 5.6, 1.2, 1.2, 6.7, 7.8, 1.2, 1.2, 6.7 };
Sparsity approxSparsity = Sparsity.ApproximateWithTolerance(0.001);
Vector[] aVector = new Vector[5];
aVector[0] = Vector.FromArray(a);
aVector[1] = Vector.FromArray(a, Sparsity.Sparse);
aVector[2] = Vector.FromArray(a, approxSparsity);
aVector[3] = DenseVector.FromArrayReference(6, aExt, 1);
aVector[4] = Vector.FromArray(a, Sparsity.Piecewise);
for (int i = 0; i < aVector.Length; i++)
VectorEquality(aVector[i]);
}
VectorEquality(Vector.FromArray(a));
VectorEquality(Vector.FromArray(a, Sparsity.Sparse));
VectorEquality(Vector.FromArray(a, approxSparsity));
VectorEquality(Vector.FromArray(a, Sparsity.Piecewise));
VectorEquality(DenseVector.FromArrayReference(6, aExt, 1));
private void VectorInequality(Vector a)
{
double min = a.Min();
double max = a.Max();
Assert.True(a.All(x => x < max + 0.1));
Assert.True(a.Any(x => x > max - 0.1));
void VectorEquality(Vector v)
{
Vector copy = Vector.Copy(v);
Assert.True(v == copy);
Assert.False(v != copy);
Assert.Equal(v, copy);
Assert.Equal(0.0, v.MaxDiff(copy));
int i2 = a.Count / 2;
double delta = 0.25;
Vector noisy = v.Clone();
noisy[0] += delta;
Assert.False(v == noisy);
Assert.True(v != noisy);
Assert.NotEqual(Vector.Zero(noisy.Count), noisy);
double diffExpected = delta / (v[0] + TOLERANCE);
double diff = v.MaxDiff(noisy, TOLERANCE);
Assert.Equal(diffExpected, diff);
Vector b = Vector.Copy(a);
b[i2] = a[i2] + 0.1;
Assert.True(b >= a);
Assert.False(b > a);
Assert.False(b < a);
Assert.False(b <= a);
Assert.True(a <= b);
Assert.False(a < b);
Assert.False(a > b);
Assert.False(a >= b);
for (int i = 0; i < a.Count; i++)
b[i] = a[i] + 0.1;
Assert.True(b >= a);
Assert.True(b > a);
Assert.False(b < a);
Assert.False(b <= a);
Assert.True(a <= b);
Assert.True(a < b);
Assert.False(a > b);
Assert.False(a >= b);
for (int i = 0; i < a.Count; i++)
b[i] = (i % 2) == 0 ? a[i] + 0.1 : a[i] - 0.1;
Assert.False(b >= a);
Assert.False(b > a);
Assert.False(b < a);
Assert.False(b <= a);
Assert.False(a <= b);
Assert.False(a < b);
Assert.False(a > b);
Assert.False(a >= b);
double d = 0.5 * (min + max);
Assert.False(a <= d);
Assert.False(a < d);
Assert.False(a > d);
Assert.False(a >= d);
Assert.True(a <= max);
Assert.True(a < max + 0.1);
Assert.False(a < max);
Assert.False(a > max);
Assert.False(a >= max);
Assert.True(a >= min);
Assert.True(a > min - 0.1);
Assert.False(a > min);
Assert.False(a < min);
Assert.False(a <= min);
v[0] = double.NaN;
Vector withNaN = v.Clone();
Assert.Equal(0.0, v.MaxDiff(withNaN));
}
}
[Fact]
@ -1678,14 +1609,81 @@ namespace Microsoft.ML.Probabilistic.Tests
double[] a = new double[] { 1.2, 2.3, 3.4, 1.2, 1.2, 2.3 };
double[] aExt = new double[] { 5.6, 1.2, 1.2, 6.7, 7.8, 1.2, 1.2, 6.7 };
Sparsity approxSparsity = Sparsity.ApproximateWithTolerance(0.001);
Vector[] aVector = new Vector[5];
aVector[0] = Vector.FromArray(a);
aVector[1] = Vector.FromArray(a, Sparsity.Sparse);
aVector[2] = Vector.FromArray(a, approxSparsity);
aVector[3] = DenseVector.FromArrayReference(6, aExt, 1);
aVector[4] = Vector.FromArray(a, Sparsity.Piecewise);
for (int i = 0; i < aVector.Length; i++)
VectorInequality(aVector[i]);
VectorInequality(Vector.FromArray(a));
VectorInequality(Vector.FromArray(a, Sparsity.Sparse));
VectorInequality(Vector.FromArray(a, approxSparsity));
VectorInequality(Vector.FromArray(a, Sparsity.Piecewise));
VectorInequality(DenseVector.FromArrayReference(6, aExt, 1));
void VectorInequality(Vector v)
{
double min = v.Min();
double max = v.Max();
Assert.True(v.All(x => x < max + 0.1));
Assert.True(v.Any(x => x > max - 0.1));
int i2 = v.Count / 2;
Vector b = Vector.Copy(v);
b[i2] = v[i2] + 0.1;
Assert.True(b >= v);
Assert.False(b > v);
Assert.False(b < v);
Assert.False(b <= v);
Assert.True(v <= b);
Assert.False(v < b);
Assert.False(v > b);
Assert.False(v >= b);
for (int i = 0; i < v.Count; i++)
b[i] = v[i] + 0.1;
Assert.True(b >= v);
Assert.True(b > v);
Assert.False(b < v);
Assert.False(b <= v);
Assert.True(v <= b);
Assert.True(v < b);
Assert.False(v > b);
Assert.False(v >= b);
for (int i = 0; i < v.Count; i++)
b[i] = (i % 2) == 0 ? v[i] + 0.1 : v[i] - 0.1;
Assert.False(b >= v);
Assert.False(b > v);
Assert.False(b < v);
Assert.False(b <= v);
Assert.False(v <= b);
Assert.False(v < b);
Assert.False(v > b);
Assert.False(v >= b);
double d = 0.5 * (min + max);
Assert.False(v <= d);
Assert.False(v < d);
Assert.False(v > d);
Assert.False(v >= d);
Assert.True(v <= max);
Assert.True(v < max + 0.1);
Assert.False(v < max);
Assert.False(v > max);
Assert.False(v >= max);
Assert.True(v >= min);
Assert.True(v > min - 0.1);
Assert.False(v > min);
Assert.False(v < min);
Assert.False(v <= min);
v[0] = double.NegativeInfinity;
v[1] = double.PositiveInfinity;
b.SetTo(v);
Assert.True(b >= v);
Assert.True(b <= v);
Assert.False(b > v);
Assert.False(b < v);
}
}
[Fact]
@ -1702,23 +1700,17 @@ namespace Microsoft.ML.Probabilistic.Tests
{
// rectangular matrix tests
Matrix R = new Matrix(new double[,] { { 1, 2, 3 }, { 4, 5, 6 } });
Console.WriteLine("R:\n{0}", R);
Matrix Rt = R.Transpose();
Console.WriteLine("R':\n{0}", Rt);
Matrix Rtt = new Matrix(R.Rows, R.Cols);
Rtt.SetToTranspose(Rt);
Assert.True(Rtt.Equals(R));
Assert.True(Rtt.GetHashCode() == R.GetHashCode());
Console.WriteLine("");
Matrix RRTrue = new Matrix(new double[,] { { 14, 32 }, { 32, 77 } });
Matrix RR = new Matrix(R.Rows, Rt.Cols);
RR.SetToProduct(R, Rt);
//Rt.SetToProduct(R,Rt); RR.SetTo(Rt);
Console.WriteLine("R*R':\n{0}", RR);
Assert.True(RR.MaxDiff(RRTrue) < TOLERANCE);
Console.WriteLine("");
RR.SetTo(RRTrue);
Assert.Equal(RR, RRTrue);
@ -1732,14 +1724,10 @@ namespace Microsoft.ML.Probabilistic.Tests
// square matrix tests
// A = [2 1 1; 1 2 1; 1 1 2]
PositiveDefiniteMatrix A = new PositiveDefiniteMatrix(new double[,] { { 2, 1, 1 }, { 1, 2, 1 }, { 1, 1, 2 } });
Console.WriteLine("A:\n{0}", A);
Console.WriteLine("");
Assert.True(A.SymmetryError() == 0.0);
double det = A.Determinant();
Console.Write("det(A) = {0}", det);
Assert.True(System.Math.Abs(det - 4) < TOLERANCE);
Console.WriteLine("");
PositiveDefiniteMatrix AinvTrue = new PositiveDefiniteMatrix(new double[,]
{
@ -1749,16 +1737,11 @@ namespace Microsoft.ML.Probabilistic.Tests
});
PositiveDefiniteMatrix Ainv = new PositiveDefiniteMatrix(3, 3);
Ainv.SetToInverse(A);
Console.WriteLine("inv(A):\n{0}", Ainv);
Assert.True(Ainv.MaxDiff(AinvTrue) < TOLERANCE);
Assert.True(Ainv.SymmetryError() == 0.0);
Console.WriteLine("");
Console.WriteLine("sum(b): {0}", b.Sum());
Vector v = Ainv * b;
Console.WriteLine("inv(A)*b:\n{0}", v);
Assert.True(v.MaxDiff(c) < TOLERANCE);
Console.WriteLine("");
v.SetTo(b);
Assert.Equal(v, b);
@ -1766,12 +1749,10 @@ namespace Microsoft.ML.Probabilistic.Tests
(new LuDecomposition(A)).Solve((DenseVector)v);
// should be same as above
Console.WriteLine("Solve(A,b):\n{0}", v);
Assert.True(v.MaxDiff(c) < TOLERANCE);
Vector b2 = Vector.Zero(b.Count);
b2.SetToProduct(A, v);
Assert.True(b.MaxDiff(b2) < TOLERANCE);
Console.WriteLine("");
LowerTriangularMatrix LTrue = new LowerTriangularMatrix(new double[,]
{
@ -1781,10 +1762,7 @@ namespace Microsoft.ML.Probabilistic.Tests
});
LowerTriangularMatrix L = new LowerTriangularMatrix(3, 3);
bool isPosDef = L.SetToCholesky(A);
//Console.WriteLine("IsPosDef(A): {0}", isPosDef);
Assert.True(isPosDef);
//Console.WriteLine("Cholesky(A):\n{0}", L);
Console.WriteLine("Cholesky(A) error = {0}", L.MaxDiff(LTrue));
Assert.True(L.MaxDiff(LTrue) < TOLERANCE);
LowerTriangularMatrix LinvTrue = new LowerTriangularMatrix(new double[,]
@ -1795,11 +1773,9 @@ namespace Microsoft.ML.Probabilistic.Tests
});
LowerTriangularMatrix Linv = new LowerTriangularMatrix(3, 3);
Linv.SetToInverse(L);
Console.WriteLine("inv(L) error = {0}", Linv.MaxDiff(LinvTrue));
Assert.True(Linv.MaxDiff(LinvTrue) < TOLERANCE);
Linv.SetTo(L);
Linv.SetToInverse(Linv);
Console.WriteLine("inv(L) error = {0}", Linv.MaxDiff(LinvTrue));
Assert.True(Linv.MaxDiff(LinvTrue) < TOLERANCE);
// L*L' = A, so L'\L\A = I
@ -1812,14 +1788,11 @@ namespace Microsoft.ML.Probabilistic.Tests
eye.PredivideBy(L);
eye.PredivideByTranspose(L);
Assert.True(eye.MaxDiff(Matrix.Identity(3)) < TOLERANCE);
Console.WriteLine("");
// L*L' = A, so inv(A)*b = inv(L')*inv(L)*b
v.SetTo(b);
v.PredivideBy(L);
Console.WriteLine("v = {0}", v); // should be 2.8284, 1.633, 1.1547
v.PredivideBy(L.Transpose());
Console.WriteLine("v = {0}", v);
Assert.True(v.MaxDiff(c) < TOLERANCE);
v.SetTo(b);
@ -1949,7 +1922,7 @@ namespace Microsoft.ML.Probabilistic.Tests
}
[Fact]
public void VectorTest()
public void VectorSetTo_WithWrongArraySize_ThrowsException()
{
Assert.Throws<ArgumentException>(() =>
{
@ -1957,7 +1930,6 @@ namespace Microsoft.ML.Probabilistic.Tests
Vector x = Vector.Zero(3);
double[] array = new double[] { 1, 2, 3 };
x.SetTo(array);
Console.WriteLine(x);
for (int i = 0; i < array.Length; i++)
{
Assert.Equal(array[i], x[i]);
@ -1990,27 +1962,21 @@ namespace Microsoft.ML.Probabilistic.Tests
{
// rectangular matrix tests
Matrix R = new Matrix(new double[,] { { 1, 2, 3 }, { 4, 5, 6 } });
Console.WriteLine("R:\n{0}", R);
Matrix Rt = R.Transpose();
Console.WriteLine("R':\n{0}", Rt);
Matrix Rtt = new Matrix(R.Rows, R.Cols);
Rtt.SetToTranspose(Rt);
Assert.True(Rtt.Equals(R));
Assert.True(Rtt.GetHashCode() == R.GetHashCode());
Console.WriteLine("");
Matrix RRTrue = new Matrix(new double[,] { { 14, 32 }, { 32, 77 } });
Matrix RR = new Matrix(R.Rows, Rt.Cols);
RR.SetToProduct(R, Rt);
//Rt.SetToProduct(R,Rt); RR.SetTo(Rt);
Console.WriteLine("R*R':\n{0}", RR);
Assert.True(RR.MaxDiff(RRTrue) < TOLERANCE);
RR.SetToOuter(R);
Assert.True(RR.MaxDiff(RRTrue) < TOLERANCE);
RR.SetToOuterTranspose(Rt);
Assert.True(RR.MaxDiff(RRTrue) < TOLERANCE);
Console.WriteLine("");
RR.SetTo(RRTrue);
Assert.Equal(RR, RRTrue);
@ -2024,14 +1990,10 @@ namespace Microsoft.ML.Probabilistic.Tests
// square matrix tests
// A = [2 1 1; 1 2 1; 1 1 2]
PositiveDefiniteMatrix A = new PositiveDefiniteMatrix(new double[,] { { 2, 1, 1 }, { 1, 2, 1 }, { 1, 1, 2 } });
Console.WriteLine("A:\n{0}", A);
Console.WriteLine("");
Assert.True(A.SymmetryError() == 0.0);
double det = A.Determinant();
Console.Write("det(A) = {0}", det);
Assert.True(System.Math.Abs(det - 4) < TOLERANCE);
Console.WriteLine("");
PositiveDefiniteMatrix AinvTrue = new PositiveDefiniteMatrix(new double[,]
{
@ -2046,18 +2008,13 @@ namespace Microsoft.ML.Probabilistic.Tests
Lapack.SymmetricInverseInPlace(t);
Assert.True(Ainv.MaxDiff(t) < TOLERANCE);
#endif
Console.WriteLine("inv(A):\n{0}", Ainv);
Assert.True(Ainv.MaxDiff(AinvTrue) < TOLERANCE);
Assert.True(Ainv.SymmetryError() == 0.0);
Console.WriteLine("");
Vector b = Vector.FromArray(new double[] { 4, 4, 4 });
Vector c = Vector.FromArray(new double[] { 1, 1, 1 });
Console.WriteLine("sum(b): {0}", b.Sum());
Vector v = Ainv * b;
Console.WriteLine("inv(A)*b:\n{0}", v);
Assert.True(v.MaxDiff(c) < TOLERANCE);
Console.WriteLine("");
v.SetTo(b);
Assert.Equal(v, b);
@ -2065,12 +2022,10 @@ namespace Microsoft.ML.Probabilistic.Tests
(new LuDecomposition(A)).Solve(v);
// should be same as above
Console.WriteLine("Solve(A,b):\n{0}", v);
Assert.True(v.MaxDiff(c) < TOLERANCE);
Vector b2 = Vector.Zero(b.Count);
b2.SetToProduct(A, v);
Assert.True(b.MaxDiff(b2) < TOLERANCE);
Console.WriteLine("");
LowerTriangularMatrix LTrue = new LowerTriangularMatrix(new double[,]
{
@ -2080,17 +2035,12 @@ namespace Microsoft.ML.Probabilistic.Tests
});
LowerTriangularMatrix L = new LowerTriangularMatrix(3, 3);
bool isPosDef = L.SetToCholesky(A);
//Console.WriteLine("IsPosDef(A): {0}", isPosDef);
Assert.True(isPosDef);
Console.WriteLine("Cholesky(A):\n{0}", L);
Console.WriteLine("Cholesky(A) error = {0}", L.MaxDiff(LTrue));
Assert.True(L.MaxDiff(LTrue) < TOLERANCE);
PositiveDefiniteMatrix Acopy = (PositiveDefiniteMatrix)A.Clone();
L = Acopy.CholeskyInPlace(out isPosDef);
Assert.True(isPosDef);
Console.WriteLine("Cholesky(A):\n{0}", L);
Console.WriteLine("Cholesky(A) error = {0}", L.MaxDiff(LTrue));
Assert.True(L.MaxDiff(LTrue) < TOLERANCE);
LowerTriangularMatrix LinvTrue = new LowerTriangularMatrix(new double[,]
@ -2101,11 +2051,9 @@ namespace Microsoft.ML.Probabilistic.Tests
});
LowerTriangularMatrix Linv = new LowerTriangularMatrix(3, 3);
Linv.SetToInverse(L);
Console.WriteLine("inv(L) error = {0}", Linv.MaxDiff(LinvTrue));
Assert.True(Linv.MaxDiff(LinvTrue) < TOLERANCE);
Linv.SetTo(L);
Linv.SetToInverse(Linv);
Console.WriteLine("inv(L) error = {0}", Linv.MaxDiff(LinvTrue));
Assert.True(Linv.MaxDiff(LinvTrue) < TOLERANCE);
// L*L' = A, so L'\L\A = I
@ -2118,14 +2066,11 @@ namespace Microsoft.ML.Probabilistic.Tests
eye.PredivideBy(L);
eye.PredivideByTranspose(L);
Assert.True(eye.MaxDiff(Matrix.Identity(3)) < TOLERANCE);
Console.WriteLine("");
// L*L' = A, so inv(A)*b = inv(L')*inv(L)*b
v.SetTo(b);
v.PredivideBy(L);
Console.WriteLine("v = {0}", v); // should be 2.8284, 1.633, 1.1547
v.PredivideBy(L.Transpose());
Console.WriteLine("v = {0}", v);
Assert.True(v.MaxDiff(c) < TOLERANCE);
v.SetTo(b);
@ -2242,14 +2187,14 @@ namespace Microsoft.ML.Probabilistic.Tests
double VError = VExpected.MaxDiff(V);
Matrix USExpected = UExpected * Matrix.FromDiagonal(SExpected);
double USError = USExpected.MaxDiff(US);
Console.WriteLine(StringUtil.JoinColumns("US = ", US.ToString("g17"), " expected ", USExpected.ToString("g17"), " error ", USError));
Console.WriteLine(StringUtil.JoinColumns("U = ", U.ToString("g17"), " expected ", UExpected.ToString("g17"), " error ", UError));
Console.WriteLine(StringUtil.JoinColumns("S = ", S, " expected ", SExpected, " error ", SError));
Console.WriteLine(StringUtil.JoinColumns("V = ", V, " expected ", VExpected, " error ", VError));
//Console.WriteLine(StringUtil.JoinColumns("US = ", US.ToString("g17"), " expected ", USExpected.ToString("g17"), " error ", USError));
//Console.WriteLine(StringUtil.JoinColumns("U = ", U.ToString("g17"), " expected ", UExpected.ToString("g17"), " error ", UError));
//Console.WriteLine(StringUtil.JoinColumns("S = ", S, " expected ", SExpected, " error ", SError));
//Console.WriteLine(StringUtil.JoinColumns("V = ", V, " expected ", VExpected, " error ", VError));
Matrix AExpected = UExpected * Matrix.FromDiagonal(SExpected) * VExpected.Transpose();
Matrix USVActual = U * Matrix.FromDiagonal(S) * V.Transpose();
Matrix AActual = US * V.Transpose();
Console.WriteLine(StringUtil.JoinColumns("A = ", AActual.ToString("g17"), " expected ", AExpected.ToString("g17")));
//Console.WriteLine(StringUtil.JoinColumns("A = ", AActual.ToString("g17"), " expected ", AExpected.ToString("g17")));
Assert.True(UError < 1e-7);
Assert.True(SError < 1e-10);
Assert.True(VError < 1e-10);
@ -2295,9 +2240,9 @@ namespace Microsoft.ML.Probabilistic.Tests
{ 0 /* -0.60148066629825048 */, 0.608938144188165, 0.793217710690245 }
});
Console.WriteLine(StringUtil.JoinColumns("U = ", U, " expected ", UExpected));
Console.WriteLine(StringUtil.JoinColumns("S = ", S, " expected ", SExpected));
Console.WriteLine(StringUtil.JoinColumns("V = ", V, " expected ", VExpected));
//Console.WriteLine(StringUtil.JoinColumns("U = ", U, " expected ", UExpected));
//Console.WriteLine(StringUtil.JoinColumns("S = ", S, " expected ", SExpected));
//Console.WriteLine(StringUtil.JoinColumns("V = ", V, " expected ", VExpected));
Assert.True(UExpected.MaxDiff(U) < 1e-10);
Assert.True(SExpected.MaxDiff(S) < 1e-10);
Assert.True(VExpected.MaxDiff(V) < 1e-10);
@ -2307,7 +2252,6 @@ namespace Microsoft.ML.Probabilistic.Tests
public void MatrixEigenvectorsSymmetricTest()
{
PositiveDefiniteMatrix A = new PositiveDefiniteMatrix(new double[,] { { 2, 1, 1 }, { 1, 2, 1 }, { 1, 1, 2 } });
Console.WriteLine("A:\n{0}", A);
PositiveDefiniteMatrix Aev;
double[] eigenvaluesReal = new double[A.Rows];
double[] eigenvaluesImag = new double[A.Rows];
@ -2325,22 +2269,21 @@ namespace Microsoft.ML.Probabilistic.Tests
Matrix eigenvectors = new Matrix(A.Rows, A.Cols);
Aev = (PositiveDefiniteMatrix)A.Clone();
eigenvectors.SetToEigenvectorsOfSymmetric(Aev);
Console.WriteLine("eigenvectors as cols:\n{0}", eigenvectors);
Console.WriteLine("eigenvalues:\n{0}", Aev);
Matrix product = eigenvectors * Aev * eigenvectors.Transpose();
Assert.True(product.MaxDiff(A) < TOLERANCE);
//A = new PositiveDefiniteMatrix(new double[,] { { 1, 5, 7 }, { 3, 0, 6 }, { 4, 3, 1 } });
Aev = (PositiveDefiniteMatrix)A.Clone();
Aev.EigenvaluesInPlace(eigenvaluesReal, eigenvaluesImag);
Console.WriteLine("eigenvalues Real: {0}", StringUtil.CollectionToString(eigenvaluesReal, " "));
Console.WriteLine("eigenvalues Imag: {0}", StringUtil.CollectionToString(eigenvaluesImag, " "));
//Console.WriteLine("eigenvalues Real: {0}", StringUtil.CollectionToString(eigenvaluesReal, " "));
//Console.WriteLine("eigenvalues Imag: {0}", StringUtil.CollectionToString(eigenvaluesImag, " "));
// TODO: assertion
A.SetTo(new double[,] { { double.PositiveInfinity, 0, 0 }, { 0, 2, 1 }, { 0, 1, 2 } });
Aev = (PositiveDefiniteMatrix)A.Clone();
eigenvectors.SetToEigenvectorsOfSymmetric(Aev);
Console.WriteLine("eigenvectors as cols:\n{0}", eigenvectors);
Console.WriteLine("eigenvalues:\n{0}", Aev);
//Console.WriteLine("eigenvectors as cols:\n{0}", eigenvectors);
//Console.WriteLine("eigenvalues:\n{0}", Aev);
}
// Test a case where balancing is required
@ -2390,9 +2333,6 @@ namespace Microsoft.ML.Probabilistic.Tests
double[] eigenvaluesImag = new double[A.Rows];
var Aev = (Matrix)A.Clone();
Aev.EigenvaluesInPlace(eigenvaluesReal, eigenvaluesImag);
Console.WriteLine(Aev);
Console.WriteLine("eigenvalues Real: {0}", StringUtil.CollectionToString(eigenvaluesReal, " "));
Console.WriteLine("eigenvalues Imag: {0}", StringUtil.CollectionToString(eigenvaluesImag, " "));
for (int i = 0; i < A.Rows; i++)
{
bool found = false;
@ -2430,10 +2370,11 @@ namespace Microsoft.ML.Probabilistic.Tests
{
Matrix A = new Matrix(new double[,] { { 1, 2 }, { 3, 4 } });
Matrix C = A.Kronecker(A);
Console.WriteLine(C);
//Console.WriteLine(C);
// TODO: assertion
Matrix K = Matrix.Commutation(4, 3);
Console.WriteLine(K);
//Console.WriteLine(K);
}
}
}

Просмотреть файл

@ -3,37 +3,24 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using Microsoft.ML.Probabilistic.Math;
using Xunit;
using Assert = Xunit.Assert;
namespace Microsoft.ML.Probabilistic.Tests
{
public class RandomTests
{
public const double TOLERANCE = 4.0e-2;
public const int nsamples = 100000;
/*
[STAThread]
public static void Main(string[] args)
{
RandUniform();
RandNormal();
RandGamma();
RandNormal2();
RandNormalP();
RandWishart();
Console.ReadKey();
}
*/
[Fact]
public void RandUniform()
public void RandSample_HasCorrectDistribution()
{
double error = 0.0;
// Uniform integers
Vector hist = Vector.Zero(4);
for (int i = 0; i < nsamples; i++)
@ -42,31 +29,48 @@ namespace Microsoft.ML.Probabilistic.Tests
hist[x]++;
}
hist = hist*(1.0/nsamples);
Console.WriteLine("[0.25,0.25,0.25,0.25]: {0}", hist);
hist *= (1.0 / nsamples);
Vector unif = Vector.Constant(4, 0.25);
error = hist.MaxDiff(unif);
double error = hist.MaxDiff(unif);
if (error > TOLERANCE)
{
Assert.True(false, String.Format("Uniform: error={0}", error));
Assert.True(false, $"Uniform: error={error}");
}
hist.SetAllElementsTo(0);
double[] init1 = new double[] {0.1, 0.2, 0.3, 0.4};
double[] init1 = new double[] { 0.1, 0.2, 0.3, 0.4 };
Vector p = Vector.FromArray(init1);
for (int i = 0; i < nsamples; i++)
{
int x = Rand.Sample(p);
hist[x]++;
}
hist = hist*(1.0/nsamples);
Console.WriteLine("\n[0.1,0.2,0.3,0.4]: {0}", hist);
hist *= (1.0 / nsamples);
error = hist.MaxDiff(p);
if (error > TOLERANCE)
{
Assert.True(false, String.Format("Sample([0.1,0.2,0.3,0.4]) error={0}", error));
Assert.True(false, $"Sample([0.1,0.2,0.3,0.4]) error={error}");
}
}
[Fact]
public void RandSample_NeverDrawsZero()
{
const int nsamples = 1_000_000;
double[] init1 = new double[] { 0, double.Epsilon };
Vector p = Vector.FromArray(init1);
for (int i = 0; i < nsamples; i++)
{
int x = Rand.Sample(p);
Assert.Equal(1, x);
x = Rand.Sample((IList<double>)p, p[1]);
Assert.Equal(1, x);
}
}
[Fact]
public void RandRestart()
{
Rand.Restart(7);
double first = Rand.Double();
Rand.Restart(7);
@ -82,22 +86,22 @@ namespace Microsoft.ML.Probabilistic.Tests
{
double x = Rand.Normal();
sum += x;
sum2 += x*x;
sum2 += x * x;
}
double m = sum/nsamples;
double v = sum2/nsamples - m*m;
double m = sum / nsamples;
double v = sum2 / nsamples - m * m;
// the sample mean has stddev = 1/sqrt(n)
double dError = System.Math.Abs(m);
if (dError > 4/ System.Math.Sqrt(nsamples))
if (dError > 4 / System.Math.Sqrt(nsamples))
{
Assert.True(false, string.Format("m: error = {0}", dError));
Assert.True(false, $"m: error = {dError}");
}
// the sample variance is Gamma(n/2,n/2) whose stddev = sqrt(2/n)
dError = System.Math.Abs(v - 1.0);
if (dError > 4* System.Math.Sqrt(2.0/ nsamples))
if (dError > 4 * System.Math.Sqrt(2.0 / nsamples))
{
Assert.True(false, string.Format("v: error = {0}", dError));
Assert.True(false, $"v: error = {dError}");
}
}
@ -116,8 +120,7 @@ namespace Microsoft.ML.Probabilistic.Tests
private void RandNormalGreaterThan(double lowerBound)
{
double meanExpected, varianceExpected;
new Microsoft.ML.Probabilistic.Distributions.TruncatedGaussian(0, 1, lowerBound, double.PositiveInfinity).GetMeanAndVariance(out meanExpected, out varianceExpected);
new Probabilistic.Distributions.TruncatedGaussian(0, 1, lowerBound, double.PositiveInfinity).GetMeanAndVariance(out double meanExpected, out double varianceExpected);
MeanVarianceAccumulator mva = new MeanVarianceAccumulator();
for (int i = 0; i < nsamples; i++)
@ -127,20 +130,18 @@ namespace Microsoft.ML.Probabilistic.Tests
}
double m = mva.Mean;
double v = mva.Variance;
Console.WriteLine("mean = {0} should be {1}", m, meanExpected);
Console.WriteLine("variance = {0} should be {1}", v, varianceExpected);
// the sample mean has stddev = 1/sqrt(n)
double dError = System.Math.Abs(m - meanExpected);
if (dError > 4/ System.Math.Sqrt(nsamples))
if (dError > 4 / System.Math.Sqrt(nsamples))
{
Assert.True(false, string.Format("m: error = {0}", dError));
Assert.True(false, $"m: error = {dError}");
}
// the sample variance is Gamma(n/2,n/2) whose stddev = sqrt(2/n)
dError = System.Math.Abs(v - varianceExpected);
if (dError > 4* System.Math.Sqrt(2.0/ nsamples))
if (dError > 4 * System.Math.Sqrt(2.0 / nsamples))
{
Assert.True(false, string.Format("v: error = {0}", dError));
Assert.True(false, $"v: error = {dError}");
}
}
@ -156,8 +157,7 @@ namespace Microsoft.ML.Probabilistic.Tests
private void RandNormalBetween(double lowerBound, double upperBound)
{
double meanExpected, varianceExpected;
new Microsoft.ML.Probabilistic.Distributions.TruncatedGaussian(0, 1, lowerBound, upperBound).GetMeanAndVariance(out meanExpected, out varianceExpected);
new Probabilistic.Distributions.TruncatedGaussian(0, 1, lowerBound, upperBound).GetMeanAndVariance(out double meanExpected, out double varianceExpected);
MeanVarianceAccumulator mva = new MeanVarianceAccumulator();
for (int i = 0; i < nsamples; i++)
@ -167,20 +167,18 @@ namespace Microsoft.ML.Probabilistic.Tests
}
double m = mva.Mean;
double v = mva.Variance;
Console.WriteLine("mean = {0} should be {1}", m, meanExpected);
Console.WriteLine("variance = {0} should be {1}", v, varianceExpected);
// the sample mean has stddev = 1/sqrt(n)
double dError = System.Math.Abs(m - meanExpected);
if (dError > 4/ System.Math.Sqrt(nsamples))
if (dError > 4 / System.Math.Sqrt(nsamples))
{
Assert.True(false, string.Format("m: error = {0}", dError));
Assert.True(false, $"m: error = {dError}");
}
// the sample variance is Gamma(n/2,n/2) whose stddev = sqrt(2/n)
dError = System.Math.Abs(v - varianceExpected);
if (dError > 4* System.Math.Sqrt(2.0/ nsamples))
if (dError > 4 * System.Math.Sqrt(2.0 / nsamples))
{
Assert.True(false, string.Format("v: error = {0}", dError));
Assert.True(false, $"v: error = {dError}");
}
}
@ -199,33 +197,32 @@ namespace Microsoft.ML.Probabilistic.Tests
{
double x = Rand.Gamma(a);
sum += x;
sum2 += x*x;
sum2 += x * x;
}
double m = sum/nsamples;
double v = sum2/nsamples - m*m;
Console.WriteLine("Gamma({2}) mean: {0} variance: {1}", m, v, a);
double m = sum / nsamples;
double v = sum2 / nsamples - m * m;
// sample mean has stddev = sqrt(a/n)
double dError = System.Math.Abs(m - a);
if (dError > 4* System.Math.Sqrt(a / nsamples))
if (dError > 4 * System.Math.Sqrt(a / nsamples))
{
Assert.True(false, string.Format("m: error = {0}", dError));
Assert.True(false, $"m: error = {dError}");
}
dError = System.Math.Abs(v - a);
if (dError > TOLERANCE)
{
Assert.True(false, String.Format("v: error = {0}", dError));
Assert.True(false, $"v: error = {dError}");
}
}
[Fact]
public void RandNormal2()
{
double[] m_init = {1, 2, 3};
double[] m_init = { 1, 2, 3 };
Vector mt = Vector.FromArray(m_init);
double[,] v_init = {{2, 1, 1}, {1, 2, 1}, {1, 1, 2}};
double[,] v_init = { { 2, 1, 1 }, { 1, 2, 1 }, { 1, 1, 2 } };
PositiveDefiniteMatrix vt = new PositiveDefiniteMatrix(v_init);
int d = mt.Count;
@ -238,35 +235,28 @@ namespace Microsoft.ML.Probabilistic.Tests
}
Vector m = mva.Mean;
Matrix v = mva.Variance;
Console.WriteLine("");
Console.WriteLine("Multivariate Normal");
Console.WriteLine("-------------------");
Console.WriteLine("m = {0}", m);
double dError = m.MaxDiff(mt);
if (dError > TOLERANCE)
{
Assert.True(false, String.Format("m: error = {0}", dError));
Assert.True(false, $"m: error = {dError}");
}
Console.WriteLine("v = \n{0}", v);
dError = v.MaxDiff(vt);
if (dError > TOLERANCE)
{
Assert.True(false, String.Format("v: error = {0}", dError));
Assert.True(false, $"v: error = {dError}");
}
}
[Fact]
public void RandNormalP()
{
double[] m_init = {1, 2, 3};
double[] m_init = { 1, 2, 3 };
Vector mt = Vector.FromArray(m_init);
double[,] v_init = {{2, 1, 1}, {1, 2, 1}, {1, 1, 2}};
double[,] v_init = { { 2, 1, 1 }, { 1, 2, 1 }, { 1, 1, 2 } };
PositiveDefiniteMatrix vt = new PositiveDefiniteMatrix(v_init);
PositiveDefiniteMatrix pt = ((PositiveDefiniteMatrix) vt.Clone()).SetToInverse(vt);
PositiveDefiniteMatrix pt = ((PositiveDefiniteMatrix)vt.Clone()).SetToInverse(vt);
int d = mt.Count;
Vector x = Vector.Zero(d);
@ -279,22 +269,16 @@ namespace Microsoft.ML.Probabilistic.Tests
Vector m = mva.Mean;
PositiveDefiniteMatrix v = mva.Variance;
Console.WriteLine("");
Console.WriteLine("Multivariate NormalP");
Console.WriteLine("--------------------");
Console.WriteLine("m = {0}", m);
double dError = m.MaxDiff(mt);
if (dError > TOLERANCE)
{
Assert.True(false, String.Format("m: error = {0}", dError));
Assert.True(false, $"m: error = {dError}");
}
Console.WriteLine("v = \n{0}", v);
dError = v.MaxDiff(vt);
if (dError > TOLERANCE)
{
Assert.True(false, String.Format("v: error = {0}", dError));
Assert.True(false, $"v: error = {dError}");
}
}
@ -316,27 +300,22 @@ namespace Microsoft.ML.Probabilistic.Tests
{
Rand.Wishart(a, L);
X.SetToProduct(L, L.Transpose());
m = m + X;
s = s + X.LogDeterminant();
m += X;
s += X.LogDeterminant();
}
double sTrue = 0;
for (int i = 0; i < d; i++) sTrue += MMath.Digamma(a - i*0.5);
m.Scale(1.0/nsamples);
s = s/nsamples;
for (int i = 0; i < d; i++) sTrue += MMath.Digamma(a - i * 0.5);
m.Scale(1.0 / nsamples);
s /= nsamples;
Console.WriteLine("");
Console.WriteLine("Multivariate Gamma");
Console.WriteLine("-------------------");
Console.WriteLine("m = \n{0}", m);
double dError = m.MaxDiff(mTrue);
if (dError > TOLERANCE)
{
Assert.True(false, String.Format("Wishart({0}) mean: (should be {0}*I), error = {1}", a, dError));
Assert.True(false, $"Wishart({a}) mean: (should be {a}*I), error = {dError}");
}
if (System.Math.Abs(s - sTrue) > TOLERANCE)
{
Assert.True(false, string.Format("E[logdet]: {0} (should be {1})", s, sTrue));
Assert.True(false, $"E[logdet]: {s} (should be {sTrue})");
}
}
@ -354,27 +333,27 @@ namespace Microsoft.ML.Probabilistic.Tests
private void RandBinomial(double p, int n)
{
double meanExpected = p*n;
double varianceExpected = p*(1 - p)*n;
double meanExpected = p * n;
double varianceExpected = p * (1 - p) * n;
double sum = 0;
double sum2 = 0;
for (int i = 0; i < nsamples; i++)
{
double x = Rand.Binomial(n, p);
sum += x;
sum2 += x*x;
sum2 += x * x;
}
double mean = sum/nsamples;
double variance = sum2/nsamples - mean*mean;
double mean = sum / nsamples;
double variance = sum2 / nsamples - mean * mean;
double error = MMath.AbsDiff(meanExpected, mean, 1e-6);
if (error > System.Math.Sqrt(varianceExpected) *5)
if (error > System.Math.Sqrt(varianceExpected) * 5)
{
Assert.True(false, string.Format("Binomial({0},{1}) mean = {2} should be {3}, error = {4}", p, n, mean, meanExpected, error));
Assert.True(false, $"Binomial({p},{n}) mean = {mean} should be {meanExpected}, error = {error}");
}
error = MMath.AbsDiff(varianceExpected, variance, 1e-6);
if (error > System.Math.Sqrt(varianceExpected) *5)
if (error > System.Math.Sqrt(varianceExpected) * 5)
{
Assert.True(false, string.Format("Binomial({0},{1}) variance = {2} should be {3}, error = {4}", p, n, variance, varianceExpected, error));
Assert.True(false, $"Binomial({p},{n}) variance = {variance} should be {varianceExpected}, error = {error}");
}
}
@ -394,8 +373,8 @@ namespace Microsoft.ML.Probabilistic.Tests
private void RandMultinomial(DenseVector p, int n)
{
Vector meanExpected = p*n;
Vector varianceExpected = p*(1 - p)*n;
Vector meanExpected = p * n;
Vector varianceExpected = p * (1 - p) * n;
DenseVector sum = DenseVector.Zero(p.Count);
DenseVector sum2 = DenseVector.Zero(p.Count);
for (int i = 0; i < nsamples; i++)
@ -404,18 +383,18 @@ namespace Microsoft.ML.Probabilistic.Tests
for (int dim = 0; dim < x.Length; dim++)
{
sum[dim] += x[dim];
sum2[dim] += x[dim]*x[dim];
sum2[dim] += x[dim] * x[dim];
}
}
Vector mean = sum*(1.0/nsamples);
Vector variance = sum2*(1.0/nsamples) - mean*mean;
Vector mean = sum * (1.0 / nsamples);
Vector variance = sum2 * (1.0 / nsamples) - mean * mean;
for (int dim = 0; dim < p.Count; dim++)
{
double error = MMath.AbsDiff(meanExpected[dim], mean[dim], 1e-6);
Console.WriteLine("Multinomial({0},{1}) mean[{5}] = {2} should be {3}, error = {4}", p, n, mean[dim], meanExpected[dim], error, dim);
////Console.WriteLine("Multinomial({0},{1}) mean[{5}] = {2} should be {3}, error = {4}", p, n, mean[dim], meanExpected[dim], error, dim);
Assert.True(error < TOLERANCE);
error = MMath.AbsDiff(varianceExpected[dim], variance[dim], 1e-6);
Console.WriteLine("Multinomial({0},{1}) variance[{5}] = {2} should be {3}, error = {4}", p, n, variance[dim], varianceExpected[dim], error, dim);
////Console.WriteLine("Multinomial({0},{1}) variance[{5}] = {2} should be {3}, error = {4}", p, n, variance[dim], varianceExpected[dim], error, dim);
Assert.True(error < TOLERANCE);
}
}
@ -425,7 +404,7 @@ namespace Microsoft.ML.Probabilistic.Tests
{
Assert.Throws<ArgumentException>(() =>
{
Rand.Int(9, 9);
Rand.Int(9, 9);
});
}