#include "stdafx.h" #include "calcul.h" #include <numeric> #include <deque> #include <bitset> #include "cstruct.h" #include "print.h" using namespace std; ///Calculates distance between two vectors. ///@param[in] u element of the compared time series (n dimensional vector) ///@param[in] v element of the compared time series (n dimensional vector) ///@return Euclidean distance double calcul::distanceDtwEuklid(vtr<double> const &u, vtr<double> const &v) { double sum = 0; for (size_t i = 0; i < u.size(); i++) { sum += pow(u[i] - v[i], 2); } return sum; } ///Calculates distance between two vectors. ///@param[in] u element of the compared time series (n dimensional vector) ///@param[in] v element of the compared time series (n dimensional vector) ///@return Manhattan distance double calcul::distanceDtwManhattan(vtr<double> const &u, vtr<double> const &v) { double sum = 0; for (size_t i = 0; i < u.size(); i++) { sum += abs(u[i] - v[i]); } return sum; } ///Calculates chroma distance between two 12d vectors (specific data music data format needed). ///@param[in] u element of the compared time series (12d vector) ///@param[in] v element of the compared time series (12d vector) ///@param[in] threshold used for filtering insignificant tones in the input vectors ///@return Euclidean distance double calcul::distanceDtwCsiChroma(vtr<double> const &u, vtr<double> const &v, double threshold /*def value in header*/) { vtr<int> u_filter(u.size()); vtr<int> v_filter(v.size()); //binary filtering for (size_t i = 0; i < u.size(); i++) { if (u[i] > threshold) u_filter[i] = 1; if (v[i] > threshold) v_filter[i] = 1; } auto getRoot = [&scale = cstruct::scaleChord](vtr<double> const &vec) { int idx = 0; int min = constant::MAX_int; for (int i = 0; i < (int)scale.size(); i++) { int sum = 0; for (size_t j = 0; j < vec.size(); j++) { sum += (int)std::abs(vec[j] - scale[i][j]); //max value == 1 -> pow 2 -> abs } if (sum < min) { min = sum; idx = i; } } return idx; }; auto idxU = getRoot(u); auto idxV = getRoot(v); //calculate result (zero u/v if minimal scale vectors == 1) double result = 0; for (size_t i = 0; i < u.size(); i++) { double tmpU; if (cstruct::scaleChord[idxU][i] == 1) { tmpU = 0; } else { tmpU = u[i]; } double tmpV; if (cstruct::scaleChord[idxV][i] == 1) { tmpV = 0; } else { tmpV = v[i]; } //result += std::abs(tmpU - tmpV); result += std::pow(tmpU - tmpV, 2); } return result; } ///Calculates chord distance between two pairs of two 12d vectors. ///@param[in] u element of the compared time series (12d vector) ///@param[in] v element of the compared time series (12d vector) ///@param[in] uKey element of the compared key time series (12d vector) ///@param[in] vKey element of the compared key time series (12d vector) ///@return chord distance double calcul::distanceDtwCsiChord(vtr<double> const &u, vtr<double> const &v, vtr<int> const &uKey, vtr<int> const &vKey) { double replaceZero = false; //if true zero vtr is replaced by c dur 100010010000 auto getRoot = [&replaceZero](vtr<double> const &chord) { auto getShift = [](int idx) { return idx > 11 ? idx % 12 : idx; }; for (int i = 0; i < (int)chord.size(); i++) { if (chord[i]) { if (chord[getShift(i + 7)]) { if (chord[getShift(i + 3)]) return i; if (chord[getShift(i + 4)]) return i; } } } if (chord == vtr<double>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) replaceZero = true; /*else { int c = 0; for (int i = 0; i < (int)chord.size(); i++) if (chord[i] > 0) c++; if (c != 3) { cout << print::vector(chord); return -1; }*/ //} //chord = vtr<double>{ 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }; */ return 0; }; auto getIdxKey = [&scale = cstruct::scaleKey](vtr<int> const &vec) { int idx = 0; int min = constant::MAX_int; for (int i = 0; i < (int)scale.size(); i++) { int sum = 0; for (size_t j = 0; j < vec.size(); j++) { sum += (int)std::abs(vec[j] - scale[i][j]); //max value == 1 -> pow 2 -> abs } if (sum < min) { min = sum; idx = i; } } return idx; }; int idxU = getRoot(u); int idxV = getRoot(v); int idxUK = getIdxKey(uKey); int idxVK = getIdxKey(vKey); /*int shiftU = (idxU > 11) ? 3 : 4; if (shiftU == 3) idxU -= 12; int shiftV = (idxV > 11) ? 3 : 4; if (shiftV == 3) idxV -= 12;*/ vtr<int> replacement{ 1,0,0,0,1,0,0,1,0,0,0,0 }; auto getPitch = [&replaceZero, &replacement](vtr<double> const &vec, vtr<int> const &key, int idx) { vtr<bool> pitch(48); //pitch space of 4 levels (level e is irrelevant) pitch[idx] = 1; //level a root pitch[idx + 12] = 1; //level b root (copy) pitch[12 + (idx + 7) % 12] = 1; //level b 2. if (replaceZero) { for (size_t i = 0; i < 12; i++) { pitch[i + 24] = replacement[i]; pitch[i + 36] = replacement[i]; } } else { for (size_t i = 0; i < 12; i++) { pitch[i + 24] = vec[i]; //add key to 4. level (level d) pitch spaces (entire key vector) pitch[i + 36] = vec[i]; //copy 3. level to 4. } } //for (size_t i = 0; i < 12; i++) //copy 3. level to 4. for (size_t i = 0; i < 12; i++) { //add key to 4. level (level d) pitch spaces (entire key vector) if (key[i] == 1) pitch[i + 36] = key[i]; } return pitch; }; auto pitchU = getPitch(u, uKey, idxU/*, shiftU*/); //pitch space of 4 levels (level e is irrelevant) auto pitchV = getPitch(v, vKey, idxV/*, shiftV*/); auto getCofDistance = [](int idx1, int idx2) { return cstruct::cofDistance.at(std::abs(idx1 - idx2)); }; auto dist1 = getCofDistance(idxU, idxV); //distance between chord roots auto dist2 = getCofDistance(idxUK, idxVK); int dist3 = 0; //calculation of pitch space distance for (size_t i = 0; i < 48; i++) { if (pitchU[i] != pitchV[i]) dist3++; } /*int count = 0; for (size_t i = 0; i < pitchU.size() / 12; i++) { for (size_t j = 0; j < 12; j++) { if (pitchU[count++]) cout << "1"; else cout << "0"; } cout << endl; } count = 0; for (size_t i = 0; i < pitchU.size() / 12; i++) { for (size_t j = 0; j < 12; j++) { if (pitchV[count++]) cout << "1"; else cout << "0"; } cout << endl; }*/ return dist1 + dist2 + dist3; } //Calculates sum of Euclidean distance between all pairs. //@param[in] series time series //@return sum of dtw distances //double calcul::distance_dtw_many(vtr2<double> const &series) //{ // double sum = 0; // // for (size_t i = 0; i < series.size(); i++) // { // for (size_t j = i + 1; j < series.size(); j++) // { // sum += distance_dtw_euklid(series[i], series[j]); // } // } // // return sum; //} ///Calculates lcss distance between two elements of the compared time series. ///@param[in] u element of the compared time series (n dimensional vector) ///@param[in] v element of the compared time series (n dimensional vector) ///@param[in] idx index ///@return lcss distance double calcul::distanceLcss(vtr<double> const &u, vtr<double> const &v, int idx) { if (u.size() == 0 || v.size() == 0) { return 0; } return abs(u[idx] - v[idx]); } ///Calculates dtw raw score s1 (last cell in the distance matrix). ///@param[in] scoreRaw raw score ///@return dtw raw score s1 double calcul::scoreDtwS1(double scoreRaw) { return scoreRaw; } ///Calculates dtw score s2 (s1 divided by warping path length) ///@param[in] scoreRaw raw score (last cell in the distance matrix) ///@param[in] pathLength length of the warping path ///@return dtw score s2 double calcul::scoreDtwS2(double scoreRaw, size_t pathLength) { return sqrt(scoreRaw) / static_cast<double>(pathLength); } ///Calculates dtw score s3. ///@param[in] lenA length of the time series A ///@param[in] lenB length of the time series B ///@param[in] pathLength length of the warping path ///@return dtw score s3 double calcul::scoreDtwS3(size_t lenA, size_t lenB, size_t pathLength) { return 1 - (lenA / static_cast<double>(pathLength) + lenB / static_cast<double>(pathLength)) / 2; } ///Calculates dtw score s4. ///@param[in] scoreRaw raw score (last cell in the distance matrix) ///@param[in] scoreRawMax maximal dtw score ///@return dtw score s4 double calcul::scoreDtwS4(double scoreRaw, double scoreRawMax) { return (sqrt(scoreRaw) / sqrt(scoreRawMax)); } ///Calculates dtw score s5. ///@param[in] scoreRaw raw score (last cell in distance matrix) ///@param[in] scoreRawMax maximal dtw score ///@param[in] coefficient ratio of the compared time series lengths ///@return dtw score s5 double calcul::scoreDtwS5(double scoreRaw, double scoreRawMax, double coefficient) { return (sqrt(scoreRaw) / sqrt(scoreRawMax)) * coefficient; } ///Calculates maximal dtw score. ///@param[in] A time series A ///@param[in] B time series B ///@param[in] start coordinations of the warping path start (left upper end). ///@param[in] end coordinations of the warping path end (bottom right end) ///@return maximal raw dtw score double calcul::scoreDtwMax(vtr2<double> const &A, vtr2<double> const &B, coord start, coord end) { double min = constant::MAX_double; double max = constant::MIN_double; size_t sA = 0; size_t eA = (int)A.size(); size_t sB = 0; size_t eB = (int)B.size(); if (A.size() < B.size()) { sB = start.col; eB = end.col; } if (B.size() < A.size()) { sA = start.row; eA = end.row; } for (size_t i = sA; i < eA; i++) { double sum = 0; for (size_t j = 0; j < A[i].size(); j++) { sum += A[i][j]; } if (min > sum) min = sum; if (max < sum) max = sum; } for (size_t i = sB; i < eB; i++) { double sum = 0; for (size_t j = 0; j < B[i].size(); j++) { sum += B[i][j]; } if (min > sum) min = sum; if (max < sum) max = sum; } return pow(max - min, 2) * std::max(eA - sA, eB - sB); } ///Calculates input time series length ratio. ///@param[in] lenA length of the time series A ///@param[in] lenB length of the time series B ///@return length ratio double calcul::lenRatio(size_t lenA, size_t lenB) { if (lenA < lenB) { return (double)lenA / lenB; } else if (lenB < lenA) { return (double)lenB / lenA; } else { return 1; } } ///Calculates ratio. ///@param[in] dividend ///@param[in] divisor ///@return ratio double calcul::ratio(size_t dividend, size_t divisor) { return dividend / (double)divisor; } ///Calculates lcss score s1. ///@param[in] scoreRaw raw score (last cell in the distance matrix) ///@param[in] pathLength length of the warping path ///@return lcss score s1 double calcul::scoreLcssS1(double scoreRaw, size_t pathLength) { return 1 - scoreRaw / static_cast<double>(pathLength); } ///Calculates lcss score s2. ///@param[in] scoreRaw raw score (last cell in the distance matrix) ///@param[in] maxABLen length of the longer input time series ///@return lcss score s2 double calcul::scoreLcssS2(double scoreRaw, size_t maxABLen) { return 1 - scoreRaw / maxABLen; } ///Calculates lcss score s3. ///@param[in] scoreRaw raw score (last cell in the distance matrix) ///@return lcss score s3 double calcul::scoreLcssS3(double scoreRaw) { return scoreRaw; } ///Calculates average rank. ///@param[in] ref cluster id reference ///@param[in] queryAnswer query answer row (from id matrix (int)) ///@param[in] clusters ground truth of the clusters ///@return average rank double calcul::scoreAverageRank(int ref, vtr<int> const &queryAnswer, inputGroundTruth const &clusters) { int clusterSize = clusters.getClusterSize(ref); int counter = 0; double averageRank = 0; for (size_t i = 0; i < queryAnswer.size(); i++) //query (ref sequence) //column { if (clusters.getClusterID(queryAnswer[i]) == clusters.getClusterID(ref)) { averageRank += (int)i + 1; counter++; if (counter == clusterSize - 1) break; } } averageRank = averageRank / (clusterSize - 1); return averageRank; } ///Calculates average precision. ///@param[in] ref cluster id reference ///@param[in] queryAnswer query answer row (from id matrix (int)) ///@param[in] clusters ground truth of the clusters ///@return average precision double calcul::scoreAveragePrecision(int ref, vtr<int> const &queryAnswer, inputGroundTruth const &clusters) { int clusterSize = clusters.getClusterSize(ref); double pr = 0; int counter = 0; for (size_t i = 0; i < queryAnswer.size(); i++) //query (ref sequence) //column { if (clusters.getClusterID(queryAnswer[i]) == clusters.getClusterID(ref)) { pr += ++counter / (double)(i + 1); if (counter == clusterSize - 1) break; } } double ap = pr / (clusterSize - 1); return ap; } ///Calculates map score (mean average precision). ///@param[in] averagePrecisions vector of average precisions ///@return map score double calcul::scoreMap(vtr<double> const &averagePrecisions) { return accumulate(averagePrecisions.begin(), averagePrecisions.end(), 0.0) / averagePrecisions.size(); } ///Calculates precision. ///@param[in] ref cluster id reference ///@param[in] queryAnswer query answer row (from id matrix (int)) ///@param[in] clusters ground truth of the clusters ///@return precision fraction double calcul::scorePrecision(int ref, vtr<int> const &queryAnswer, inputGroundTruth const &clusters) { int clusterSize = clusters.getClusterSize(ref); int truePositives = 0; int falsePositives = 0; //int range = min(topThreshold, (int)top.size()); for (int i = 0; i < clusterSize - 1; i++) { if (clusters.getClusterID(queryAnswer[i]) == clusters.getClusterID(ref)) { truePositives++; } else { falsePositives++; } } double precision = (double)truePositives / (truePositives + falsePositives); return precision; } ///Calculates recall. ///@param[in] ref cluster id reference ///@param[in] queryAnswer query answer row (from id matrix (int)) ///@param[in] clusters ground truth of the clusters ///@return recall fraction double calcul::scoreRecall(int ref, vtr<int> const &queryAnswer, inputGroundTruth const &clusters) { int clusterSize = clusters.getClusterSize(ref); int truePositives = 0; for (int i = 0; i < clusterSize - 1; i++) { if (clusters.getClusterID(queryAnswer[i]) == clusters.getClusterID(ref)) truePositives++; } double recall = (double)truePositives / (clusterSize - 1); return recall; } ///Calculates Keogh's lower bound for dtw. EXPERIMENT ///@param[in] A time series A ///@param[in] B time series B ///@param[in] params parameters ///@return Keogh's lower bound distance double calcul::lbKeogh(vtr2<double> const &A, vtr2<double> const &B, parameter const ¶ms) { int width = 1 + 2 * (int)params.w; int w = (int)params.w; deque<int> maxfifo, minfifo; maxfifo.emplace_back(0); minfifo.emplace_back(0); vtr<double> maxvalues(B.size()); vtr<double> minvalues(B.size()); for (int i = 1; i < static_cast<int>(A.size()); ++i) { if (i >= w + 1) { maxvalues[i - w - 1] = A[maxfifo.front()][0]; minvalues[i - w - 1] = A[minfifo.front()][0]; } if (A[i][0] > A[i - 1][0]) { maxfifo.pop_back(); while (maxfifo.size() > 0) { if (A[i][0] <= A[maxfifo.back()][0]) break; maxfifo.pop_back(); } } else { minfifo.pop_back(); while (minfifo.size() > 0) { if (A[i][0] >= A[minfifo.back()][0]) break; minfifo.pop_back(); } } maxfifo.emplace_back(static_cast<int>(i)); minfifo.emplace_back(static_cast<int>(i)); if (i == width + maxfifo.front()) { maxfifo.pop_front(); } else if (i == width + minfifo.front()) { minfifo.pop_front(); } } for (size_t i = A.size(); i <= A.size() + w; ++i) { maxvalues[i - w - 1] = A[maxfifo.front()][0]; minvalues[i - w - 1] = A[minfifo.front()][0]; if (static_cast<int>(i) - maxfifo.front() >= width) maxfifo.pop_front(); if (static_cast<int>(i) - minfifo.front() >= width) minfifo.pop_front(); } double result = 0; for (size_t i = 0; i < A.size(); i++) { if (B[i][0] > maxvalues[i]) { result += pow(B[i][0] - maxvalues[i], 2); } else if (B[i][0] < minvalues[i]) { result += pow(B[i][0] - minvalues[i], 2); } } return result; } //Calculates Cosine distance. //@param[in] u element of the compared time series //@param[in] v element of the compared time series //@return cosine distance //double calcul::distance_cosine(vtr<double> const &u, vtr<double> const &v) //{ // double sumAB = 0; // for (size_t i = 0; i < u.size(); i++) // sumAB += u[i] * v[i]; // // double sumA = 0; // for (size_t i = 0; i < u.size(); i++) // sumA += pow(u[i], 2); // // double sumB = 0; // for (size_t i = 0; i < u.size(); i++) // sumB += pow(v[i], 2); // // return sumAB / (sqrt(sumA) * sqrt(sumB)); //} // //double calcul::distance_cosine2(input_point_ref const &point) //{ // double sumAB = 0; // for (size_t i = 0; i < point.p1.size(); i++) // sumAB += point.p1[i] * point.p2[i]; // // double sumA = 0; // for (size_t i = 0; i < point.p1.size(); i++) // sumA += pow(point.p1[i], 2); // // double sumB = 0; // for (size_t i = 0; i < point.p1.size(); i++) // sumB += pow(point.p2[i], 2); // // return sumAB / (sqrt(sumA) * sqrt(sumB)); //} ///Calculates first cell included in the warping window. ///@param[in] row row ///@param[in] win warping window width ///@param[in] coefficient input time series length ratio ///@return index of first cell in warping window int calcul::dtwPassStart(size_t row, int win, double coefficient) { return std::max(1, (int)(ceil((row - 1) * coefficient + 0.0000000001) - win)); } ///Calculates last cell included in the warping window. ///@param[in] row row ///@param[in] win warping window width ///@param[in] coefficient input time series length ratio ///@param[in] lenB length of the time series B ///@return index of last cell in warping window int calcul::dtwPassEnd(size_t row, int win, double coefficient, int lenB) { return std::min(lenB + 1, (int)(ceil(row * coefficient) + 1) + win); //const size_t end = min(lenB + 1, (int)(ceil(i * lenB / (double)lenA) + 1) + w); } ///Calculates if cell is included in the flexible warping pass. ///@param[in] row row ///@param[in] col column ///@param[in] past last cell which was included ///@param[in] w flexible warping pass width ///@return TRUE if cell is in the flexible pass ///@return FALSE if cell is not in the flexible pass bool calcul::isFlexiblePass(int row, int col, coord const &past, int w) { return std::abs((past.row - row) - (past.col - col)) < w; } ///Calculates mean value of the input vector. ///@param[in] v vector of doubles ///@return mean double calcul::vtrMean(vtr<double> const &v) { double sum = 0; for (auto &i : v) { sum += i; } return sum / v.size(); } ///Calculates vector of means of the 2d input vector. ///@param[in] series two dimensional vector ///@return vector of means vtr<double> calcul::vtrMean(vtr2<double> const &series) { vtr<double> average(series.size()); for (size_t i = 0; i < series.size(); i++) { average[i] = vtrMean(series[i]); } return average; } ///Calculates standard deviation of the input vector. ///@param[in] v vector ///@return standard deviation double calcul::vtrStd(vtr<double> const &v) { double mean = vtrMean(v); double sum = 0; for (auto &i : v) { sum += pow(i - mean, 2); } return sqrt(sum / v.size()); } ///Finds maximal value contained in the input vector. ///@tparam data type of searched vector ///@param[in] input vector ///@return maximal value template <typename T> T calcul::vtrMax(vtr<T> const &input) { T max = (T)constant::MIN_double; for (auto &i : input) { if (i > max) max = i; } return max; } template int calcul::vtrMax(vtr<int> const &input); template double calcul::vtrMax<double>(vtr<double> const &input); ///Finds maximal value contained in the 2d input vector. ///@tparam data type of searched vector ///@param[in] input vector ///@return maximal value template <typename T> T calcul::vtrMax(vtr2<T> const &input) { double max = constant::MIN_double; for (auto &&i : input) { for (auto &&j : i) { if (j > max) max = j; } } return max; } template double calcul::vtrMax<double>(vtr2<double> const &input); ///Finds maximal value contained in the 3d input vector. ///@param[in] input vector ///@return maximal value template <typename T> T calcul::vtrMax(vtr3<T> const &input) { double max = constant::MIN_double; for (auto const &i : input) { auto tmp = vtr_findMax(i); if (tmp > max) max = tmp; } return max; } ///Finds minimal value contained in the input vector. ///@param[in] input vector ///@return minimal value template <typename T> T calcul::vtrMin(vtr<T> const &input) { T min = (T)constant::MAX_double; for (auto &i : input) { if (i < min) min = i; } return min; } template double calcul::vtrMin<double>(vtr<double> const &input); ///Finds minimal value contained in the input vector. ///@param[in] input vector ///@return minimal value template <typename T> T calcul::vtrMin(vtr2<T> const &input) { double min = constant::MAX_double; for (auto const &i : input) { for (auto const &j : i) { if (j < min) min = j; } } return min; } template double calcul::vtrMin<double>(vtr2<double> const &input);