Sodila, da ich nun ein
Ergebnis vorzuweisen habe, ist jetzt Brainstorming gefragt. Der Fingerprint eines Liedes sieht wie folgt aus:
Code:
[Serializable]
public class SCMS
{
public Vector mean = null;
public CovarianceMatrix cov = null;
public CovarianceMatrix icov = null;
}
Dabei werden noch folgende Klassen genutzt:
Code:
[Serializable]
public class CovarianceMatrix
{
public float[] d;
public int dim;
}
public class Vector : Matrix
{
/// <summary>
/// Constructor for this Class.
/// </summary>
/// <param name="rows"></param>
public Vector(int rows) : base(rows, 1)
{
}
}
[Serializable]
public class Matrix
{
#region Properties
public float[,] d; //2-dimensional array with the values for the matrix
public int columns; //count of columns
public int rows; //count of rows
#endregion
}
Wie ich die Daten speichern kann, ist klar. Dank .NET kann man Klassen super serialisieren. Aber die Berechnung der Abstände muss ich
imho immernoch in C# machen. Oder? Im Programm mache ich das über eine Kullback - Leibler - Divergenz.
Code:
/** Utility class storing a cache and Configuration variables for the Scms
* distance computation.
*/
public class ScmsConfiguration
{
private int dim;
private int covlen;
private float[] mdiff;
private float[] aicov;
public ScmsConfiguration (int dimension)
{
dim = dimension;
covlen = (dim*dim + dim)/2;
mdiff = new float[dim];
aicov = new float[covlen];
}
public int Dimension {
get { return dim; }
}
public int CovarianceLength {
get { return covlen; }
}
public float [] AddInverseCovariance {
get { return aicov; }
}
public float[] MeanDiff {
get { return mdiff; }
}
}
/** Function to compute the spectral distance between two song models.
* This is a fast implementation of the symmetrized Kullback Leibler
* Divergence.
*/
public static float Distance(ref SCMS s1, ref SCMS s2, ScmsConfiguration c)
{
float val = 0;
unsafe
{
int i;
int k;
int idx = 0;
int dim = c.Dimension;
int covlen = (dim * (dim + 1)) / 2;
float tmp1;
fixed (float* s1cov = s1.cov.d, s2icov = s2.icov.d,
s1icov = s1.icov.d, s2cov = s2.cov.d,
s1mean = s1.mean.d, s2mean = s2.mean.d,
mdiff = c.MeanDiff, aicov = c.AddInverseCovariance)
{
for (i = 0; i < covlen; i++)
{
val += s1cov[i] * s2icov[i] + s2cov[i] * s1icov[i];
aicov[i] = s1icov[i] + s2icov[i];
}
for (i = 0; i < dim; i++)
{
mdiff[i] = s1mean[i] - s2mean[i];
}
for (i = 0; i < dim; i++)
{
idx = i - dim;
tmp1 = 0;
for (k = 0; k <= i; k++)
{
idx += dim - k;
tmp1 += aicov[idx] * mdiff[k];
}
for (k = i + 1; k < dim; k++)
{
idx++;
tmp1 += aicov[idx] * mdiff[k];
}
val += tmp1 * mdiff[i];
}
}
}
// FIXME: fix the negative return values
//val = Math.Max(0.0f, (val/2 - s1.cov.dim));
val = val / 2 - s1.cov.dim;
return val;
}
Als Ergebnis erhalte ich dabei einen Float-Wert.
Der Code stammt aus dem Mirage-Plugin für Banshee und steht unter
GPL, nicht, dass sich da einer wundern tut.
Ideen sind jederzeit willkommen.