Skip to content

Commit 69140b5

Browse files
committed
Fix the two piecewise-linear regression calculation
#66 The current implementation of the regression calculation has these flaws: When processing (x[0], y[0]), L1 must be any line through (x[0], y[0]) which meets L2 at a point (x’, y’) where x[0] < x' < x[1]. L1 has no error. When processing (x[n - 2], y[n - 2]), L2 must be any line through (x[n - 1], y[n - 1]) which meets L1 at a point (x’, y’) where x[n - 2] < x' < x[n - 1]. L2 has no error. The lambda calculation is incorrect. It includes a term called H which is equal to C - I. Looking at the algorithm of Kundu/Ubhaya, this should be just C. lambda should to be used with calculating L1 and (1 - lambda) should to be used with calculating L2. Currently (1 - lambda) is used in calculating L1 and L2. The current calculation has this condition if (t1 != t2) continue; This condition is almost always true even if t1 and t2 are essentiallyEqual.
1 parent 1a99525 commit 69140b5

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

MotionMark/resources/runner/motionmark.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,11 @@
162162
var calculation = regressionResult.regression;
163163
result[Strings.json.complexity] = {};
164164
result[Strings.json.complexity][Strings.json.regressions.segment1] = [
165-
[regressionResult.minComplexity, calculation.s1 + calculation.t1 * regressionResult.minComplexity],
166-
[calculation.complexity, calculation.s1 + calculation.t1 * calculation.complexity]
165+
[regressionResult.minComplexity, desiredFrameLength],
166+
[calculation.complexity, desiredFrameLength]
167167
];
168168
result[Strings.json.complexity][Strings.json.regressions.segment2] = [
169-
[calculation.complexity, calculation.s2 + calculation.t2 * calculation.complexity],
169+
[calculation.complexity, desiredFrameLength],
170170
[regressionResult.maxComplexity, calculation.s2 + calculation.t2 * regressionResult.maxComplexity]
171171
];
172172
result[Strings.json.complexity][Strings.json.complexity] = calculation.complexity;

MotionMark/resources/statistics.js

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ Regression = Utilities.createClass(
195195
e: Number.MAX_VALUE
196196
};
197197

198+
this.complexity = 0;
199+
198200
if (options.preferredProfile == Strings.json.profiles.flat) {
199201
this._calculateRegression(samples, {
200202
s1: options.desiredFrameLength,
@@ -213,7 +215,6 @@ Regression = Utilities.createClass(
213215
this.startIndex = Math.min(startIndex, endIndex);
214216
this.endIndex = Math.max(startIndex, endIndex);
215217

216-
this.complexity = this._complexity();
217218
this.s1 = this.segment1.s;
218219
this.t1 = this.segment1.t;
219220
this.s2 = this.segment2.s;
@@ -242,10 +243,30 @@ Regression = Utilities.createClass(
242243
return this.segment1.e + this.segment2.e;
243244
},
244245

245-
_setOptimal: function(segment1, segment2, options) {
246+
_areEssentiallyEqual: function(n1, n2) {
247+
const epsilon = 0.001;
248+
return Math.abs(n1 - n2) < epsilon;
249+
},
250+
251+
_setOptimal: function(segment1, segment2, xp, x, options) {
246252
if (segment1.e + segment2.e > this.segment1.e + this.segment2.e)
247253
return false;
248254

255+
let complexity = this._complexity();
256+
if (!this._areEssentiallyEqual(this.segment1.t, this.segment2.t)) {
257+
// If segment1 and segment2 are not parallel, then they have to meet
258+
// at complexity such that xp < complexity < x.
259+
if (!(complexity >= xp && complexity <= x))
260+
return false;
261+
} else {
262+
// If segment1 and segment2 are parallel, then they have to form one
263+
// single line.
264+
if (!this._areEssentiallyEqual(this.segment1.s, this.segment2.s))
265+
return false;
266+
}
267+
268+
this.complexity = complexity;
269+
249270
this.segment1.s = options.s1 !== undefined ? options.s1 : segment1.s;
250271
this.segment1.t = options.t1 !== undefined ? options.t1 : segment1.t;
251272
this.segment1.e = segment1.e;
@@ -330,9 +351,10 @@ Regression = Utilities.createClass(
330351

331352
let segment1;
332353
let segment2;
354+
let xp = (j == 0) ? 0 : sortedSamples[j - 1][complexityIndex];
333355

334356
if (j == 0) {
335-
// Let segment1 be any line through (x0, y0) which meets segment2 at
357+
// Let segment1 be any line through (x[0], y[0]) which meets segment2 at
336358
// a point (x’, y’) where x[0] < x' < x[1]. segment1 has no error.
337359
let xMid = (x + sortedSamples[j + 1][complexityIndex]) / 2;
338360
let yMid = s2 + t2 * xMid;
@@ -373,16 +395,18 @@ Regression = Utilities.createClass(
373395
};
374396
}
375397

376-
if (this._setOptimal(segment1, segment2, options))
398+
if (this._setOptimal(segment1, segment2, xp, x, options))
377399
continue
378400

401+
// These values remove the influence of this sample
379402
let G = A + B * x - C * y;
380-
let H = D + E * x - F * y;
403+
let J = D + E * x - F * y;
381404

382405
let I = c1 - 2 * b1 * x + a1 * xx;
383406
let K = c2 - 2 * b2 * x + a2 * xx;
384407

385-
let lambda = (G * F + G * K - H * C) / (I * H + G * K);
408+
// Calculate lambda, which divides the weight of this sample between the two lines
409+
let lambda = (G * F + G * K - J * C) / (I * J + G * K);
386410
if (!(lambda > 0 && lambda < 1))
387411
continue;
388412

@@ -402,7 +426,7 @@ Regression = Utilities.createClass(
402426
e: (k2 + a2 * s2 * s2 + c2 * t2 * t2 - 2 * d2 * s2 - 2 * h2 * t2 + 2 * b2 * s2 * t2) + lambda1 * Math.pow(y - (s2 + t2 * x), 2)
403427
};
404428

405-
this._setOptimal(segment1, segment2, options);
429+
this._setOptimal(segment1, segment2, xp, x, options);
406430
}
407431
}
408432
});

0 commit comments

Comments
 (0)