Mercurial > hg > svcore
changeset 1392:667e369cfeab
LogRange tests
author | Chris Cannam |
---|---|
date | Tue, 28 Feb 2017 11:21:49 +0000 |
parents | 2c0e04062a99 |
children | 04abe8f73b22 |
files | base/LogRange.cpp base/LogRange.h base/test/TestLogRange.h base/test/files.pri base/test/svcore-base-test.cpp data/fileio/test/svcore-data-fileio-test.cpp data/model/EditableDenseThreeDimensionalModel.cpp data/model/test/svcore-data-model-test.cpp |
diffstat | 8 files changed, 357 insertions(+), 17 deletions(-) [+] |
line wrap: on
line diff
--- a/base/LogRange.cpp Mon Feb 27 16:52:47 2017 +0000 +++ b/base/LogRange.cpp Tue Feb 28 11:21:49 2017 +0000 @@ -96,7 +96,7 @@ } bool -LogRange::useLogScale(std::vector<double> values) +LogRange::shouldUseLogScale(std::vector<double> values) { // Principle: Partition the data into two sets around the median; // calculate the standard deviation of each set; if the two SDs
--- a/base/LogRange.h Mon Feb 27 16:52:47 2017 +0000 +++ b/base/LogRange.h Tue Feb 28 11:21:49 2017 +0000 @@ -23,14 +23,6 @@ { public: /** - * Map a linear range onto a logarithmic range. min and max are - * passed as the extents of the linear range and returned as the - * extents of the logarithmic range. thresh is the minimum value - * for the log range, to be used if the linear range spans zero. - */ - static void mapRange(double &min, double &max, double thresh = -10); - - /** * Map a value onto a logarithmic range. This just means taking * the base-10 log of the absolute value, or using the threshold * value if the absolute value is zero. @@ -44,11 +36,19 @@ static double unmap(double value); /** + * Map a linear range onto a logarithmic range. min and max are + * passed as the extents of the linear range and returned as the + * extents of the logarithmic range. thresh is the minimum value + * for the log range, to be used if the linear range spans zero. + */ + static void mapRange(double &min, double &max, double thresh = -10); + + /** * Estimate whether a set of values would be more properly shown * using a logarithmic than a linear scale. This is only ever * going to be a rough guess. */ - static bool useLogScale(std::vector<double> values); + static bool shouldUseLogScale(std::vector<double> values); };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/test/TestLogRange.h Tue Feb 28 11:21:49 2017 +0000 @@ -0,0 +1,333 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef TEST_LOG_RANGE_H +#define TEST_LOG_RANGE_H + +#include "../LogRange.h" + +#include <QObject> +#include <QtTest> + +#include <iostream> +#include <cmath> + +using namespace std; + +class TestLogRange : public QObject +{ + Q_OBJECT + +private slots: + + void mapPositiveAboveDefaultThreshold() + { + QCOMPARE(LogRange::map(10.0), 1.0); + QCOMPARE(LogRange::map(100.0), 2.0); + QCOMPARE(LogRange::map(0.1), -1.0); + QCOMPARE(LogRange::map(1.0), 0.0); + QCOMPARE(LogRange::map(0.0000001), -7.0); + QCOMPARE(LogRange::map(20.0), log10(20.0)); + } + + void mapPositiveAboveSetThreshold() + { + QCOMPARE(LogRange::map(10.0, -10.0), 1.0); + QCOMPARE(LogRange::map(100.0, 1.0), 2.0); + QCOMPARE(LogRange::map(0.1, -5.0), -1.0); + QCOMPARE(LogRange::map(1.0, -0.01), 0.0); + QCOMPARE(LogRange::map(0.0000001, -20.0), -7.0); + QCOMPARE(LogRange::map(20.0, 0.0), log10(20.0)); + } + + void mapZeroDefaultThreshold() + { + QCOMPARE(LogRange::map(0.0), -10.0); + } + + void mapZeroSetThreshold() + { + QCOMPARE(LogRange::map(0.0, 12.0), 12.0); + QCOMPARE(LogRange::map(0.0, -12.0), -12.0); + QCOMPARE(LogRange::map(0.0, 0.0), 0.0); + } + + void mapPositiveBelowDefaultThreshold() + { + // The threshold is used only for zero values, not for very + // small ones -- it's arguably a stand-in or replacement value + // rather than a threshold. So this should behave the same as + // for values above the threshold. + QCOMPARE(LogRange::map(1e-10), -10.0); + QCOMPARE(LogRange::map(1e-20), -20.0); + QCOMPARE(LogRange::map(1e-100), -100.0); + } + + void mapPositiveBelowSetThreshold() + { + // As above + QCOMPARE(LogRange::map(10.0, 4.0), 1.0); + QCOMPARE(LogRange::map(1e-10, 4.0), -10.0); + QCOMPARE(LogRange::map(1e-20, -15.0), -20.0); + QCOMPARE(LogRange::map(1e-100, -100.0), -100.0); + } + + void mapNegative() + { + // Should always return map of absolute value. These are + // picked from vaarious of the above tests. + + QCOMPARE(LogRange::map(-10.0), 1.0); + QCOMPARE(LogRange::map(-100.0), 2.0); + QCOMPARE(LogRange::map(-0.1), -1.0); + QCOMPARE(LogRange::map(-1.0), 0.0); + QCOMPARE(LogRange::map(-0.0000001), -7.0); + QCOMPARE(LogRange::map(-20.0), log10(20.0)); + QCOMPARE(LogRange::map(-10.0, 4.0), 1.0); + QCOMPARE(LogRange::map(-1e-10, 4.0), -10.0); + QCOMPARE(LogRange::map(-1e-20, -15.0), -20.0); + QCOMPARE(LogRange::map(-1e-100, -100.0), -100.0); + QCOMPARE(LogRange::map(-0.0, 12.0), 12.0); + QCOMPARE(LogRange::map(-0.0, -12.0), -12.0); + QCOMPARE(LogRange::map(-0.0, 0.0), 0.0); + } + + void unmap() + { + // Simply pow(10, x) + + QCOMPARE(LogRange::unmap(0.0), 1.0); + QCOMPARE(LogRange::unmap(1.0), 10.0); + QCOMPARE(LogRange::unmap(-1.0), 0.1); + QCOMPARE(LogRange::unmap(100.0), 1e+100); + QCOMPARE(LogRange::unmap(-100.0), 1e-100); + } + + void mapRangeAllPositiveDefaultThreshold() + { + double min, max; + + min = 1.0; max = 10.0; + LogRange::mapRange(min, max); + QCOMPARE(min, 0.0); QCOMPARE(max, 1.0); + + min = 10.0; max = 1.0; + LogRange::mapRange(min, max); + QCOMPARE(min, 0.0); QCOMPARE(max, 1.0); + + // if equal, the function uses an arbitrary 1.0 range before mapping + min = 10.0; max = 10.0; + LogRange::mapRange(min, max); + QCOMPARE(min, 1.0); QCOMPARE(max, log10(11.0)); + } + + void mapRangeAllPositiveSetThreshold() + { + double min, max; + + min = 1.0; max = 10.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, 0.0); QCOMPARE(max, 1.0); + + min = 10.0; max = 1.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, 0.0); QCOMPARE(max, 1.0); + + // if equal, the function uses an arbitrary 1.0 range before mapping + min = 10.0; max = 10.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, 1.0); QCOMPARE(max, log10(11.0)); + } + + void mapRangeAllNegativeDefaultThreshold() + { + double min, max; + + min = -1.0; max = -10.0; + LogRange::mapRange(min, max); + QCOMPARE(min, 0.0); QCOMPARE(max, 1.0); + + min = -10.0; max = -1.0; + LogRange::mapRange(min, max); + QCOMPARE(min, 0.0); QCOMPARE(max, 1.0); + + // if equal, the function uses an arbitrary 1.0 range before mapping + min = -10.0; max = -10.0; + LogRange::mapRange(min, max); + QCOMPARE(min, log10(9.0)); QCOMPARE(max, 1.0); + } + + void mapRangeAllNegativeSetThreshold() + { + double min, max; + + min = -1.0; max = -10.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, 0.0); QCOMPARE(max, 1.0); + + min = -10.0; max = -1.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, 0.0); QCOMPARE(max, 1.0); + + // if equal, the function uses an arbitrary 1.0 range before mapping + min = -10.0; max = -10.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, log10(9.0)); QCOMPARE(max, 1.0); + } + + void mapRangeAllNonNegativeDefaultThreshold() + { + double min, max; + + min = 0.0; max = 10.0; + LogRange::mapRange(min, max); + QCOMPARE(min, -10.0); QCOMPARE(max, 1.0); + + min = 10.0; max = 0.0; + LogRange::mapRange(min, max); + QCOMPARE(min, -10.0); QCOMPARE(max, 1.0); + + // if equal, the function uses an arbitrary 1.0 range before mapping + min = 0.0; max = 0.0; + LogRange::mapRange(min, max); + QCOMPARE(min, -10.0); QCOMPARE(max, 0.0); + } + + void mapRangeAllNonNegativeSetThreshold() + { + double min, max; + + min = 0.0; max = 10.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -4.0); QCOMPARE(max, 1.0); + + min = 10.0; max = 0.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -4.0); QCOMPARE(max, 1.0); + + // if equal, the function uses an arbitrary 1.0 range before mapping + min = 0.0; max = 0.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -4.0); QCOMPARE(max, 0.0); + } + + void mapRangeAllNonPositiveDefaultThreshold() + { + double min, max; + + min = 0.0; max = -10.0; + LogRange::mapRange(min, max); + QCOMPARE(min, -10.0); QCOMPARE(max, 1.0); + + min = -10.0; max = 0.0; + LogRange::mapRange(min, max); + QCOMPARE(min, -10.0); QCOMPARE(max, 1.0); + } + + void mapRangeAllNonPositiveSetThreshold() + { + double min, max; + + min = 0.0; max = -10.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -4.0); QCOMPARE(max, 1.0); + + min = -10.0; max = 0.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -4.0); QCOMPARE(max, 1.0); + } + + void mapRangeSpanningZeroDefaultThreshold() + { + double min, max; + + min = -1.0; max = 10.0; + LogRange::mapRange(min, max); + QCOMPARE(min, -10.0); QCOMPARE(max, 1.0); + + min = -100.0; max = 1.0; + LogRange::mapRange(min, max); + QCOMPARE(min, -10.0); QCOMPARE(max, 2.0); + + min = -10.0; max = 1e-200; + LogRange::mapRange(min, max); + QCOMPARE(min, -10.0); QCOMPARE(max, 1.0); + + min = 1e-200; max = -10.0; + LogRange::mapRange(min, max); + QCOMPARE(min, -10.0); QCOMPARE(max, 1.0); + + min = -1e-200; max = 100.0; + LogRange::mapRange(min, max); + QCOMPARE(min, -10.0); QCOMPARE(max, 2.0); + + min = 10.0; max = -1e-200; + LogRange::mapRange(min, max); + QCOMPARE(min, -10.0); QCOMPARE(max, 1.0); + + // if none of the input range is above the threshold in + // magnitude, but it still spans zero, we use the input max as + // threshold and then add 1 for range + min = -1e-200; max = 1e-300; + LogRange::mapRange(min, max); + QCOMPARE(min, -201.0); QCOMPARE(max, -200.0); + + min = 1e-200; max = -1e-300; + LogRange::mapRange(min, max); + QCOMPARE(min, -201.0); QCOMPARE(max, -200.0); + } + + void mapRangeSpanningZeroSetThreshold() + { + double min, max; + + min = -1.0; max = 10.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -4.0); QCOMPARE(max, 1.0); + + min = -100.0; max = 1.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -4.0); QCOMPARE(max, 2.0); + + min = -10.0; max = 1e-200; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -4.0); QCOMPARE(max, 1.0); + + min = 1e-200; max = -10.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -4.0); QCOMPARE(max, 1.0); + + min = -1e-200; max = 100.0; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -4.0); QCOMPARE(max, 2.0); + + min = 10.0; max = -1e-200; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -4.0); QCOMPARE(max, 1.0); + + // if none of the input range is above the threshold in + // magnitude, but it still spans zero, we use the input max as + // threshold and then add 1 for range + min = -1e-200; max = 1e-300; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -201.0); QCOMPARE(max, -200.0); + + min = 1e-200; max = -1e-300; + LogRange::mapRange(min, max, -4.0); + QCOMPARE(min, -201.0); QCOMPARE(max, -200.0); + } + +}; + +#endif
--- a/base/test/files.pri Mon Feb 27 16:52:47 2017 +0000 +++ b/base/test/files.pri Tue Feb 28 11:21:49 2017 +0000 @@ -1,10 +1,11 @@ TEST_HEADERS = \ + TestColumnOp.h \ + TestLogRange.h \ TestRangeMapper.h \ + TestOurRealTime.h \ TestPitch.h \ - TestOurRealTime.h \ - TestVampRealTime.h \ TestStringBits.h \ - TestColumnOp.h + TestVampRealTime.h TEST_SOURCES += \ svcore-base-test.cpp
--- a/base/test/svcore-base-test.cpp Mon Feb 27 16:52:47 2017 +0000 +++ b/base/test/svcore-base-test.cpp Tue Feb 28 11:21:49 2017 +0000 @@ -11,6 +11,7 @@ COPYING included with this distribution for more information. */ +#include "TestLogRange.h" #include "TestRangeMapper.h" #include "TestPitch.h" #include "TestStringBits.h" @@ -27,7 +28,7 @@ int good = 0, bad = 0; QCoreApplication app(argc, argv); - app.setOrganizationName("Sonic Visualiser"); + app.setOrganizationName("sonic-visualiser"); app.setApplicationName("test-svcore-base"); { @@ -60,6 +61,11 @@ if (QTest::qExec(&t, argc, argv) == 0) ++good; else ++bad; } + { + TestLogRange t; + if (QTest::qExec(&t, argc, argv) == 0) ++good; + else ++bad; + } if (bad > 0) { cerr << "\n********* " << bad << " test suite(s) failed!\n" << endl;
--- a/data/fileio/test/svcore-data-fileio-test.cpp Mon Feb 27 16:52:47 2017 +0000 +++ b/data/fileio/test/svcore-data-fileio-test.cpp Tue Feb 28 11:21:49 2017 +0000 @@ -43,7 +43,7 @@ } QCoreApplication app(argc, argv); - app.setOrganizationName("Sonic Visualiser"); + app.setOrganizationName("sonic-visualiser"); app.setApplicationName("test-fileio"); {
--- a/data/model/EditableDenseThreeDimensionalModel.cpp Mon Feb 27 16:52:47 2017 +0000 +++ b/data/model/EditableDenseThreeDimensionalModel.cpp Tue Feb 28 11:21:49 2017 +0000 @@ -455,7 +455,7 @@ if (n[j]) sample[j] /= n[j]; } - return LogRange::useLogScale(sample); + return LogRange::shouldUseLogScale(sample); } void
--- a/data/model/test/svcore-data-model-test.cpp Mon Feb 27 16:52:47 2017 +0000 +++ b/data/model/test/svcore-data-model-test.cpp Tue Feb 28 11:21:49 2017 +0000 @@ -24,7 +24,7 @@ int good = 0, bad = 0; QCoreApplication app(argc, argv); - app.setOrganizationName("Sonic Visualiser"); + app.setOrganizationName("sonic-visualiser"); app.setApplicationName("test-model"); {