public static void VerifyExplanation(string q, int doc, float score, bool deep, Explanation expl)
{
float value = expl.Value;
Assert.AreEqual(score, value, ExplainToleranceDelta(score, value), q + ": score(doc=" + doc + ")=" + score + " != explanationScore=" + value + " Explanation: " + expl);
if (!deep)
{
return;
}
Explanation[] detail = expl.Details;
// TODO: can we improve this entire method? its really geared to work only with TF/IDF
if (expl.Description.EndsWith("computed from:"))
{
return; // something more complicated.
}
if (detail != null)
{
if (detail.Length == 1)
{
// simple containment, unless its a freq of: (which lets a query explain how the freq is calculated),
// just verify contained expl has same score
if (!expl.Description.EndsWith("with freq of:"))
{
VerifyExplanation(q, doc, score, deep, detail[0]);
}
}
else
{
// explanation must either:
// - end with one of: "product of:", "sum of:", "max of:", or
// - have "max plus <x> times others" (where <x> is float).
float x = 0;
string descr = expl.Description.ToLower(CultureInfo.InvariantCulture);
bool productOf = descr.EndsWith("product of:");
bool sumOf = descr.EndsWith("sum of:");
bool maxOf = descr.EndsWith("max of:");
bool maxTimesOthers = false;
if (!(productOf || sumOf || maxOf))
{
// maybe 'max plus x times others'
int k1 = descr.IndexOf("max plus ");
if (k1 >= 0)
{
k1 += "max plus ".Length;
int k2 = descr.IndexOf(" ", k1);
try
{
x = Convert.ToSingle(descr.Substring(k1, k2 - k1).Trim());
if (descr.Substring(k2).Trim().Equals("times others of:"))
{
maxTimesOthers = true;
}
}
catch (FormatException e)
{
}
}
}
// TODO: this is a TERRIBLE assertion!!!!
Assert.IsTrue(productOf || sumOf || maxOf || maxTimesOthers, q + ": multi valued explanation description=\"" + descr + "\" must be 'max of plus x times others' or end with 'product of'" + " or 'sum of:' or 'max of:' - " + expl);
float sum = 0;
float product = 1;
float max = 0;
for (int i = 0; i < detail.Length; i++)
{
float dval = detail[i].Value;
VerifyExplanation(q, doc, dval, deep, detail[i]);
product *= dval;
sum += dval;
max = Math.Max(max, dval);
}
float combined = 0;
if (productOf)
{
combined = product;
}
else if (sumOf)
{
combined = sum;
}
else if (maxOf)
{
combined = max;
}
else if (maxTimesOthers)
{
combined = max + x * (sum - max);
}
else
{
Assert.IsTrue(false, "should never get here!");
}
Assert.AreEqual(combined, value, ExplainToleranceDelta(combined, value), q + ": actual subDetails combined==" + combined + " != value=" + value + " Explanation: " + expl);
}
}
}