using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
namespace SharpGLTF.Transforms
{
[Category("Core.Transforms")]
public class SparseWeight8Tests
{
[TestCase(0)]
[TestCase(1)]
[TestCase(0,0.0001f)]
[TestCase(2, -2, 2, -2)]
[TestCase(0.2f, 0.15f, 0.25f, 0.10f, 0.30f)]
[TestCase(0, 0, 1, 0, 2, 0, 3, 4, 5, 0, 6, 0, 7, 0, 6, 0, 9, 0, 11)]
[TestCase(9, -9, 8, -8, 7, -7, 6, -6, 5, -5, 4, -4, 3, -3, 2, -2, 1, -1)]
[TestCase(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)]
[TestCase(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)]
public void TestSparseCreation(params float[] array1)
{
var array2 = CreateSparseCompatibleArray(array1);
var array3 = array1
.Select((val, idx) => (idx, val))
.Where(item => item.val != 0)
.Reverse()
.ToArray();
// creation mode 1
var sparse = SparseWeight8.Create(array1);
Assert.That(sparse.WeightSum, Is.EqualTo(array2.Sum()));
Assert.That(sparse.Expand(array2.Length), Is.EqualTo(array2));
// creation mode 2
var indexedSparse = SparseWeight8.Create(array3);
Assert.That(indexedSparse.WeightSum, Is.EqualTo(array2.Sum()).Within(0.000001f));
Assert.That(indexedSparse.Expand(array2.Length), Is.EqualTo(array2));
Assert.That(SparseWeight8.AreEqual(sparse, indexedSparse));
// sort by weights
var sByWeights = SparseWeight8.OrderedByWeight(sparse);
Assert.That(sByWeights.WeightSum, Is.EqualTo(array2.Sum()));
Assert.That(sByWeights.Expand(array2.Length), Is.EqualTo(array2));
CheckWeightOrdered(sByWeights);
// sort by indices
var sByIndices = SparseWeight8.OrderedByIndex(sByWeights);
CheckIndexOrdered(sByIndices);
Assert.That(sByIndices.WeightSum, Is.EqualTo(array2.Sum()));
Assert.That(sByIndices.Expand(array2.Length), Is.EqualTo(array2));
// equality
Assert.That(SparseWeight8.AreEqual(sByIndices, sByWeights), Is.True);
Assert.That(sByWeights.GetHashCode(), Is.EqualTo(sByIndices.GetHashCode()));
// sum
var sum = SparseWeight8.Add(sByIndices, sByWeights);
Assert.That(sum.WeightSum, Is.EqualTo(array2.Sum() * 2));
// complement normalization
if (!array2.Any(item => item<0))
{
Assert.That(sparse.GetNormalizedWithComplement(int.MaxValue).WeightSum, Is.GreaterThanOrEqualTo(1));
}
}
[Test]
public void TestSparseCreation()
{
var sparse = SparseWeight8.Create
(
(9, 9),
(8, 2),
(5, 1), // we set these weights separately
(5, 1), // to check that 5 will pass 8
(5, 1), // in the sorted set.
(7, 1)
);
Assert.That(sparse[5], Is.EqualTo(3));
Assert.That(sparse[7], Is.EqualTo(1));
Assert.That(sparse[8], Is.EqualTo(2));
Assert.That(sparse[9], Is.EqualTo(9));
}
[Test]
public void TestCreateSparseFromVectors()
{
Assert.That
(
SparseWeight8.Create(new System.Numerics.Vector4(0, 1, 2, 3), new System.Numerics.Vector4(1, 1, 1, 1)).Expand(4),
Is.EqualTo(SparseWeight8.Create(1, 1, 1, 1).Expand(4))
);
Assert.That
(
SparseWeight8.Create(new System.Numerics.Vector4(0, 1, 2, 3), new System.Numerics.Vector4(1, 2, 3, 4)).Expand(4),
Is.EqualTo(SparseWeight8.Create(1, 2, 3, 4).Expand(4))
);
Assert.That
(
SparseWeight8.Create(new System.Numerics.Vector4(0, 1, 2, 3), new System.Numerics.Vector4(4, 3, 2, 1)).Expand(4),
Is.EqualTo(SparseWeight8.Create(4, 3, 2, 1).Expand(4))
);
Assert.That
(
SparseWeight8.Create(new System.Numerics.Vector4(0, 2, 2, 3), new System.Numerics.Vector4(4, 3, 2, 1)).Expand(4),
Is.EqualTo(SparseWeight8.Create(4, 0, 5, 1).Expand(4))
);
Assert.That
(
SparseWeight8.Create(new System.Numerics.Vector4(1, 1, 1, 1), new System.Numerics.Vector4(1, 1, 1, 1)).Expand(4),
Is.EqualTo(SparseWeight8.Create(0, 4, 0, 0).Expand(4))
);
}
///
/// Creates a new array with only the 8 most relevant weights.
///
///
///
static float[] CreateSparseCompatibleArray(params float[] array)
{
const int MAXWEIGHTS = 8;
if (array == null) return null;
var threshold =array
.Select(item => Math.Abs(item))
.OrderByDescending(item => item)
.Take(MAXWEIGHTS)
.Min();
var array2 = new float[array.Length];
var c = 0;
for(int i=0; i < array2.Length; ++i)
{
var v = array[i];
if (v == 0) continue;
if (Math.Abs(v) >= threshold)
{
array2[i] = v;
++c;
if (c >= MAXWEIGHTS) return array2;
}
}
return array2;
}
static void CheckWeightOrdered(SparseWeight8 sparse)
{
Assert.Multiple(() =>
{
Assert.That(Math.Abs(sparse.Weight0), Is.GreaterThanOrEqualTo(Math.Abs(sparse.Weight1)));
Assert.That(Math.Abs(sparse.Weight1), Is.GreaterThanOrEqualTo(Math.Abs(sparse.Weight2)));
Assert.That(Math.Abs(sparse.Weight2), Is.GreaterThanOrEqualTo(Math.Abs(sparse.Weight3)));
Assert.That(Math.Abs(sparse.Weight3), Is.GreaterThanOrEqualTo(Math.Abs(sparse.Weight4)));
Assert.That(Math.Abs(sparse.Weight4), Is.GreaterThanOrEqualTo(Math.Abs(sparse.Weight5)));
Assert.That(Math.Abs(sparse.Weight5), Is.GreaterThanOrEqualTo(Math.Abs(sparse.Weight6)));
Assert.That(Math.Abs(sparse.Weight6), Is.GreaterThanOrEqualTo(Math.Abs(sparse.Weight7)));
});
}
static void CheckIndexOrdered(SparseWeight8 sparse)
{
var pairs = sparse.GetIndexedWeights();
bool zeroFound = false;
long lastIndex = long.MinValue;
foreach(var (index,weight) in pairs)
{
if (weight == 0) zeroFound = true;
if (zeroFound)
{
Assert.That(index, Is.EqualTo(0));
Assert.That(weight, Is.EqualTo(0));
continue;
}
Assert.That(index, Is.GreaterThan(lastIndex));
lastIndex = index;
}
}
[Test]
public void TestSparseNormalization()
{
var sparse1 = SparseWeight8
.Create(0, 0, 0, 0, 0, 0.1f, 0.7f, 0, 0, 0, 0.1f)
.GetNormalizedWithComplement(int.MaxValue);
Assert.That(sparse1[5], Is.EqualTo(0.1f));
Assert.That(sparse1[6], Is.EqualTo(0.7f));
Assert.That(sparse1[10], Is.EqualTo(0.1f));
Assert.That(sparse1[int.MaxValue], Is.EqualTo(0.1f).Within(0.0000001f));
Assert.That(sparse1.WeightSum, Is.EqualTo(1));
}
[Test]
public void TestSparseEquality()
{
Assert.That(SparseWeight8.AreEqual(SparseWeight8.Create(0, 1), SparseWeight8.Create(0, 1)), Is.True);
Assert.That(SparseWeight8.AreEqual(SparseWeight8.Create(0, 1), SparseWeight8.Create(0, 1, 0.25f)), Is.False);
Assert.That(SparseWeight8.AreEqual(SparseWeight8.Create(0, 1), SparseWeight8.Create(1, 0)), Is.False);
// check if two "half weights" are equal to one "full weight"
//Assert.IsTrue(SparseWeight8.AreWeightsEqual(SparseWeight8.Create((3, 5), (3, 5)), SparseWeight8.Create((3, 10))));
}
[Test]
public void TestSparseWeightsLinearInterpolation1()
{
var x = SparseWeight8.Create(0,0,1,2); Assert.That(x.Expand(4), Is.EqualTo(new[] { 0f, 0f, 1f, 2f }));
var y = SparseWeight8.Create(1,2,0,0); Assert.That(y.Expand(4), Is.EqualTo(new[] { 1f, 2f, 0f, 0f }));
var z = SparseWeight8.InterpolateLinear(x, y, 0.5f);
Assert.That(z[0], Is.EqualTo(0.5f));
Assert.That(z[1], Is.EqualTo(1));
Assert.That(z[2], Is.EqualTo(0.5f));
Assert.That(z[3], Is.EqualTo(1));
}
[Test]
public void TestSparseWeightsLinearInterpolation2()
{
var ax = new float[] { 0, 0, 0, 0, 0, 0.1f, 0.7f, 0, 0, 0, 0.1f };
var ay = new float[] { 0, 0, 0.2f, 0, 0.1f, 0, 0, 0, 0, 0, 0, 0, 0.2f };
var cc = Math.Min(ax.Length, ay.Length);
var x = SparseWeight8.Create(ax); Assert.That(x.Expand(ax.Length), Is.EqualTo(ax));
var y = SparseWeight8.Create(ay); Assert.That(y.Expand(ay.Length), Is.EqualTo(ay));
var z = SparseWeight8.InterpolateLinear(x, y, 0.5f);
for (int i=0; i < cc; ++i)
{
var w = (ax[i] + ay[i]) / 2;
Assert.That(z[i], Is.EqualTo(w));
}
}
[Test]
public void TestSparseWeightsCubicInterpolation()
{
var a = SparseWeight8.Create(0, 0, 0.2f, 0, 0, 0, 1);
var b = SparseWeight8.Create(1, 1, 0.4f, 0, 0, 1, 0);
var t = SparseWeight8.Subtract(b, a);
Assert.That(t[0], Is.EqualTo(1));
Assert.That(t[1], Is.EqualTo(1));
Assert.That(t[2], Is.EqualTo(0.2f));
Assert.That(t[3], Is.EqualTo(0));
Assert.That(t[4], Is.EqualTo(0));
Assert.That(t[5], Is.EqualTo(1));
Assert.That(t[6], Is.EqualTo(-1));
var lr = SparseWeight8.InterpolateLinear(a, b, 0.4f);
var cr = SparseWeight8.InterpolateCubic(a, t, b, t, 0.4f);
Assert.That(cr[0], Is.EqualTo(lr[0]).Within(0.000001f));
Assert.That(cr[1], Is.EqualTo(lr[1]).Within(0.000001f));
Assert.That(cr[2], Is.EqualTo(lr[2]).Within(0.000001f));
Assert.That(cr[3], Is.EqualTo(lr[3]).Within(0.000001f));
Assert.That(cr[4], Is.EqualTo(lr[4]).Within(0.000001f));
Assert.That(cr[5], Is.EqualTo(lr[5]).Within(0.000001f));
Assert.That(cr[6], Is.EqualTo(lr[6]).Within(0.000001f));
Assert.That(cr[7], Is.EqualTo(lr[7]).Within(0.000001f));
}
[Test]
public void TestSparseWeightReduction()
{
var a = SparseWeight8.Create(5, 3, 2, 4, 0, 4, 2, 6, 3, 6, 1);
var b = a.GetTrimmed(4);
Assert.That(b.GetNonZeroWeights().Count(), Is.EqualTo(4));
Assert.That(b[0], Is.EqualTo(a[0]));
Assert.That(b[3], Is.EqualTo(a[3]));
Assert.That(b[7], Is.EqualTo(a[7]));
Assert.That(b[9], Is.EqualTo(a[9]));
Assert.That(b.Weight4, Is.EqualTo(0));
Assert.That(b.Weight5, Is.EqualTo(0));
Assert.That(b.Weight6, Is.EqualTo(0));
Assert.That(b.Weight7, Is.EqualTo(0));
}
}
}