///------------------------------------------------------------------------------------------------- // file: Validate.cs // // summary: Implements the validate class ///------------------------------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Linq; namespace BenchmarkFramework { ///------------------------------------------------------------------------------------------------- /// Validation utils ///------------------------------------------------------------------------------------------------- public class Validate { public static void Check( IEnumerable[] ss, IComparer comparer = null, bool sort = true, bool verbose = false, IComparer sortcomparer = null ) { if(ss.Length == 0) return; if(comparer == null) { comparer = Comparer.Default; if(comparer == null) { throw new ArgumentNullException("Can't not be null."); } } if(sortcomparer == null) sortcomparer = comparer; T[][] aa = new T[ss.Length][]; for(int i = 0; i < aa.Length; i++) { aa[i] = ss[i].ToArray(); if(sort) Array.Sort(aa[i], sortcomparer); } int len = aa[0].Length; for(int i = 1; i < aa.Length; i++) { if(aa[i].Length != len) { throw new Exception("Wrong number of elements."); } } for(int i = 0; i < len; i++) { T elem = aa[0][i]; for(int j = 1; j < aa.Length; j++) { if(verbose) { //TestOutput.WriteLine("Comparing {0} to {1}", elem.ToString(), aa[j][i].ToString()); } if(comparer.Compare(elem, aa[j][i]) != 0) { throw new Exception("Elements failed to match: " + elem + " != " + aa[j][i]); } } } } //public static void //GroupCheck( // IEnumerable>[] ss, // IComparer kComparer = null, // IComparer vComparer = null // ) { // if(ss.Length == 0) return; // if(kComparer == null) { // kComparer = Comparer.Default; // if(kComparer == null) { // throw new ArgumentNullException("Can't not be null."); // } // } // if(vComparer == null) { // vComparer = Comparer.Default; // if(vComparer == null) { // throw new ArgumentNullException("Can't not be null."); // } // } // IGrouping[][] aa = new IGrouping[ss.Length][]; // for(int i = 0; i < aa.Length; i++) { // aa[i] = ss[i].ToArray(); // K[] keys = aa[i].Select(x => x.Key).ToArray(); // Array.Sort(keys, aa[i], kComparer); // } // int len = aa[0].Length; // for(int i = 1; i < aa.Length; i++) { // if(aa[i].Length != len) { // throw new Exception("Wrong number of elements."); // } // } // for(int i = 0; i < len; i++) { // IEnumerable elem = aa[0][i]; // for(int j = 1; j < aa.Length; j++) { // Check(new IEnumerable[] { elem, aa[j][i] }, vComparer); // } // } //} } /* ///------------------------------------------------------------------------------------------------- /// Tolerant float comparer. Floating point differences between /// GPU and CPU cause the default comparer to fail sometimes even when /// the result is correct. Use this comparer to introduce some tolerance /// for this /// /// /// Crossbac, 2/19/2013. ///------------------------------------------------------------------------------------------------- public class TolerantDoubleComparer : IComparer { Double EPSILON; public TolerantDoubleComparer(Double _epsilon = 0.000001f) { EPSILON = _epsilon; } public int Compare(Double a, Double b) { Double delta = a - b; if(Math.Abs(delta) <= EPSILON) return 0; return delta < 0.0f ? -1 : 1; } } ///------------------------------------------------------------------------------------------------- /// Tolerant float comparer. Floating point differences between /// GPU and CPU cause the default comparer to fail sometimes even when /// the result is correct. Use this comparer to introduce some tolerance /// for this /// /// /// Crossbac, 2/19/2013. ///------------------------------------------------------------------------------------------------- public class TolerantFloatComparer : IComparer { float EPSILON; public TolerantFloatComparer(float _epsilon = 0.000001f) { EPSILON = _epsilon; } public int Compare(float a, float b) { float delta = a - b; if(Math.Abs(delta) <= EPSILON) return 0; return delta < 0.0f ? -1 : 1; } } ///------------------------------------------------------------------------------------------------- /// Tolerant float comparer. Floating point differences between /// GPU and CPU cause the default comparer to fail sometimes even when /// the result is correct. Use this comparer to introduce some tolerance /// for this /// /// /// Crossbac, 2/19/2013. ///------------------------------------------------------------------------------------------------- public class TolerantVectorComparer : IComparer { float EPSILON; public TolerantVectorComparer(float _epsilon = 0.0001f) { EPSILON = _epsilon; } public int Compare(Vector a, Vector b) { for(int i = 0; i < a.m_elems.Length; i++) { float delta = a.m_elems[i] - b.m_elems[i]; if(Math.Abs(delta) > EPSILON) return delta < 0.0f ? -1 : 1; } return 0; } } ///------------------------------------------------------------------------------------------------- /// Interface for epsilon comparable single. /// /// Crossbac, 1/16/2014. /// /// Generic type parameter. ///------------------------------------------------------------------------------------------------- public interface IEpsilonComparableSingle { int EpsilonCompare(T a, T b, float epsilon); } ///------------------------------------------------------------------------------------------------- /// Interface for epsilon comparable double. /// /// Crossbac, 1/16/2014. /// /// Generic type parameter. ///------------------------------------------------------------------------------------------------- public interface IEpsilonComparableDouble { int EpsilonCompare(T a, T b, double epsilon); } ///------------------------------------------------------------------------------------------------- /// Tolerant float comparer. Floating point differences between /// GPU and CPU cause the default comparer to fail sometimes even when /// the result is correct. Use this comparer to introduce some tolerance /// for this /// /// /// Crossbac, 2/19/2013. ///------------------------------------------------------------------------------------------------- public class EpsilonComparer : IComparer where T : IEpsilonComparableSingle { float EPSILON; public EpsilonComparer(float _epsilon = 0.0001f) { EPSILON = _epsilon; } public int Compare(T a, T b) { return a.EpsilonCompare(a, b, EPSILON); } } ///------------------------------------------------------------------------------------------------- /// Tolerant float comparer for images. Floating point differences between /// GPU and CPU cause the default comparer to fail sometimes even when /// the result is correct. Use this comparer to introduce some tolerance /// for this /// /// /// Crossbac, 2/19/2013. ///------------------------------------------------------------------------------------------------- public class TolerantImageComparer : IComparer { float EPSILON; public TolerantImageComparer(float _epsilon = 0.0001f) { EPSILON = _epsilon; } public int Compare(Image a, Image b) { for(int i = 0; i < a.m_elems.Length; i++) { float delta = a.m_elems[i] - b.m_elems[i]; if(Math.Abs(delta) > EPSILON) return delta < 0.0f ? -1 : 1; } return 0; } } /// /// Compare two instances of Pair. /// Implement for concrete type as Pair cannot straighforwardly implement IComparable. /// /// /// jcurrey, 3/11/2013. public class PairIntIntComparer : IComparer> { public int Compare(Pair a, Pair b) { int keyComparison = a.Key.CompareTo(b.Key); if(keyComparison == 0) { return a.Value.CompareTo(b.Value); } else { return keyComparison; } } } */ }