Advertisement
999ms

DSP homework

Mar 29th, 2021 (edited)
862
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.20 KB | None | 0 0
  1. #include <bits/stdc++.h>
  2. #define all(x) begin(x), end(x)
  3.  
  4. using namespace std;
  5.  
  6. mt19937 rnd(58); // random generator
  7. const double PI = acos(-1);
  8.  
  9. vector<int> logs = {-1};
  10.  
  11. int Log2(int x) {
  12.   while (logs.size() <= x) {
  13.     logs.push_back(logs[logs.size() >> 1] + 1);
  14.   }
  15.   return logs[x];
  16. }
  17.  
  18.  
  19. vector<double> generateSequence(int n) {
  20.   vector<double> result(n);
  21.   for (int i = 0; i < n; i++) {
  22.     result[i] = 1.0 / ((unsigned int)rnd() + 1) * rnd();
  23.   }
  24.   return result;
  25. }
  26.  
  27. struct Statistics {
  28.   int multOperationCounter = 0;
  29.   int sumOperationCounter = 0;
  30. };
  31.  
  32. auto calculateSimpleConvolution(const vector<double>& a, const vector<double>& b) {
  33.   assert(a.size() == b.size());
  34.   auto start = clock();
  35.   Statistics stat;
  36.   const int n = a.size();
  37.   vector<double> result(a.size() + b.size() - 1);
  38.  
  39.   for (int i = 0; i < n; i++) {
  40.     for (int j = 0; j < n; j++) {
  41.       result[i + j] += a[i] * b[j];
  42.       stat.sumOperationCounter++;
  43.       stat.multOperationCounter++;
  44.     }
  45.   }
  46.  
  47.   auto finish = clock();
  48.  
  49.   return tuple<double, Statistics, vector<double>>{(finish - start) * 1000.0 / CLOCKS_PER_SEC, stat, result};
  50. }
  51.  
  52. struct Complex {
  53.   double real, imag;
  54.   Complex(double real = 0, double imag = 0) : real(real), imag(imag) {}
  55.  
  56.   Complex operator + (const Complex& o) const {
  57.     return {real + o.real, imag + o.imag};
  58.   }
  59.  
  60.   Complex operator - (const Complex& o) const {
  61.     return {real + o.real, imag + o.imag};
  62.   }
  63.  
  64.   Complex operator * (const Complex& o) const {
  65.     return {real * o.real - imag * o.imag, real * o.imag + imag * o.real};
  66.   }
  67.  
  68.   Complex operator / (const double& o) const {
  69.     return {real / o, imag / o};
  70.   }
  71.  
  72. };
  73.  
  74.  
  75. auto precalc(int n) {
  76.   static const double PI = acos(-1);
  77.   vector<Complex> w(n);
  78.   for (int i = 0; i < n; ++i) {
  79.     w[i] = Complex(cos(i * PI / (n >> 1)), sin(i * PI / (n >> 1)));
  80.   }
  81.   return w;
  82. }
  83.  
  84.  
  85. void FFT(vector<Complex>& arr, int pwr, Statistics& stat, const vector<Complex>& w) {
  86.   if (pwr == 0) return;
  87.  
  88.   const int size = 1 << pwr;
  89.  
  90.   vector<Complex> a(size >> 1), b(size >> 1);
  91.  
  92.   for (int i = 0; i < size; i++) {
  93.     if (i & 1) {
  94.       b[i >> 1] = arr[i];
  95.     } else {
  96.       a[i >> 1] = arr[i];
  97.     }
  98.   }
  99.  
  100.   FFT(a, pwr - 1, stat, w);
  101.   FFT(b, pwr - 1, stat, w);
  102.  
  103.   for (int i = 0; i < size; i++) {
  104.     arr[i] = a[i % a.size()] + w[i << Log2(w.size() / arr.size())] * b[i % b.size()];
  105.     stat.sumOperationCounter += 4;
  106.     stat.multOperationCounter += 3;
  107.   }
  108. }
  109.  
  110.  
  111. auto calculateConvolutionWithFFT(const vector<double>& a, const vector<double>& b) {
  112.   Statistics stat;
  113.   const int n = a.size();
  114.  
  115.   int power = 0;
  116.   int sz1 = a.size();
  117.   int sz2 = b.size();
  118.   while ((1 << power) < (sz1 + sz2 - 1)) power++;
  119.   int x = 1 << power;
  120.  
  121.   auto w = precalc(x);
  122.  
  123.   auto start = clock();
  124.  
  125.   vector<Complex> arr(x);
  126.   vector<Complex> brr(x);
  127.   for (int i = 0; i < n; i++) {
  128.     arr[i] = {a[i], 0.0};
  129.     brr[i] = {b[i], 0.0};
  130.   }
  131.  
  132.  
  133.   FFT(arr, power, stat, w);
  134.   FFT(brr, power, stat, w);
  135.  
  136.   for (int i = 0; i < x; i++) {
  137.     arr[i] = arr[i] * brr[i];
  138.     stat.multOperationCounter += 2;
  139.     stat.sumOperationCounter += 2;
  140.   }
  141.  
  142.  
  143.   FFT(arr, power, stat, w);
  144.   vector<double> result(x);
  145.  
  146.   for (int i = 0; i < x; i++) {
  147.     result[i] = arr[i].real / x;
  148.     stat.multOperationCounter++;
  149.   }
  150.   reverse(begin(result) + 1, end(result));
  151.   result.resize(a.size() + b.size() - 1);
  152.  
  153.   auto finish = clock();
  154.  
  155.   return tuple<double, Statistics, vector<double>>{(finish - start) * 1000.0 / CLOCKS_PER_SEC, stat, result};
  156. }
  157.  
  158. void FHT(vector<double>& arr, Statistics& stat, const vector<double>& cosinuses, const vector<double>& sinuses) {
  159.   if (arr.size() == 2) {
  160.     arr = {arr[0] + arr[1], arr[0] - arr[1]};
  161.     stat.sumOperationCounter += 2;
  162.     return;
  163.   }
  164.   const int n = arr.size();
  165.   vector<double> a(n >> 1), b(n >> 1);
  166.   for (int i = 0; i < n; i++) {
  167.     if (i & 1) {
  168.       b[i >> 1] = arr[i];
  169.     } else {
  170.       a[i >> 1] = arr[i];
  171.     }
  172.   }
  173.   FHT(a, stat, cosinuses, sinuses);
  174.   FHT(b, stat, cosinuses, sinuses);
  175.   a.resize(n);
  176.   b.resize(n);
  177.   for (int i = 0; i < n / 2; i++) {
  178.     a[i + n / 2] = a[i];
  179.     b[i + n / 2] = b[i];
  180.   }
  181.   for (int k = 0; k < n; k++) {
  182.     double c = cosinuses[k << Log2(cosinuses.size() / n)];
  183.     double s = sinuses[k << Log2(cosinuses.size() / n)];
  184.     arr[k] = a[k] + b[k] * c + b[(n - k) % n] * s;
  185.     stat.multOperationCounter += 2;
  186.     stat.sumOperationCounter += 2;
  187.   }
  188. }
  189.  
  190. auto calculateConvolutionWithFHT(const vector<double>& a, const vector<double>& b) {
  191.   Statistics stat;
  192.  
  193.   int power = 0;
  194.   while ((1 << power) < (a.size() + b.size() - 1)) power++;
  195.   int x = 1 << power;
  196.  
  197.   vector<double> cosinuses(x);
  198.   vector<double> sinuses(x);
  199.   for (int i = 0; i < x; i++) {
  200.     cosinuses[i] = cos(2 * PI * i / x);
  201.     sinuses[i] = sin(2 * PI * i / x);
  202.   }
  203.   auto start = clock();
  204.  
  205.   vector<double> arr(all(a));
  206.   vector<double> brr(all(b));
  207.   arr.resize(x);
  208.   brr.resize(x);
  209.  
  210.  
  211.   FHT(arr, stat, cosinuses, sinuses);
  212.   FHT(brr, stat, cosinuses, sinuses);
  213.  
  214.   vector<double> result(x);
  215.  
  216.   for (int i = 0; i < x; i++) {
  217.     result[i] = (
  218.           arr[i] * brr[i]
  219.         + arr[(x - i) % x] * brr[i]
  220.         + arr[i] * brr[(x - i) % x]
  221.         - arr[(x - i) % x] * brr[(x - i) % x]
  222.       ) / 2;
  223.     stat.multOperationCounter += 4;
  224.     stat.sumOperationCounter += 3;
  225.   }
  226.  
  227.   FHT(result, stat, cosinuses, sinuses);
  228.  
  229.   for (auto& value : result) {
  230.     value /= x;
  231.   }
  232.  
  233.   result.resize(a.size() + b.size() - 1);
  234.  
  235.   auto finish = clock();
  236.  
  237.   return tuple<double, Statistics, vector<double>>{(finish - start) * 1000.0 / CLOCKS_PER_SEC, stat, result};
  238. }
  239.  
  240.  
  241. void DHT(vector<double>& arr, Statistics& stat, const vector<double>& cosinuses, const vector<double>& sinuses) {
  242.   const int n = arr.size();
  243.   vector<double> result(n);
  244.   for (int i = 0; i < n; i++) {
  245.     for (int j = 0; j < n; j++) {
  246.       result[i] += arr[j] * (cosinuses[i * j % n] + sinuses[i * j % n]);
  247.       stat.multOperationCounter += 1;
  248.       stat.sumOperationCounter += 2;
  249.     }
  250.   }  
  251.   arr = std::move(result);
  252. }
  253.  
  254. auto calculateConvolutionWithDHT(const vector<double>& a, const vector<double>& b) {
  255.   Statistics stat;
  256.  
  257.   int x = a.size() + b.size() - 1;
  258.  
  259.   vector<double> cosinuses(x);
  260.   vector<double> sinuses(x);
  261.   for (int i = 0; i < x; i++) {
  262.     cosinuses[i] = cos(2 * PI * i / x);
  263.     sinuses[i] = sin(2 * PI * i / x);
  264.   }
  265.   auto start = clock();
  266.  
  267.   vector<double> arr(all(a));
  268.   vector<double> brr(all(b));
  269.   arr.resize(x);
  270.   brr.resize(x);
  271.  
  272.  
  273.   DHT(arr, stat, cosinuses, sinuses);
  274.   DHT(brr, stat, cosinuses, sinuses);
  275.  
  276.   vector<double> result(x);
  277.  
  278.   for (int i = 0; i < x; i++) {
  279.     result[i] = (
  280.           arr[i] * brr[i]
  281.         + arr[(x - i) % x] * brr[i]
  282.         + arr[i] * brr[(x - i) % x]
  283.         - arr[(x - i) % x] * brr[(x - i) % x]
  284.       ) / 2;
  285.     stat.multOperationCounter += 4;
  286.     stat.sumOperationCounter += 3;
  287.   }
  288.  
  289.   DHT(result, stat, cosinuses, sinuses);
  290.  
  291.   for (auto& value : result) {
  292.     value /= x;
  293.   }
  294.  
  295.   result.resize(a.size() + b.size() - 1);
  296.  
  297.   auto finish = clock();
  298.  
  299.   return tuple<double, Statistics, vector<double>>{(finish - start) * 1000.0 / CLOCKS_PER_SEC, stat, result};
  300. }
  301.  
  302.  
  303. double calculateDelta(vector<double>& a, vector<double>& b) {
  304.   double answer = 0;
  305.   for (int i = 0; i < int(a.size()); i++) {
  306.     answer += abs(a[i] - b[i]);
  307.   }
  308.   return answer;
  309. }
  310.  
  311. int main() {
  312.  
  313.   for (int log2_len = 1; log2_len <= 10; log2_len++) {
  314.     const int n = 3 << log2_len;
  315.     auto a = generateSequence(n);
  316.     auto b = generateSequence(n);
  317.    
  318.     cout << "Size = " << n << '\n';
  319.     cout << '\n';
  320.     cout << "simple:\n";
  321.     auto [spentTimeSimple, statSimple, resultSimple] = calculateSimpleConvolution(a, b);
  322.     cout << spentTimeSimple << " ms.\n";
  323.     cout << "Mult operations: " << statSimple.multOperationCounter << '\n';
  324.     cout << "Sum operations: " << statSimple.sumOperationCounter << '\n';
  325.     cout << '\n';
  326.    
  327.     cout << "fft:\n";
  328.     auto [spentTimeFFT, statFFT, resultFFT] = calculateConvolutionWithFFT(a, b);
  329.     cout << spentTimeFFT << " ms.\n";
  330.     cout << "Mult operations: " << statFFT.multOperationCounter << '\n';
  331.     cout << "Sum operations: " << statFFT.sumOperationCounter << '\n';
  332.    
  333.     cout << "Differ fft - simple: " << calculateDelta(resultSimple, resultFFT) << '\n';
  334.     cout << '\n';
  335.  
  336.     cout << "fht:\n";
  337.     auto [spentTimeFHT, statFHT, resultFHT] = calculateConvolutionWithFHT(a, b);
  338.     cout << spentTimeFHT << " ms.\n";
  339.     cout << "Mult operations: " << statFHT.multOperationCounter << '\n';
  340.     cout << "Sum operations: " << statFHT.sumOperationCounter << '\n';
  341.    
  342.     cout << "Differ fht - simple: " << calculateDelta(resultSimple, resultFHT) << '\n';
  343.     cout << '\n';
  344.    
  345.     cout << "dht:\n";
  346.     auto [spentTimeDHT, statDHT, resultDHT] = calculateConvolutionWithDHT(a, b);
  347.     cout << spentTimeDHT << " ms.\n";
  348.     cout << "Mult operations: " << statDHT.multOperationCounter << '\n';
  349.     cout << "Sum operations: " << statDHT.sumOperationCounter << '\n';
  350.    
  351.     cout << "Differ dht - simple: " << calculateDelta(resultSimple, resultDHT) << '\n';
  352.     cout << '\n';
  353.   }
  354. }
  355.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement