Skip to content

Commit

Permalink
Merge pull request #6 from shapelets/feature/findBestNOccurences
Browse files Browse the repository at this point in the history
  • Loading branch information
jrecuerda authored Jun 11, 2019
2 parents e10d4a8 + 493e3c7 commit fc63f13
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 2 deletions.
45 changes: 45 additions & 0 deletions src/Interop/DLLMatrix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,50 @@ public static extern void stomp([In] ref IntPtr tssa, [In] ref IntPtr tssb, ref
[DllImport(DLLLibrary.KhivaPath, CallingConvention = CallingConvention.Cdecl)]
public static extern void stomp_self_join([In] ref IntPtr tss, ref long m, [Out] out IntPtr p,
[Out] out IntPtr i);

/// <summary>
/// Mueen's Algorithm for Similarity Search.
///
/// The result has the following structure:
/// - 1st dimension corresponds to the index of the subsequence in the time series.
/// - 2nd dimension corresponds to the number of queries.
/// - 3rd dimension corresponds to the number of time series.
///
/// For example, the distance in the position (1, 2, 3) correspond to the distance of the third query to the fourth time
/// series for the second subsequence in the time series.
///
/// [1] Yan Zhu, Zachary Zimmerman, Nader Shakibay Senobari, Chin-Chia Michael Yeh, Gareth Funning, Abdullah Mueen,
/// Philip Brisk and Eamonn Keogh (2016). Matrix Profile II: Exploiting a Novel Algorithm and GPUs to break the one
/// Hundred Million Barrier for Time Series Motifs and Joins. IEEE ICDM 2016.
/// </summary>
/// <param name="query">Array whose first dimension is the length of the query time series and the second dimension
/// is the number of queries.</param>
/// <param name="tss">Array whose first dimension is the length of the time series and the second dimension is the
/// number of time series.</param>
/// <param name="distances">Resulting distances.</param>
[DllImport(DLLLibrary.KhivaPath, CallingConvention = CallingConvention.Cdecl)]
public static extern void mass([In] ref IntPtr query, [In] ref IntPtr tss, [Out] out IntPtr distances);

/// <summary>
/// Calculates the N best matches of several queries in several time series.
/// The result has the following structure:
/// - 1st dimension corresponds to the nth best match.
/// - 2nd dimension corresponds to the number of queries.
/// - 3rd dimension corresponds to the number of time series.
///
/// For example, the distance in the position (1, 2, 3) corresponds to the second best distance of the third query in the
/// fourth time series. The index in the position (1, 2, 3) is the is the index of the subsequence which leads to the
/// second best distance of the third query in the fourth time series.
/// </summary>
/// <param name="query">Array whose first dimension is the length of the query time series and the second dimension
/// is the number of queries.</param>
/// <param name="tss">Array whose first dimension is the length of the time series and the second dimension is the
/// number of time series.</param>
/// <param name="n">Number of matches to return.</param>
/// <param name="distances">Resulting distances.</param>
/// <param name="indexes">Resulting indexes.</param>
[DllImport(DLLLibrary.KhivaPath, CallingConvention = CallingConvention.Cdecl)]
public static extern void find_best_n_occurrences([In] ref IntPtr query, [In] ref IntPtr tss, ref long n,
[Out] out IntPtr distances, [Out] out IntPtr indexes);
}
}
58 changes: 58 additions & 0 deletions src/Matrix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,63 @@ public static Tuple<KhivaArray, KhivaArray> StompSelfJoin(KhivaArray tss, long m
KhivaArray.Create(i));
return tuple;
}

/// <summary>
/// Mueen's Algorithm for Similarity Search.
///
/// The result has the following structure:
/// - 1st dimension corresponds to the index of the subsequence in the time series.
/// - 2nd dimension corresponds to the number of queries.
/// - 3rd dimension corresponds to the number of time series.
///
/// For example, the distance in the position (1, 2, 3) correspond to the distance of the third query to the fourth time
/// series for the second subsequence in the time series.
///
/// [1] Yan Zhu, Zachary Zimmerman, Nader Shakibay Senobari, Chin-Chia Michael Yeh, Gareth Funning, Abdullah Mueen,
/// Philip Brisk and Eamonn Keogh (2016). Matrix Profile II: Exploiting a Novel Algorithm and GPUs to break the one
/// Hundred Million Barrier for Time Series Motifs and Joins. IEEE ICDM 2016.
/// </summary>
/// <param name="query">Array whose first dimension is the length of the query time series and the second dimension
/// is the number of queries.</param>
/// <param name="tss">Array whose first dimension is the length of the time series and the second dimension is the
/// number of time series.</param>
/// <returns>Resulting distances.</returns>
public static KhivaArray Mass(KhivaArray query, KhivaArray tss)
{
var q = query.Reference;
var t = tss.Reference;
DLLMatrix.mass(ref q, ref t, out var distances);
query.Reference = q;
tss.Reference = t;
return KhivaArray.Create(distances);
}

/// <summary>
/// Calculates the N best matches of several queries in several time series.
/// The result has the following structure:
/// - 1st dimension corresponds to the nth best match.
/// - 2nd dimension corresponds to the number of queries.
/// - 3rd dimension corresponds to the number of time series.
///
/// For example, the distance in the position (1, 2, 3) corresponds to the second best distance of the third query in the
/// fourth time series. The index in the position (1, 2, 3) is the is the index of the subsequence which leads to the
/// second best distance of the third query in the fourth time series.
/// </summary>
/// <param name="query">Array whose first dimension is the length of the query time series and the second dimension
/// is the number of queries.</param>
/// <param name="tss">Array whose first dimension is the length of the time series and the second dimension is the
/// number of time series.</param>
/// <param name="n">Number of matches to return.</param>
/// <returns>Tuple with the resulting distances and indexes.</returns>
public static Tuple<KhivaArray, KhivaArray> FindBestNOccurrences(KhivaArray query, KhivaArray tss, long n)
{
var q = query.Reference;
var t = tss.Reference;
DLLMatrix.find_best_n_occurrences(ref q, ref t, ref n, out var distances, out var indexes);
query.Reference = q;
tss.Reference = t;
return Tuple.Create(KhivaArray.Create(distances),
KhivaArray.Create(indexes));
}
}
}
92 changes: 90 additions & 2 deletions test/MatrixTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,94 @@ public void TestFindBestNMotifsConsecutive()
}
}
}
}
}

[Test]
public void TestMass()
{
float[] q = {4.0F, 3.0F, 8.0F};
float[] tss = {10.0F, 10.0F, 10.0F, 11.0F, 12.0F, 11.0F, 10.0F, 10.0F, 11.0F, 12.0F, 11.0F, 14.0F, 10.0F, 10.0F};
using (KhivaArray qArr = KhivaArray.Create(q), tssArr = KhivaArray.Create(tss))
{
var distancesArr = Matrix.Mass(qArr, tssArr);
using (distancesArr)
{
float[] expectedDistances = {1.732051F, 0.328954F, 1.210135F, 3.150851F, 3.245858F, 2.822044F,
0.328954F, 1.210135F, 3.150851F, 0.248097F, 3.30187F, 2.82205F};

var distances = distancesArr.GetData3D<float>();

for (var index = 0; index < 12; index++)
{
Assert.AreEqual(expectedDistances[index], distances[0, 0, index], 1e-4);
}
}
}
}

[Test]
public void TestMassMultiple()
{
float[,] q = { { 10, 10, 11, 11 }, { 10, 11, 10, 10 } };
float[,] tss = { { 10, 10, 10, 11, 12, 11, 10 }, { 10, 11, 12, 11, 14, 10, 10 } };
using (KhivaArray qArr = KhivaArray.Create(q), tssArr = KhivaArray.Create(tss))
{
var distancesArr = Matrix.Mass(qArr, tssArr);
using (distancesArr)
{
Assert.AreEqual(4, distancesArr.Dims[0]);
Assert.AreEqual(2, distancesArr.Dims[1]);
Assert.AreEqual(2, distancesArr.Dims[2]);
Assert.AreEqual(1, distancesArr.Dims[3]);

var distances = distancesArr.GetData3D<float>();

Assert.AreEqual(2.57832384, distances[1, 0, 2], 1e-4);
Assert.AreEqual(0.50202721, distances[1, 1, 3], 1e-4);
}
}
}

[Test]
public void TestFindBestNOccurrences()
{
float[] q = {10, 11, 12};
float[,] tss = { {10, 10, 11, 11, 12, 11, 10, 10, 11, 12, 11, 10, 10, 11},
{10, 10, 11, 11, 12, 11, 10, 10, 11, 12, 11, 10, 10, 11} };
using (KhivaArray qArr = KhivaArray.Create(q), tssArr = KhivaArray.Create(tss))
{
var (distancesArr, indexesArr) = Matrix.FindBestNOccurrences(qArr, tssArr, 1);
using (distancesArr)
using (indexesArr)
{
var distances = distancesArr.GetData3D<float>();
var indexes = indexesArr.GetData3D<uint>();

Assert.AreEqual(0.00, distances[0, 0, 0], 1e-2);
Assert.AreEqual(7, indexes[0, 0, 0]);
}
}
}

[Test]
public void TestFindBestNOccurrencesMultiple()
{
float[,] q = { { 11, 11, 10, 11 }, { 10, 11, 11, 12 } };
float[,] tss = { {10, 10, 11, 11, 10, 11, 10, 10, 11, 11, 10, 11, 10, 10},
{11, 10, 10, 11, 10, 11, 11, 10, 11, 11, 14, 10, 11, 10} };
using (KhivaArray qArr = KhivaArray.Create(q), tssArr = KhivaArray.Create(tss))
{
var (distancesArr, indexesArr) = Matrix.FindBestNOccurrences(qArr, tssArr, 4);
using (distancesArr)
using (indexesArr)
{
var distances = distancesArr.GetData3D<float>();
var indexes = indexesArr.GetData3D<uint>();

Assert.AreEqual(1.83880329, distances[1, 0, 2], 1e-2);
Assert.AreEqual(2, indexes[0, 1, 3]);
}
}
}
}
}
}

0 comments on commit fc63f13

Please sign in to comment.