diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cc795263..86c74a774 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ if(hasParent) endif() if(APPLE) - set(CMAKE_OSX_DEPLOYMENT_TARGET "10.8" CACHE STRING "") + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "") #A consequence of targetting 10.8. Needs to be set globally from 10.15 onwards in order for the test program to compile successfully during configure string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++") endif() diff --git a/FlucomaVersion.cmake b/FlucomaVersion.cmake index 9d7538ad6..ea4ab57a4 100644 --- a/FlucomaVersion.cmake +++ b/FlucomaVersion.cmake @@ -14,7 +14,7 @@ find_package(Git REQUIRED) set(flucoma_VERSION_MAJOR 1) set(flucoma_VERSION_MINOR 0) -set(flucoma_VERSION_PATCH 7) +set(flucoma_VERSION_PATCH 8) set(flucoma_VERSION_SUFFIX "") function(make_flucoma_version_string output_variable) diff --git a/docs/requirements.txt b/docs/requirements.txt index fba8d392c..be0c5eac7 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,3 +2,4 @@ sphinx breathe myst-parser sphinx-book-theme +schema diff --git a/include/algorithms/public/SKMeans.hpp b/include/algorithms/public/SKMeans.hpp index 0ddf9699d..576a9dd76 100644 --- a/include/algorithms/public/SKMeans.hpp +++ b/include/algorithms/public/SKMeans.hpp @@ -33,7 +33,8 @@ class SKMeans : public KMeans using namespace Eigen; using namespace _impl; assert(!mTrained || (dataset.pointSize() == mDims && mK == k)); - MatrixXd dataPoints = asEigen(dataset.getData()); + MatrixXd dataPoints = + asEigen(dataset.getData()).rowwise().normalized(); MatrixXd dataPointsT = dataPoints.transpose(); if (mTrained) { mAssignments = assignClusters(dataPointsT);} else @@ -87,9 +88,8 @@ class SKMeans : public KMeans { for (index i = 0; i < mAssignments.cols(); i++) { - double val = mEmbedding(mAssignments(i), i); mEmbedding.col(i).setZero(); - mEmbedding(mAssignments(i), i) = val; + mEmbedding(mAssignments(i), i) = 1.0; } } diff --git a/include/algorithms/util/FFT.hpp b/include/algorithms/util/FFT.hpp index dd80f700d..e6865865d 100644 --- a/include/algorithms/util/FFT.hpp +++ b/include/algorithms/util/FFT.hpp @@ -14,6 +14,7 @@ under the European Union’s Horizon 2020 research and innovation programme #include "../../data/FluidMemory.hpp" #include #include +#include namespace fluid { namespace algorithm { @@ -38,8 +39,8 @@ class FFTSetup FFTSetup(FFTSetup const&) = delete; FFTSetup& operator=(FFTSetup const&) = delete; - FFTSetup(FFTSetup&& other) { *this = std::move(other); }; - FFTSetup& operator=(FFTSetup&& other) + FFTSetup(FFTSetup&& other) noexcept { *this = std::move(other); }; + FFTSetup& operator=(FFTSetup&& other) noexcept { using std::swap; swap(mMaxSize, other.mMaxSize); @@ -62,13 +63,13 @@ class FFT public: using MapXcd = Eigen::Map; - static void setup() { getFFTSetup(); } FFT() = delete; FFT(index size, Allocator& alloc = FluidDefaultAllocator()) noexcept : mMaxSize(size), mSize(size), mFrameSize(size / 2 + 1), - mLog2Size(static_cast(std::log2(size))), mSetup(getFFTSetup()), + mLog2Size(static_cast(std::log2(size))), + mSetup(getFFTSetup(*this, size)), mRealBuffer(asUnsigned(mFrameSize), alloc), mImagBuffer(asUnsigned(mFrameSize), alloc), mOutputBuffer(asUnsigned(mFrameSize), alloc) @@ -106,11 +107,18 @@ class FFT return {mOutputBuffer.data(), mFrameSize}; } +private: + std::optional mLocalSetup; protected: - static htl::setup_type getFFTSetup() - { - static const impl::FFTSetup static_setup(65536); - return static_setup(); + static constexpr index default_max = 65536; + static htl::setup_type getFFTSetup(FFT& _this, index size) + { + static const impl::FFTSetup static_setup(default_max); + if(size <= default_max) return static_setup(); + else { + _this.mLocalSetup = std::optional(size); + return _this.mLocalSetup->operator()(); + } } index mMaxSize{16384}; @@ -127,6 +135,7 @@ class FFT rt::vector> mOutputBuffer; }; + class IFFT : public FFT { diff --git a/include/algorithms/util/TruePeak.hpp b/include/algorithms/util/TruePeak.hpp index 0c45e80d6..c242e3ed6 100644 --- a/include/algorithms/util/TruePeak.hpp +++ b/include/algorithms/util/TruePeak.hpp @@ -35,10 +35,12 @@ class Interpolator }; public: - Interpolator(index maxtaps, index maxfactor, Allocator& alloc) - : mMaxTaps{maxtaps}, mMaxFactor{maxfactor}, - mMaxLatency{(mMaxTaps + mMaxFactor - 1) / mMaxFactor}, - mBuffer(asUnsigned(mMaxLatency), alloc), mCount(asUnsigned(mMaxFactor), alloc), + Interpolator(index maxtaps, index maxfactor, index minFactor, + Allocator& alloc) + : mMaxTaps{maxtaps}, mMaxFactor{maxfactor}, mMinFactor{minFactor}, + mMaxLatency{(mMaxTaps + mMinFactor - 1) / minFactor}, + mBuffer(asUnsigned(mMaxLatency), alloc), + mCount(asUnsigned(mMaxFactor), alloc), mFilters(mMaxFactor, mMaxLatency, alloc), mIndex(mMaxFactor, mMaxLatency, alloc) {} @@ -47,6 +49,7 @@ class Interpolator { assert(taps <= mMaxTaps); assert(factor <= mMaxFactor); + assert(factor >= mMinFactor); assert(factor > 0); assert(taps > 0); @@ -121,7 +124,8 @@ class Interpolator index mMaxTaps; index mMaxFactor; - index mMaxLatency; + index mMinFactor; + index mMaxLatency; index mTaps; index mFactor; @@ -142,17 +146,18 @@ class TruePeak { static constexpr index nTaps = 49; static constexpr index maxFactor = 4; + static constexpr index minFactor = 2; public: TruePeak(index maxSize, Allocator& alloc) - : mInterpolator(nTaps, maxFactor, alloc), mBuffer{maxFactor * maxSize, - alloc} + : mInterpolator(nTaps, maxFactor, minFactor, alloc), + mBuffer{maxFactor * maxSize, alloc} {} void init(index /*size*/, double sampleRate, Allocator&) { mSampleRate = sampleRate; - mFactor = sampleRate < (2 * 44100) ? 4 : 2; + mFactor = sampleRate < (2 * 44100) ? maxFactor : minFactor; mInterpolator.init(nTaps, mFactor); } diff --git a/include/clients/nrt/DataSetQueryClient.hpp b/include/clients/nrt/DataSetQueryClient.hpp index ddaa1fce1..25dacd24f 100644 --- a/include/clients/nrt/DataSetQueryClient.hpp +++ b/include/clients/nrt/DataSetQueryClient.hpp @@ -144,10 +144,10 @@ class DataSetQueryClient : public FluidBaseClient, OfflineIn, OfflineOut return OK(); } - MessageResult limit(index rows) + MessageResult limit(index points) { - if (rows <= 0) return Error("invalid value"); - mAlgorithm.limit(rows); + if (points <= 0) return Error("invalid limit on the number of points"); + mAlgorithm.limit(points); return OK(); } diff --git a/include/clients/nrt/KNNClassifierClient.hpp b/include/clients/nrt/KNNClassifierClient.hpp index 4fc020086..bc99e4082 100644 --- a/include/clients/nrt/KNNClassifierClient.hpp +++ b/include/clients/nrt/KNNClassifierClient.hpp @@ -22,11 +22,11 @@ namespace knnclassifier { struct KNNClassifierData { - algorithm::KDTree tree{0}; + algorithm::KDTree tree{algorithm::KDTree()}; FluidDataSet labels{1}; - index size() const { return labels.size(); } - index dims() const { return tree.dims(); } - void clear() + index size() const { return labels.size(); } + index dims() const { return tree.dims(); } + void clear() { labels = FluidDataSet(1); tree.clear(); @@ -43,7 +43,10 @@ void to_json(nlohmann::json& j, const KNNClassifierData& data) bool check_json(const nlohmann::json& j, const KNNClassifierData&) { return fluid::check_json(j, {"tree", "labels"}, - {JSONTypes::OBJECT, JSONTypes::OBJECT}); + {JSONTypes::OBJECT, JSONTypes::OBJECT}) && + fluid::algorithm::check_json(j.at("tree"), algorithm::KDTree()) && + fluid::check_json(j.at("labels"), + FluidDataSet()); } void from_json(const nlohmann::json& j, KNNClassifierData& data) @@ -132,14 +135,14 @@ class KNNClassifierClient : public FluidBaseClient, algorithm::KNNClassifier classifier; RealVector point(mAlgorithm.tree.dims()); point <<= BufferAdaptor::ReadAccess(data.get()) - .samps(0, mAlgorithm.tree.dims(), 0); + .samps(0, mAlgorithm.tree.dims(), 0); std::string result = classifier.predict(mAlgorithm.tree, point, mAlgorithm.labels, k, weight); return result; } - MessageResult predict(InputDataSetClientRef source, - LabelSetClientRef dest) const + MessageResult predict(InputDataSetClientRef source, + LabelSetClientRef dest) const { index k = get(); bool weight = get() != 0; @@ -163,7 +166,7 @@ class KNNClassifierClient : public FluidBaseClient, { RealVectorView point = data.row(i); StringVector label = {classifier.predict(mAlgorithm.tree, point, - mAlgorithm.labels, k, weight)}; + mAlgorithm.labels, k, weight)}; result.add(ids(i), label); } destPtr->setLabelSet(result); @@ -186,7 +189,7 @@ class KNNClassifierClient : public FluidBaseClient, makeMessage("read", &KNNClassifierClient::read)); } - index encodeIndex(std::string const& label) const + index encodeIndex(std::string const& label) const { return mLabelSetEncoder.encodeIndex(label); } diff --git a/include/clients/nrt/KNNRegressorClient.hpp b/include/clients/nrt/KNNRegressorClient.hpp index ec272a245..2a0b49ec6 100644 --- a/include/clients/nrt/KNNRegressorClient.hpp +++ b/include/clients/nrt/KNNRegressorClient.hpp @@ -20,7 +20,7 @@ namespace knnregressor { struct KNNRegressorData { - algorithm::KDTree tree{0}; + algorithm::KDTree tree{algorithm::KDTree()}; FluidDataSet target{1}; index size() const { return target.size(); } index dims() const { return tree.dims(); } @@ -41,7 +41,10 @@ void to_json(nlohmann::json& j, const KNNRegressorData& data) bool check_json(const nlohmann::json& j, const KNNRegressorData&) { return fluid::check_json(j, {"tree", "target"}, - {JSONTypes::OBJECT, JSONTypes::OBJECT}); + {JSONTypes::OBJECT, JSONTypes::OBJECT}) && + fluid::algorithm::check_json(j.at("tree"), algorithm::KDTree()) && + fluid::check_json(j.at("labels"), + FluidDataSet()); } void from_json(const nlohmann::json& j, KNNRegressorData& data) @@ -128,24 +131,25 @@ class KNNRegressorClient : public FluidBaseClient, if (mAlgorithm.tree.size() < k) return Error(NotEnoughData); InBufferCheck bufCheck(mAlgorithm.tree.dims()); - if (!bufCheck.checkInputs(in.get())) - return Error(bufCheck.error()); + if (!bufCheck.checkInputs(in.get())) return Error(bufCheck.error()); BufferAdaptor::ReadAccess inBuf(in.get()); - BufferAdaptor::Access outBuf(out.get()); + BufferAdaptor::Access outBuf(out.get()); if (!outBuf.exists()) return Error(InvalidBuffer); - Result resizeResult = outBuf.resize(mAlgorithm.target.dims(), 1, inBuf.sampleRate()); + Result resizeResult = + outBuf.resize(mAlgorithm.target.dims(), 1, inBuf.sampleRate()); if (!resizeResult.ok()) return Error(BufferAlloc); algorithm::KNNRegressor regressor; RealVector input(mAlgorithm.tree.dims()); RealVector output(mAlgorithm.target.dims()); input <<= inBuf.samps(0, mAlgorithm.tree.dims(), 0); - regressor.predict(mAlgorithm.tree, mAlgorithm.target, input, output, k, weight); + regressor.predict(mAlgorithm.tree, mAlgorithm.target, input, output, k, + weight); outBuf.samps(0) <<= output; return OK(); } MessageResult predict(InputDataSetClientRef source, - DataSetClientRef dest) const + DataSetClientRef dest) const { index k = get(); bool weight = get() != 0; @@ -169,7 +173,8 @@ class KNNRegressorClient : public FluidBaseClient, for (index i = 0; i < dataSet.size(); i++) { RealVectorView point = data.row(i); - regressor.predict(mAlgorithm.tree, mAlgorithm.target, point, prediction, k, weight); + regressor.predict(mAlgorithm.tree, mAlgorithm.target, point, prediction, + k, weight); result.add(ids(i), prediction); } destPtr->setDataSet(result); @@ -262,9 +267,10 @@ class KNNRegressorQuery : public FluidBaseClient, ControlIn, ControlOut RealVector output(algorithm.target.dims(), c.allocator()); input <<= BufferAdaptor::ReadAccess(get().get()) - .samps(0, algorithm.tree.dims(), 0); + .samps(0, algorithm.tree.dims(), 0); - regressor.predict(algorithm.tree, algorithm.target, input, output, k, weight, c.allocator()); + regressor.predict(algorithm.tree, algorithm.target, input, output, k, + weight, c.allocator()); outBuf.samps(0) <<= output; } } diff --git a/include/clients/nrt/NMFCrossClient.hpp b/include/clients/nrt/NMFCrossClient.hpp index f407f6393..0b3ea1c48 100644 --- a/include/clients/nrt/NMFCrossClient.hpp +++ b/include/clients/nrt/NMFCrossClient.hpp @@ -40,7 +40,7 @@ constexpr auto NMFCrossParams = defineParameters( InputBufferParam("target", "Target Buffer"), BufferParam("output", "Output Buffer"), LongParam("timeSparsity", "Time Sparsity", 7, Min(1), Odd()), - LongParam("polyphony", "Polyphony", 10, Min(1), Odd(), + LongParam("polyphony", "Polyphony", 11, Min(1), Odd(), FrameSizeUpperLimit()), LongParam("continuity", "Continuity", 7, Min(1), Odd()), LongParam("iterations", "Number of Iterations", 50, Min(1)), diff --git a/include/clients/nrt/UMAPClient.hpp b/include/clients/nrt/UMAPClient.hpp index 90f59fc97..bf60d4024 100644 --- a/include/clients/nrt/UMAPClient.hpp +++ b/include/clients/nrt/UMAPClient.hpp @@ -79,8 +79,8 @@ class UMAPClient : public FluidBaseClient, auto src = srcPtr->getDataSet(); auto dest = destPtr->getDataSet(); if (src.size() == 0) return Error(EmptyDataSet); - if (get() > src.size()) - return Error("Number of Neighbours is larger than dataset"); + if (get() >= src.size()) + return Error("Number of Neighbours is greater or equal to the size of the the dataset"); FluidDataSet result; try { diff --git a/include/data/FluidDataSet.hpp b/include/data/FluidDataSet.hpp index 08ca3a07c..d73d37202 100644 --- a/include/data/FluidDataSet.hpp +++ b/include/data/FluidDataSet.hpp @@ -170,7 +170,7 @@ class FluidDataSet using namespace std; if (size() == 0) return "{}"; ostringstream result; - result << endl << "rows: " << size() << " cols: " << pointSize() << endl; + result << endl << "points:" << size() << " cols:" << pointSize() << endl; if (size() < maxRows) { for (index r = 0; r < size(); r++) diff --git a/tests/data/TestFluidTensor.cpp b/tests/data/TestFluidTensor.cpp index d7f553f5d..932c7b99c 100644 --- a/tests/data/TestFluidTensor.cpp +++ b/tests/data/TestFluidTensor.cpp @@ -20,7 +20,7 @@ TEST_CASE("FluidTensor can be created from a list of dimenions","[FluidTensor]") REQUIRE(x.size() == 3); REQUIRE(x.rows() == 3); - REQUIRE(x.cols() == 1); + // REQUIRE(x.cols() == 1); REQUIRE(std::distance(x.begin(),x.end()) == x.size()); } SECTION("2D creation reports correct sizes"){ @@ -31,15 +31,15 @@ TEST_CASE("FluidTensor can be created from a list of dimenions","[FluidTensor]") REQUIRE(x.cols() == 2); REQUIRE(std::distance(x.begin(),x.end()) == x.size()); } - // SECTION("3D creation reports correct sizes"){ - // const FluidTensor x(fluid::FluidDefaultAllocator(), 3,2,5); + SECTION("3D creation reports correct sizes"){ + const FluidTensor x(3,2,5); - // REQUIRE(x.size() == (3 * 2 * 5)); - // REQUIRE(x.rows() == 3); - // REQUIRE(x.cols() == 2); - // REQUIRE(x.descriptor().extents[2] == 5); - // REQUIRE(std::distance(x.begin(),x.end()) == x.size()); - // } + REQUIRE(x.size() == (3 * 2 * 5)); + REQUIRE(x.rows() == 3); + REQUIRE(x.cols() == 2); + REQUIRE(x.descriptor().extents[2] == 5); + REQUIRE(std::distance(x.begin(),x.end()) == x.size()); + } } TEST_CASE("FluidTensor can be initialized from initializer lists","[FluidTensor]"){ @@ -62,7 +62,7 @@ TEST_CASE("FluidTensor can be initialized from initializer lists","[FluidTensor] 4}; const std::array y{0,1,2,3,4}; REQUIRE(x.rows() == 5); - REQUIRE(x.cols() == 1); + // REQUIRE(x.cols() == 1); REQUIRE(std::distance(x.begin(),x.end()) == x.size()); REQUIRE(std::equal(x.begin(),x.end(), y.begin())); } diff --git a/tests/data/approval_tests/TestFluidDataSet.FluidDataSet_prints_consistent_summaries_for_approval.bigger.approved.txt b/tests/data/approval_tests/TestFluidDataSet.FluidDataSet_prints_consistent_summaries_for_approval.bigger.approved.txt index 87022a7eb..63a78ec18 100644 --- a/tests/data/approval_tests/TestFluidDataSet.FluidDataSet_prints_consistent_summaries_for_approval.bigger.approved.txt +++ b/tests/data/approval_tests/TestFluidDataSet.FluidDataSet_prints_consistent_summaries_for_approval.bigger.approved.txt @@ -1,5 +1,5 @@ -rows: 100 cols: 100 +points:100 cols:100 0 0 1 2 ... 97 98 99 0 100 101 102 ... 197 198 199 0 200 201 202 ... 297 298 299 diff --git a/tests/data/approval_tests/TestFluidDataSet.FluidDataSet_prints_consistent_summaries_for_approval.small.approved.txt b/tests/data/approval_tests/TestFluidDataSet.FluidDataSet_prints_consistent_summaries_for_approval.small.approved.txt index 0db43d1ca..b35c6f6d2 100644 --- a/tests/data/approval_tests/TestFluidDataSet.FluidDataSet_prints_consistent_summaries_for_approval.small.approved.txt +++ b/tests/data/approval_tests/TestFluidDataSet.FluidDataSet_prints_consistent_summaries_for_approval.small.approved.txt @@ -1,5 +1,5 @@ -rows: 2 cols: 5 +points:2 cols:5 zero 0 1 2 3 4 one 5 6 7 8 9