• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 class Vector {
2    std::vector<double> k;
3    int N;
4 public:
Vector(int size)5    explicit Vector(int size): k(size) {
6       N = size;
7       for (int i = 0; i < N; i++)
8          k[i] = 0.0;
9    }
10 
GetSize()11    inline int GetSize() const { return N; }
12 
13    inline double& operator[] (int ix) {
14       CHECK(ix < N && ix >= 0);
15       return k[ix];
16    }
17 
18    inline const double& operator[] (int ix) const {
19       CHECK(ix < N && ix >= 0);
20       return k[ix];
21    }
22 
23    inline Vector operator+ (const Vector & other) const {
24       CHECK(other.GetSize() == N);
25       Vector ret(N);
26       for (int i = 0; i < N; i++)
27          ret[i] = k[i] + other[i];
28       return ret;
29    }
30 
31    inline Vector operator- (const Vector & other) const {
32       CHECK(other.GetSize() == N);
33       Vector ret(N);
34       for (int i = 0; i < N; i++)
35          ret[i] = k[i] - other[i];
36       return ret;
37    }
38 
39    inline Vector operator* (double factor) const {
40       Vector ret(N);
41       for (int i = 0; i < N; i++)
42          ret[i] = k[i] * factor;
43       return ret;
44    }
45 
DotProduct(const Vector & other)46    inline double DotProduct (const Vector & other) const {
47       CHECK(other.GetSize() == N);
48       double ret = 0.0;
49       for (int i = 0; i < N; i++)
50          ret += k[i] * other[i];
51       return ret;
52    }
53 
Len2()54    inline double Len2 () const {
55       double ret = 0.0;
56       for (int i = 0; i < N; i++)
57          ret += k[i] * k[i];
58       return ret;
59    }
60 
Len()61    inline double Len () const { return sqrt(Len2()); }
62 
ToString()63    string ToString () const {
64       char temp[1024] = "(";
65       for (int i = 0; i < N; i++)
66          sprintf(temp, "%s%s%.1lf", temp, i == 0 ? "" : ", ", k[i]);
67       return (std::string)temp + ")";
68    }
69 
Copy(const Vector & from)70    inline void Copy(const Vector & from) {
71       CHECK(from.GetSize() == N);
72       for (int i = 0; i < N; i++)
73          k[i] = from[i];
74    }
75 };
76 
77 class Matrix {
78    int M;
79    std::vector<double*> data;
80 public:
81    /*
82     * This matrix can grow its "N" i.e. width
83     * See http://en.wikipedia.org/wiki/Matrix_(mathematics)
84     */
85 
Matrix(int M_,int N)86    Matrix (int M_, int N) {
87       M = M_;
88       for (int i = 0; i < N; i++) {
89          IncN();
90       }
91    }
92 
~Matrix()93    ~Matrix() {
94       for (int i = 0; i < data.size(); i++)
95          delete [] data[i];
96    }
97 
GetM()98    inline int GetM() const { return M; }
99 
GetN()100    inline int GetN() const { return data.size(); }
IncN()101    inline void IncN() {
102       double * k = new double[M];
103       for (int i = 0; i < M; i++)
104          k[i] = 0.0;
105       data.push_back(k);
106    }
107 
108 
At(int i,int j)109    inline double& At(int i, int j) {
110       CHECK(i < M && i >= 0);
111       CHECK(j < data.size() && j >= 0);
112       // Note the reverse order of indices!
113       return data[j][i];
114    }
115 
At(int i,int j)116    inline const double& At(int i, int j) const {
117       CHECK(i < M && i >= 0);
118       CHECK(j < data.size() && j >= 0);
119       // Note the reverse order of indices!
120       return data[j][i];
121    }
122 
MultiplyRight(const Vector & v)123    Vector MultiplyRight (const Vector & v) const {
124       int N = data.size();
125       CHECK(v.GetSize() == N);
126       Vector ret(M);
127       for (int i = 0; i < M; i++)
128          for (int j = 0; j < N; j++)
129             ret[i] += v[j] * At(i,j);
130       return ret;
131    }
132 
MultiplyLeft(const Vector & v_to_transpose)133    Vector MultiplyLeft (const Vector & v_to_transpose) const {
134       int N = data.size();
135       CHECK(v_to_transpose.GetSize() == M);
136       Vector ret(N);
137       for (int i = 0; i < M; i++)
138          for (int j = 0; j < N; j++)
139             ret[j] += v_to_transpose[i] * At(i,j);
140       return ret;
141    }
142 
ToString()143    string ToString() const {
144       string ret = "";
145       for (int i = 0; i < M; i++) {
146          ret += "[";
147          for (int j = 0; j < GetN(); j++) {
148             char temp[128] = "";
149             sprintf(temp, "%s%.1lf", j == 0 ? "" : ", ", At(i,j));
150             ret += temp;
151          }
152          ret += "]\n";
153       }
154       return ret;
155    }
156 };
157 
158 Vector EstimateParameters(const Matrix & perf_m, const Vector & stats_v, double rel_diff, int * iter_count = NULL)
159 {
160    /*
161     *  Goal: find Vector<N> parameters:
162     *   (perf_m * parameters - stats_v)^2 -> min
163     * With the following limitations:
164     *    parameters[i] >= 0
165     * "Stop rule":
166     *    for every i=0...M
167     *    -> |stats_v[i] - (perf_m * parameters)[i]| < rel_diff * stats_v[i]
168     * Algorithm used is a gradient descend
169     */
170    int N = perf_m.GetN(), M = perf_m.GetM();
171    CHECK(stats_v.GetSize() == M);
172    Vector current(N);
173 
174    // First, let's find out those lines in matrix having only one non-zero coefficient
175    // and if we have any, decrease the dimension of our matrix
176    {
177       int count_easy_param = 0;
178       std::vector<int> parameters_set(N); // N (line#) -> M (row#) of the only nonzero element; -1 if 0/2+
179       for (int n = 0; n < N; n++) {
180          parameters_set[n] = -1;
181       }
182       // we may detect & assert unresolvable conflicts like the following
183       // |1|       |1|
184       // |1| * p = |2|
185       // |1|       |3|
186 
187       // Find out those 0000*0000 lines
188       for (int m = 0; m < M; m++) {
189          int zero_id = -1; // -1 = not found, -2 = found twice, else - idx
190          for (int n = 0; n < N; n++) {
191             const double & m_n = perf_m.At(m,n);
192             if (m_n != 0.0) {
193                if (zero_id == -1) {
194                   zero_id = n;
195                } else if (zero_id >= 0) {
196                   zero_id = -2;
197                   break;
198                }
199             }
200          }
201          if (zero_id >= 0) {
202             CHECK(parameters_set[zero_id] == -1);
203             parameters_set[zero_id] = m;
204             count_easy_param++;
205             current[zero_id] = stats_v[m] / perf_m.At(m, zero_id);
206          }
207       }
208 
209       if (count_easy_param > 0) {
210          //printf("tmp = %s\n", current.ToString().c_str());
211 
212          //printf("\n\nDecreasing the dimensions!\n");
213          std::vector<int> new_m_to_old(M - count_easy_param),
214                           new_n_to_old(N - count_easy_param);
215          for (int m = 0; m < M - count_easy_param; m++) {
216             // see increments later
217             new_m_to_old[m] = m;
218          }
219          int cur_n = 0;
220          for (int n = 0; n < N; n++) {
221             if (parameters_set[n] == -1) {
222                new_n_to_old[cur_n] = n;
223                cur_n++;
224             } else {
225                for (int m = parameters_set[n]; m < M - count_easy_param; m++) {
226                   new_m_to_old[m]++;
227                }
228             }
229          }
230 
231          Vector auto_stats = perf_m.MultiplyRight(current), // we have these stats for sure ...
232                 diff_stats = stats_v - auto_stats; // ... and we need to get these stats more
233 
234          // Formulate the sub-problem (sub-matrix & sub-stats)
235          Matrix new_m(M - count_easy_param, N - count_easy_param);
236          Vector new_stats(M - count_easy_param);
237          for (int m = 0; m < M - count_easy_param; m++) {
238             new_stats[m] = diff_stats[new_m_to_old[m]];
239             CHECK(new_stats[m] >= 0.0);
240             for (int n = 0; n < N - count_easy_param; n++)
241                new_m.At(m,n) = perf_m.At(new_m_to_old[m], new_n_to_old[n]);
242          }
243 
244          // Solve the submatrix and put the results back
245          Vector new_param = EstimateParameters(new_m, new_stats, rel_diff, iter_count);
246          for (int n = 0; n < N - count_easy_param; n++) {
247             current[new_n_to_old[n]] = new_param[n];
248          }
249          return current;
250       }
251    }
252 
253    bool stop_condition = false;
254    double prev_distance = stats_v.Len2();
255 
256    //printf("Initial distance = %.1lf\n", prev_distance);
257    while (stop_condition == false) {
258       (*iter_count)++;
259       Vector m_by_curr(M);
260       m_by_curr.Copy(perf_m.MultiplyRight(current));
261       Vector derivative(N); // this is actually "-derivative/2" :-)
262       derivative.Copy(perf_m.MultiplyLeft(stats_v - m_by_curr));
263 
264       if (derivative.Len() > 1000.0) {
265          derivative = derivative * (1000.0 / derivative.Len());
266       }
267 
268       // Descend according to the gradient
269       {
270          Vector new_curr(N);
271          double step = 1024.0;
272          double new_distance;
273          for (int i = 0; i < N; i++) {
274             if (current[i] + derivative[i] * step < 0.0) {
275                step = - current[i] / derivative[i];
276             }
277          }
278          do {
279             new_curr = current + derivative*step;
280             step /= 2.0;
281             new_distance = (perf_m.MultiplyRight(new_curr) - stats_v).Len2();
282             if (step < 0.00001) {
283                stop_condition = true;
284             }
285             (*iter_count)++;
286          } while (new_distance >= prev_distance && !stop_condition);
287 
288          prev_distance = new_distance;
289          current = new_curr;
290          //printf ("Dist=%.1lf, cur=%s\n", new_distance, current.ToString().c_str());
291       }
292 
293       // Check stop condition
294       if (stop_condition == false)
295       {
296          stop_condition = true;
297          Vector stats_est(M);
298          stats_est.Copy(perf_m.MultiplyRight(current));
299          for (int i = 0; i < M; i++)
300             if (fabs(stats_v[i] - stats_est[i]) > rel_diff * stats_v[i])
301                stop_condition = false;
302       }
303    }
304 
305    return current;
306 }
307