Hiho! Ich wollte den Max-Lloyd-Algorithmus zur Optimalquantisierung in
C++ implementieren.
Allerdings wollte ich nicht über die Integration der
Wahrscheinlichkeitsdichteverteilung gehen sondern habe den Algorithmus
wie folgt abgewandelt:
Wiederhole:
* ordne jedem Trainigssample den Rekonstruktionswert zu, der ihm am
nächsten liegt.
* berechne die Rekonstruktionswerte als Mittelwert der ihnen
zugeordneten Samples.
Die Ergebnisse sehen für laplaceverteilte Daten schon ganz gut aus,
allerdings nicht mehr für einen Sinus als Eingangssignal. Dort müßten
sich die Rekonstruktionswerte eigentlich im Bereich der großen
Amplituden konzentrieren, was sie aber nicht wirklich tun.
1 | template<class T> bool MaxLloydQuantizer<T>::train(const itpp::Vec<T> &trainingdata,double epsilon,unsigned int max_iter)
|
2 | {
|
3 | #ifdef DEBUG
|
4 | if(!initialized) cerr << "MaxLloydQuantizer<T>::train() called before initializing the quantizer!" << endl;
|
5 | #endif
|
6 | if(trainingdata.length()==0) return false;
|
7 | T minv,maxv;
|
8 | minv=maxv=trainingdata(0);
|
9 | for(const T* ptr=trainingdata._data();ptr < trainingdata._data()+trainingdata.length();ptr++)
|
10 | {
|
11 | register T val = *ptr;
|
12 | minv = ((val < minv) ? val : minv);
|
13 | maxv = ((val > maxv) ? val : maxv);
|
14 | }
|
15 |
|
16 | // berechne nun die Intervallgrenzen eines gleichverteilten Quantisierers
|
17 | T step=(maxv-minv)/N;
|
18 | T w=minv;
|
19 | for(unsigned int k=0;k<=N;k++,w+=step) d(k)=w;
|
20 | w=minv+step/2;
|
21 | for(unsigned int k=0;k<N;k++,w+=step) r(k)=w;
|
22 |
|
23 | itpp::Vec<T> r_neu(N);
|
24 | itpp::Vec<unsigned int> r_anz(N);
|
25 |
|
26 | unsigned int iteration=0;
|
27 | for(;iteration < max_iter;iteration++)
|
28 | {
|
29 | // ordne jedem Trainingswert einen Rekonstruktionswert zu
|
30 | for(int k=0;k<trainingdata.length();k++)
|
31 | {
|
32 | T val=trainingdata(k);
|
33 | T min_dist=std::abs(r(0)-val);
|
34 | unsigned min_index=0;
|
35 | for(unsigned int l=1;l<N;l++)
|
36 | {
|
37 | T dist=std::abs(T(r(l)-val));
|
38 | if(dist < min_dist)
|
39 | {
|
40 | min_dist=dist;
|
41 | min_index=l;
|
42 | }
|
43 | }
|
44 | r_neu(min_index)+=val;
|
45 | r_anz(min_index)++;
|
46 | }
|
47 | double change=0.0;
|
48 | for(unsigned int k=0;k<N;k++)
|
49 | {
|
50 | double r_neuw = (r_anz(k) != 0 ? r_neu(k)/r_anz(k) : r(k));
|
51 | double tmp=r_neuw-r(k);
|
52 | change+=tmp*tmp;
|
53 | r(k)=r_neuw;
|
54 | }
|
55 |
|
56 | if(change/N <= epsilon) break;
|
57 | r_neu.clear();
|
58 | r_anz.clear();
|
59 | }
|
60 | // berechne Intervallgrenzen neu
|
61 |
|
62 | for(unsigned int i=1;i<N;i++)
|
63 | {
|
64 | T di_neu=(r(i-1)+r(i))/2;
|
65 |
|
66 | d(i)=di_neu;
|
67 | }
|
68 | trained=true;
|
69 | return (iteration!=max_iter);
|
70 | }
|