Added fft() and ifft()

This commit is contained in:
Davis King 2013-04-20 12:57:24 -04:00
parent cd5147b200
commit e9a66e030b
6 changed files with 553 additions and 0 deletions

View File

@ -12,6 +12,7 @@
#include "matrix/symmetric_matrix_cache.h"
#include "matrix/matrix_conv.h"
#include "matrix/matrix_read_from_istream.h"
#include "matrix/matrix_fft.h"
#ifdef DLIB_USE_BLAS
#include "matrix/matrix_blas_bindings.h"

258
dlib/matrix/matrix_fft.h Normal file
View File

@ -0,0 +1,258 @@
// Copyright (C) 2013 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_FFt_H__
#define DLIB_FFt_H__
#include "matrix_fft_abstract.h"
#include "matrix_utilities.h"
#include "../hash.h"
#include "../algs.h"
#ifdef DLIB_USE_FFTW
#include <fftw3.h>
#endif // DLIB_USE_FFTW
namespace dlib
{
// ----------------------------------------------------------------------------------------
namespace impl
{
inline unsigned long reverse_bits (
unsigned long val,
unsigned long num
)
{
unsigned long temp = 0;
for (unsigned long i = 0; i < num; ++i)
{
temp <<= 1;
temp |= val&0x1;
val >>= 1;
}
return temp;
}
template <typename T, long NR, long NC, typename MM, typename L>
void permute (
const matrix<std::complex<T>,NR,NC,MM,L>& data,
matrix<std::complex<T>,NR,NC,MM,L>& outdata
)
{
outdata.set_size(data.size());
if (data.size() == 0)
return;
const unsigned long num = static_cast<unsigned long>(std::log(data.size())/std::log(2.0) + 0.5);
for (unsigned long i = 0; i < (unsigned long)data.size(); ++i)
{
outdata(impl::reverse_bits(i,num)) = data(i);
}
}
}
// ----------------------------------------------------------------------------------------
inline bool is_power_of_two (
const unsigned long& value
)
{
if (value == 0)
return true;
else
return count_bits(value) == 1;
}
// ----------------------------------------------------------------------------------------
template <typename T, long NR, long NC, typename MM, typename L>
matrix<std::complex<T>,NR,NC,MM,L> fft (
const matrix<std::complex<T>,NR,NC,MM,L>& data
)
{
if (data.size() == 0)
return data;
// make sure requires clause is not broken
DLIB_CASSERT(is_vector(data) && is_power_of_two(data.size()),
"\t void ifft(data)"
<< "\n\t data must be a vector with a size that is a power of two."
<< "\n\t is_vector(data): " << is_vector(data)
<< "\n\t data.size(): " << data.size()
);
matrix<std::complex<T>,NR,NC,MM,L> outdata(data);
const long half = outdata.size()/2;
typedef std::complex<T> ct;
matrix<ct,0,1,MM,L> twiddle_factors(half);
// compute the complex root of unity w
const T temp = -2.0*pi/outdata.size();
ct w = ct(std::cos(temp),std::sin(temp));
ct w_pow = 1;
// compute the twiddle factors
for (long j = 0; j < twiddle_factors.size(); ++j)
{
twiddle_factors(j) = w_pow;
w_pow *= w;
}
// now compute the decimation in frequency. This first
// outer loop loops log2(outdata.size()) number of times
long skip = 1;
for (long step = half; step != 0; step >>= 1)
{
// do blocks of butterflies in this loop
for (long j = 0; j < outdata.size(); j += step*2)
{
// do step butterflies
for (long k = 0; k < step; ++k)
{
const long a_idx = j+k;
const long b_idx = j+k+step;
const ct a = outdata(a_idx) + outdata(b_idx);
const ct b = (outdata(a_idx) - outdata(b_idx))*twiddle_factors(k*skip);
outdata(a_idx) = a;
outdata(b_idx) = b;
}
}
skip *= 2;
}
matrix<std::complex<T>,NR,NC,MM,L> outperm;
impl::permute(outdata, outperm);
return outperm;
}
// ----------------------------------------------------------------------------------------
template <typename T, long NR, long NC, typename MM, typename L>
matrix<std::complex<T>,NR,NC,MM,L> ifft (
const matrix<std::complex<T>,NR,NC,MM,L>& data
)
{
if (data.size() == 0)
return data;
// make sure requires clause is not broken
DLIB_CASSERT(is_vector(data) && is_power_of_two(data.size()),
"\t void ifft(data)"
<< "\n\t data must be a vector with a size that is a power of two."
<< "\n\t is_vector(data): " << is_vector(data)
<< "\n\t data.size(): " << data.size()
);
matrix<std::complex<T>,NR,NC,MM,L> outdata;
impl::permute(data,outdata);
const long half = outdata.size()/2;
typedef std::complex<T> ct;
matrix<ct,0,1,MM,L> twiddle_factors(half);
// compute the complex root of unity w
const T temp = 2.0*pi/outdata.size();
ct w = ct(std::cos(temp),std::sin(temp));
ct w_pow = 1;
// compute the twiddle factors
for (long j = 0; j < twiddle_factors.size(); ++j)
{
twiddle_factors(j) = w_pow;
w_pow *= w;
}
// now compute the inverse decimation in frequency. This first
// outer loop loops log2(outdata.size()) number of times
long skip = half;
for (long step = 1; step <= half; step <<= 1)
{
// do blocks of butterflies in this loop
for (long j = 0; j < outdata.size(); j += step*2)
{
// do step butterflies
for (long k = 0; k < step; ++k)
{
const long a_idx = j+k;
const long b_idx = j+k+step;
outdata(b_idx) *= twiddle_factors(k*skip);
const ct a = outdata(a_idx) + outdata(b_idx);
const ct b = outdata(a_idx) - outdata(b_idx);
outdata(a_idx) = a;
outdata(b_idx) = b;
}
}
skip /= 2;
}
outdata /= outdata.size();
return outdata;
}
// ----------------------------------------------------------------------------------------
#ifdef DLIB_USE_FFTW
inline matrix<std::complex<double>,0,1> fft(
const matrix<std::complex<double>,0,1>& data
)
{
// make sure requires clause is not broken
DLIB_CASSERT(is_vector(data) && is_power_of_two(data.size()),
"\t void fft(data)"
<< "\n\t data must be a vector with a size that is a power of two."
<< "\n\t is_vector(data): " << is_vector(data)
<< "\n\t data.size(): " << data.size()
);
matrix<std::complex<double>,0,1> m2(data.size());
fftw_complex *in, *out;
fftw_plan p;
in = (fftw_complex*)&data(0);
out = (fftw_complex*)&m2(0);
p = fftw_plan_dft_1d(data.size(), in, out, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(p);
fftw_destroy_plan(p);
return m2;
}
inline matrix<std::complex<double>,0,1> ifft(
const matrix<std::complex<double>,0,1>& data
)
{
// make sure requires clause is not broken
DLIB_CASSERT(is_vector(data) && is_power_of_two(data.size()),
"\t void ifft(data)"
<< "\n\t data must be a vector with a size that is a power of two."
<< "\n\t is_vector(data): " << is_vector(data)
<< "\n\t data.size(): " << data.size()
);
matrix<std::complex<double>,0,1> m2(data.size());
fftw_complex *in, *out;
fftw_plan p;
in = (fftw_complex*)&data(0);
out = (fftw_complex*)&m2(0);
p = fftw_plan_dft_1d(data.size(), in, out, FFTW_BACKWARD, FFTW_ESTIMATE);
fftw_execute(p);
fftw_destroy_plan(p);
return m2/data.size();
}
#endif // DLIB_USE_FFTW
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_FFt_H__

View File

@ -0,0 +1,85 @@
// Copyright (C) 2013 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_FFt_ABSTRACT_H__
#ifdef DLIB_FFt_ABSTRACT_H__
#include "matrix_abstract.h"
#include "../algs.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
bool is_power_of_two (
const unsigned long& value
);
/*!
ensures
- returns true if value contains a power of two and false otherwise. As a
special case, we also consider 0 to be a power of two.
!*/
// ----------------------------------------------------------------------------------------
template <
typename T,
long NR,
long NC,
typename MM,
typename L
>
matrix<std::complex<T>,NR,NC,MM,L> fft (
const matrix<std::complex<T>,NR,NC,MM,L>& data
);
/*!
requires
- is_vector(data) == true
- is_power_of_two(data.size()) == true
ensures
- Computes the discrete Fourier transform of the given data vector and
returns it. In particular, we return a matrix D such that:
- D.nr() == data.nr()
- D.nc() == data.nc()
- D(0) == the DC term of the Fourier transform.
- starting with D(0), D contains progressively higher frequency components
of the input data.
- ifft(D) == D
- if DLIB_USE_FFTW is #defined then this function will use the very fast fftw
library when given double precision matrices instead of dlib's default fft
implementation.
!*/
// ----------------------------------------------------------------------------------------
template <
typename T,
long NR,
long NC,
typename MM,
typename L
>
matrix<std::complex<T>,NR,NC,MM,L> ifft (
const matrix<std::complex<T>,NR,NC,MM,L>& data
);
/*!
requires
- is_vector(data) == true
- is_power_of_two(data.size()) == true
ensures
- Computes the inverse discrete Fourier transform of the given data vector and
returns it. In particular, we return a matrix D such that:
- D.nr() == data.nr()
- D.nc() == data.nc()
- fft(D) == data
- if DLIB_USE_FFTW is #defined then this function will use the very fast fftw
library when given double precision matrices instead of dlib's default fft
implementation.
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_FFt_ABSTRACT_H__

View File

@ -44,6 +44,7 @@ set (tests
entropy_coder.cpp
entropy_encoder_model.cpp
example_args.cpp
fft.cpp
filtering.cpp
find_max_factor_graph_nmplp.cpp
find_max_factor_graph_viterbi.cpp

207
dlib/test/fft.cpp Normal file
View File

@ -0,0 +1,207 @@
// Copyright (C) 2013 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#include <sstream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <dlib/matrix.h>
#include <dlib/rand.h>
#include <dlib/compress_stream.h>
#include <dlib/base64.h>
#include "tester.h"
namespace
{
using namespace test;
using namespace dlib;
using namespace std;
logger dlog("test.fft");
// ----------------------------------------------------------------------------------------
matrix<complex<double> > rand_complex(long num)
{
static dlib::rand rnd;
matrix<complex<double> > m(num,1);
for (long i = 0; i < m.size(); ++i)
{
m(i) = complex<double>(rnd.get_random_gaussian()*10, rnd.get_random_gaussian()*10);
}
return m;
}
const std::string get_decoded_string();
void test_against_saved_good_ffts()
{
print_spinner();
istringstream sin(get_decoded_string());
matrix<complex<double>,0,1> m1, m2;
matrix<complex<float>,0,1> fm1, fm2;
while (sin.peek() != EOF)
{
deserialize(m1,sin);
deserialize(m2,sin);
fm1 = matrix_cast<complex<float> >(m1);
fm2 = matrix_cast<complex<float> >(m2);
DLIB_TEST(max(norm(fft(m1)-m2)) < 1e-16);
DLIB_TEST(max(norm(m1-ifft(m2))) < 1e-16);
DLIB_TEST(max(norm(fft(fm1)-fm2)) < 1e-7);
DLIB_TEST(max(norm(fm1-ifft(fm2))) < 1e-7);
}
}
// ----------------------------------------------------------------------------------------
void test_random_ffts()
{
print_spinner();
for (int iter = 0; iter < 10; ++iter)
{
for (int size = 1; size <= 64; size *= 2)
{
const matrix<complex<double>,0,1> m1 = rand_complex(size);
const matrix<complex<float>,0,1> fm1 = matrix_cast<complex<float> >(rand_complex(size));
DLIB_TEST(max(norm(ifft(fft(m1))-m1)) < 1e-16);
DLIB_TEST(max(norm(ifft(fft(fm1))-fm1)) < 1e-7);
}
}
}
// ----------------------------------------------------------------------------------------
class test_fft : public tester
{
public:
test_fft (
) :
tester ("test_fft",
"Runs tests on the fft routines.")
{}
void perform_test (
)
{
test_against_saved_good_ffts();
test_random_ffts();
}
} a;
// ----------------------------------------------------------------------------------------
// This function returns the contents of the file 'fft_test_data.dat'
const std::string get_decoded_string()
{
dlib::base64 base64_coder;
dlib::compress_stream::kernel_1ea compressor;
std::ostringstream sout;
std::istringstream sin;
// The base64 encoded data from the file 'fft_test_data.dat' we want to decode and return.
sout << "gO1l2wKz8OsyeYMPYcGx6QdBG65vnrB+omgAJ7Bnsuk9vkTw/Y9Y/UZEFXhVf6qnq92QHPLV16Fo";
sout << "a+IUHNTjoPAfBOTyfb8QRcTj9SaWpxA65+UCJ+5L6x/TEyPKDtB23S0KRpRSdfxBSW9/rnUrkIv7";
sout << "6i6LWcxKzdsw2WGsRCX1k3t0adQW49m/yb8LV9Loqs7/phzY7HkJ4D2PLtpc6Wyk1qG/h6KQ7nkF";
sout << "GFkHIoh+xKXhHpqWaSofx8H8m/++H++g0VSPqfQ1ktFz+K8UtiGoyR2GqpP+br47YLXG3WqVU5Km";
sout << "Di3+IjQoBH2m4jykD926aRvdRrgUH4gZunokl+U6shv20Zm0NL8j4A46/2f++YPGCVBNJJmcJdI7";
sout << "9RlPL9SFbJ8rnH5bbLvZ2pKZmmbeZN78yzLUhdGwn4DGpf/Zo1fU2YPUjVKkwY6olW4w3tiBl05a";
sout << "cS1HwBeQjnajqsXNyudbrBkM1Z9XiwM+J5iMsu5ldaJ8iLn30W2Te2RnZhJRHO8MgL7Fn1j0n0Qb";
sout << "8dB+6aQYv0l/5LQkr5SX6YSRYX5b5rnqhi8IzJKms6dzoyBm97IGTm8pRxtLXcmsk1MvJcHF2gl2";
sout << "CslQazsl5iIS6fMxEodmlMdwdfIpp/6MqmeIydSHwdyJJZnNPl2p5X+Il5egmwdaSoDQNphPfTaQ";
sout << "R0Xh3xqsZKgHLKxB14Rsf/R7Eu9ZASTByX3UrEHsSzLSUo9/G+tS3n1iC30Liusksh2Wkt+/QtDy";
sout << "A1ZX31H5OlSFwCYC/TYitwyl4U9k7WhHBDoT7MdmVTYQEK1dK48nwOhnZa9prE8n3dD40CCe25q3";
sout << "Qo4VVYc5tBWu1TfTbshvkmHAcp3Gyw/caqq6jdq5Z2BD1b67i/bY66xhmowOFS8xeA7v6tKdkvpp";
sout << "Rk8FegzVdB72wpw3872T4K+eplMDcCPGkwIieF5pZStWxhGsNOC0p2wvpFvTpQgfNOGUvRt69hsd";
sout << "xaUEYlWZcY3sfsiOwPGgBUEEv6b+8W7+8Ddj8Nx4wG+bdWozphfz7THbmOeaDM63imIEHmJbZ47I";
sout << "QgoyzFD5WoWtZ1wMEv4LL+a63B3FzBcvPvdPaa2QEmyiK9yN7GEePs2Fv2A3ymhGw5NeR1dOzAjz";
sout << "lEQW01p8opk/dpyLO18zj8d+Hn4EnJkKD0p1u+XuLRda8AnRu/WmSOOpyG5EUrUoEyuvbECLbY9X";
sout << "3AMgzkbxltmZlkyOOwfCGM0yumGYKdz0aGKdyid7ddLMTpQ908dCNLyRgTybdZG9137PQirgX5+O";
sout << "08T/+L4EIyyrslOYxpUaLm2ASnSUgiivoIJvfnu8IeH2W9fPupY89ioXIYuwZU8f9FDCA9z7peQw";
sout << "9H6l4PDdDrB7nwQhncpV9FYLkHQLbSgE1VD+eL6Y2k48pI2zUndcoHEZW72NcmK6E8fDvfgbKkYD";
sout << "m02RiGuj4tvEEsIVuVa29Q0JGO+37n7Mlz7+RMcUMo1pLnh+jibas6R+1LCy7b4ubiKMFB1gvjut";
sout << "gjMABy1dJxSOdb9xUa0K/Alwwu3MxdkrbTxwqkn0C2JnVV7z9S2I+PWcfZKzcpg8Itzh/ON6I/DE";
sout << "EGK3s39XhLI2xPg3PE9R9QMaisqxb3FeP1NkBXrLQtuQfrSk+KZk6ArQWVgtem799fxgipQsa5RH";
sout << "z2Dq9t+pJzNGUnWg5PWzaAY3lWMscn+BIRhsZfDJ3QBtS9Vmib8r2dtYwXi/Q+FhnAHFfcXbhDC3";
sout << "GHn16aP2PY1sw8KMtfPRAcqY8Ylbr9EQXjWoIYUs0YyX2Ks8ZgibunTPFz/Wu98RVYswMtjubFaJ";
sout << "jb0pK9S6qoe/w10CAAHqoAfca7uMOxw9trZZmjCf5vF4leH/nDgsNjesYn21rE6rLhSbg8vaZXo5";
sout << "I/e1uhZlRz4ZNnMlZSnL70Jt0IjuR0YNphCsGZjmvvZ4ihxrcLrHvAcSTJuqW5EARtvjyQWqBKSP";
sout << "5XhlkrI73Ejvy+Lhv6n6O7+VrfWa/tGRuvvAToS1wPOP1T2oniDXsNlD0QbMnCao+dTWgkTDiNTk";
sout << "sFxsoN8YjwHqYUAp+hfnu1Vh2ovyemAUmo87vuG7at6f8MgFSuZffmBkGuijKNDDy7OrHoh7+5/+";
sout << "aOkcvp0pW3ONZ4l6peRNvzaW5DEBTvcZGvRwVCHWII1eGpzeJKaHWvDfLqjaPkFrG5pR7SGCY/9L";
sout << "73W2U0JCe2h7VjWbCM7hdvJEgYi/mEarVQpt+0P834es6Rm9rsMCbgbrWl7uv35+LVMTHU29Oxln";
sout << "bDzBUJQs5KIA81IWR3R7D+HuJvpMkAYMF73c1owI7K74SBOsTq1ayC81aNlK7YwOOjZyBqwsQ5sy";
sout << "zZi0k9AcKRGmTC323o7Tp/n/gkAU3NObTnqPEJitjGloXqrhPvorixBhHXSZy+wgL5R+04KiF1uU";
sout << "LEFOzJ0zKUMstTB+fgC7D6ZnVEtUq3HEYnmaRRwEhRSgMTLXE8VvnOdo802pMVN5GMCkH299rJm5";
sout << "Ina8mTwlC9JrNuYHot5KK/Gny4KPyUeS51cifByPwroemwBHe9EmKCkcEJPoDpG3QMaV36aopyJl";
sout << "GwhZxaZSqbut9XSWr0IMxHUkFeslRB+n/7Vx+xWpDNjQ7JA5S/B0ZW+YBQPcjA3sRQTey25JD4Jy";
sout << "RsULxNY5e3mjn59fI8OpBOYfNPTt2Jzppm1GDpym0LHuz7KZ6xk6QAyogk+HMjC/5RcQA7zJWDRM";
sout << "dXC4CXUjrBxVzmm/YHXv76LrsaFdzJgn+/qzlM6IvIgicMhcJl+hA1swTkgcw6JRalJiDqnvapKP";
sout << "V+T+/X5PSNMswgZURHQJ2l0PkMrUT909pBOC9t4GCsK8k4rYS2o0I0UYfcpm4jMRU5X34zlT8Qv+";
sout << "GV3mA0oGq1U2dJwArlPX3gI5sZ2Jsw7Qa5edvQNG5GoRb2j2Muo4AkZXXjbx0KEa5leLIhVL4BAE";
sout << "2GTdbL7T8hUGY3QlRQGwSVAytjUfXg4jCyn9w6ZbxUOu5MDBuCEtrhRSJNKuBLInK3Bh+fr2FshC";
sout << "T1eDtIFE2EDEaSbLj4NCNWpTFdKMXZ9CQg2VtoVOIJfgKzqAjjcWX8kqWpMFlQgtdTfIqN7gnFit";
sout << "do/FO0OzLghevyexHdl+Ze+MjITKOF0mTPPMkcIYcINIR1za6q3rLDZg03+GouzYhL8lwM3WAnkg";
sout << "Qg+NM6reQATKFK3ieOxacZYnIwOR/ZMM/lO/rHY/ZbdAnJHbMBWwRtK1vDi+o+ZgS7EgsDpsmz/l";
sout << "PguXPK0Ws51OUhIJJ5YDBv+nVPJabxOYV3dU0z49xFpxNTW9pTISo8mKZvLp2D765kExGJ9YKoAx";
sout << "Hfi6WEg3pFS9YQLNhOZjE4bQThugIWXhi+2OPgqUIUoV5ctSnP5Lv+xhbkZfjnQQQQffrrU4peSz";
sout << "6CuNEVLuNuG/mc3WEDZwf1HxYv3u9pr7A79QG0EROf23zPzaf5biE9e9xH+ruPApRHM58H2RpxXU";
sout << "RlkYnfoAUqyvT3Lhhk6ngv8Axhi4otvz7sRiXQmZO7mtzWzsCTkCJoziwRKlD6P6LYnbm4fRYP1M";
sout << "MvOuW3NhsQNrsDtgMuvqiVQpRzg157ES1i1qnTjJxTD5emK1RljuQEetbGksyetctWdWiEd8ZfSh";
sout << "DHBJC2FLucmkMt0LHsVPnk4ni055uMRdKPRKjTE2MjpEsxR52xiWR3MtwXiEhH9fZnUl1IdBl3PG";
sout << "TfLiZ286m4ePm6JOgNM1chtZir+q8pr4ghk/xycWvHmgkqT9dQcFP8iEtlVLCS22/2mS79cTev2r";
sout << "yE90otp9vibcTnpORzrnLrMhhpmYRTxRjRaHGhwdJYluARJFBBVTMEenK2ubdLOJ8skZjLzPv1dt";
sout << "9IrO1sNUwrMpEie8PG7D7DzQ7//jdlC/HUZaGKrwj5aMUULi+ZYiBLYoeL4N8ozAK1u3KtXLKlRE";
sout << "3Akys4Py8+CmrY5qaaDOXZvwl3FF3skmGhx5KValRXrbndqr3Cks0hXglHgNonZh795galZwu0Jp";
sout << "ww/mTQLCV0djTdEfjXBUnP49zyGXWWsEsl2jfqEAfBDcT4+mMzAUtBSwwPJYXXAJQz45R32MThNb";
sout << "k21X+rw63QJe0zIbOJepHz3jaedMkj8GKNYBjqzibNqfYelunBUqW0bpi81HYdN5OFY/3GNKgygG";
sout << "4R5HJaP+x9e1HxehpI/4pKFC+TAIb29uSV5GtkNTb1fYLm0kjeCZNA5GKtf42gBY52N6STl+lcI0";
sout << "gD+jJ/ogknne3sRtEJEtCFFe1c50oikyJamQbeUO1PcDUBt8Phl1rI/p4PTP+H686usJVhSDY+b5";
sout << "9CdS6F7XSSDiXlpFl+Esex30fRZ8zAQsTo9oN0sSZUUJKcyVk0dCqw2mHWPpyM6hYKQ3ij1nYjYl";
sout << "3PzRfFMlu+dgStcBn70jvlEv5pOWXb2OqrN9nJtb29n8jrB2K2nlbcYoPPiQ3yXk+Wpom82LoT5W";
sout << "F9NeNwwAB4EDWtB96OU6noW8NHJj7NiADQJGvQpk/3JzIzeBJQCxULYJMRJdBKf61+24F791reHa";
sout << "qrH+rLUrrv05dIPDTUvGW5LQLTTFFa59OmMIu7WJE7Ln6gMIwDw3FXnGFzaWnHlHL/9jJ0zM1FQL";
sout << "kfK4wTd++GbeI0gsnXWFK0N0kV/FiHm++J4udWwIXZxH7qZCHtwlT/5oGDVujtAtOPag+txUrjVc";
sout << "G4iLeiPbV/2Vfc2D1oV5/yyXDDii9qrLH6SOOfgvdiJZr7X3uMUIDGO75x5wBDSxr9t3I2CrX2dM";
sout << "M6kD7U1+bf5QVRbkh3Us4NAhFVnLNEcrm0x9Yx0wRmxPKgJeGGbWi7/BHi8ShIFllizuxuMyfypC";
sout << "hhzSlxxbYAQwtcC3cHEnyYZAO7HC6hyke+HQJfxAmKyfguGtzEzsiG18XJVruwz7IoOpZS/O71zy";
sout << "Nv+T8trOhy59ZUAgIsCAAQJYEBWl/T/qFtkE+tITbVRKtHjbxHSeN12OnHFRoKguJYaakTo4qLs0";
sout << "fr4E4nZUMfjdF7oI7YutegY9TkiJ9ujLJw4pfY1XRtPrRukEl8orypWXq0gErnYO/RVtK3XImrDp";
sout << "LY5sXH5pNzkqVH9VCl6lh9sg2HWjNwv9bDcDlIhvTL19Mx9yUtx/iQtG/OKy22tW6ByahPNnMNtA";
sout << "tBVB38RLf6eJr68mhn10Qg68cXxVL7/zEIZd9rUaCo8xCzeFblDNErKfG02JJ6fbQ6M6ZdNez7Q0";
sout << "x2IYbz2DEk0wHmR7OtA/oTFMvJlyMt+dDWTEpHnvqkbe+veENpxn2WWy3UsumkvhhtzzmLxyD6Sh";
sout << "mMbMPwgUjvMG51JfRrgMfJzT49z0sebSfzvid/9QV4lNkR7s9nfUJEwAued4S4klRy3LiFdQhjQR";
sout << "FOZZNqUge8vxVOzVCfS+xsjvnGrd7azt7LJg6wPXFgPfeE2bRlx+8AoRFG7SUpudmm/bkNw+uNgS";
sout << "YRdaH8p16RyNoMlSfi/7BNDhtKwrl202pVuCqhFey0mPYehYee2HhLZs6ph+HKMYy8lZ/ac1Q17d";
sout << "1tcI4WH0Hz0B/3GWl8xWfoq2OO40EIjuCPNhk70MpiytWXggJrKoKPu52GOqTU8+jZ6F+u6U2muZ";
sout << "6QZLYXDwPaNz/lq5U4ACw767DkhUHd1/h0g6r/RwtLKxdrzYldQto99TAMmHc+z9aIciTv7kl/Gs";
sout << "WA58nI8aODhwjIkOGaExdlR1k/3JR2tAAj5vRzYlJeakhAA82pA+8xMPZr3HRlQx4DlEjH1spAA=";
// Put the data into the istream sin
sin.str(sout.str());
sout.str("");
// Decode the base64 text into its compressed binary form
base64_coder.decode(sin,sout);
sin.clear();
sin.str(sout.str());
sout.str("");
// Decompress the data into its original form
compressor.decompress(sin,sout);
// Return the decoded and decompressed data
return sout.str();
}
}

View File

@ -59,6 +59,7 @@ SRC += ekm_and_lisf.cpp
SRC += empirical_kernel_map.cpp
SRC += entropy_coder.cpp
SRC += entropy_encoder_model.cpp
SRC += fft.cpp
SRC += filtering.cpp
SRC += find_max_factor_graph_nmplp.cpp
SRC += find_max_factor_graph_viterbi.cpp