Skip to content

Commit 415a046

Browse files
committed
Refactor the mapping to be the same as reference implementation, remove unused implementations
1 parent b06df3c commit 415a046

File tree

14 files changed

+110
-898
lines changed

14 files changed

+110
-898
lines changed

package.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@
3030
"prepack": "yarn build",
3131
"typecheck": "tsc --noEmit"
3232
},
33-
"dependencies": {
34-
"math-float64-frexp": "^1.0.0",
35-
"math-float64-ldexp": "^1.0.1"
36-
},
3733
"devDependencies": {
3834
"@types/jest": "^26.0.14",
3935
"@typescript-eslint/eslint-plugin": "^4.2.0",

src/ddsketch/DDSketch.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,21 @@
66
*/
77

88
import { Bin, DenseStore } from './store';
9-
import { Mapping, LogarithmicMapping } from './mapping';
9+
import { IndexMapping, LogarithmicMapping } from './mapping';
1010

1111
const DEFAULT_RELATIVE_ACCURACY = 0.01;
1212

1313
interface BaseSketchConfig {
1414
/** The mapping between values and indicies for the sketch */
15-
mapping: Mapping;
15+
mapping: IndexMapping;
1616
/** Storage for values */
1717
store: DenseStore;
1818
}
1919

2020
/** Base class for DDSketch*/
2121
class BaseDDSketch {
2222
/** The mapping between values and indicies for the sketch */
23-
mapping: Mapping;
23+
mapping: IndexMapping;
2424
/** Storage for values */
2525
store: DenseStore;
2626
/** The minimum value seen by the sketch */
@@ -52,8 +52,8 @@ class BaseDDSketch {
5252
*/
5353
accept(value: number, weight = 1): void {
5454
if (
55-
value < this.mapping.minPossible ||
56-
value > this.mapping.maxPossible
55+
value < this.mapping.minIndexableValue ||
56+
value > this.mapping.maxIndexableValue
5757
) {
5858
throw new Error(
5959
'Input value is outside the range that is tracked by the sketch'
@@ -64,7 +64,7 @@ class BaseDDSketch {
6464
throw new Error('Weight must be a positive number');
6565
}
6666

67-
const key = this.mapping.key(value);
67+
const key = this.mapping.index(value);
6868
this.store.add(key, weight);
6969

7070
/* Keep track of summary stats */
@@ -136,7 +136,7 @@ class BaseDDSketch {
136136
* @param sketch The sketch to be merged into the caller sketch
137137
*/
138138
mergeable(sketch: DDSketch): boolean {
139-
return this.mapping.gamma === sketch.mapping.gamma;
139+
return this.mapping.equals(sketch.mapping);
140140
}
141141

142142
/*

src/ddsketch/mapping/CubicallyInterpolatedMapping.ts

Lines changed: 0 additions & 86 deletions
This file was deleted.

src/ddsketch/mapping/KeyMapping.ts

Lines changed: 0 additions & 82 deletions
This file was deleted.

src/ddsketch/mapping/LinearlyInterpolatedMapping.ts

Lines changed: 0 additions & 69 deletions
This file was deleted.

src/ddsketch/mapping/LogarithmicMapping.ts

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,57 @@
55
* Copyright 2021 GraphMetrics for modifications
66
*/
77

8-
import { KeyMapping, MIN_INT_16, MAX_INT_16 } from './KeyMapping';
8+
import {
9+
EXP_OVERFLOW,
10+
MAX_INT_16,
11+
MIN_INT_16,
12+
MIN_SAFE_FLOAT,
13+
withinTolerance
14+
} from './helpers';
15+
import { IndexMapping } from './types';
916

1017
/**
1118
* A memory-optimal KeyMapping, i.e., given a targeted relative accuracy, it
1219
* requires the least number of keys to cover a given range of values. This is
1320
* done by logarithmically mapping floating-point values to integers.
1421
*/
15-
export class LogarithmicMapping extends KeyMapping {
16-
constructor(relativeAccuracy: number, offset = 0) {
17-
super(relativeAccuracy, offset);
18-
this._multiplier *= Math.log(2);
19-
this.minPossible = Math.max(
20-
Math.pow(2, (MIN_INT_16 - this._offset) / this._multiplier + 1),
21-
this.minPossible
22+
export class LogarithmicMapping implements IndexMapping {
23+
public readonly relativeAccuracy: number;
24+
public readonly minIndexableValue: number;
25+
public readonly maxIndexableValue: number;
26+
private readonly multiplier: number;
27+
28+
constructor(relativeAccuracy: number) {
29+
this.relativeAccuracy = relativeAccuracy;
30+
this.multiplier =
31+
1 / Math.log1p((2 * relativeAccuracy) / (1 - relativeAccuracy));
32+
this.minIndexableValue = Math.max(
33+
Math.exp(MIN_INT_16 / this.multiplier + 1),
34+
(MIN_SAFE_FLOAT * (1 + relativeAccuracy)) / (1 - relativeAccuracy)
2235
);
23-
this.maxPossible = Math.min(
24-
Math.pow(2, (MAX_INT_16 - this._offset) / this._multiplier - 1),
25-
this.maxPossible
36+
this.maxIndexableValue = Math.min(
37+
Math.exp(MAX_INT_16 / this.multiplier - 1),
38+
Math.exp(EXP_OVERFLOW) / (1 + relativeAccuracy)
2639
);
2740
}
2841

29-
_logGamma(value: number): number {
30-
return Math.log2(value) * this._multiplier;
42+
public index(value: number): number {
43+
const index = Math.log(value) * this.multiplier;
44+
if (index >= 0) {
45+
return ~~index;
46+
} else {
47+
return ~~index - 1; // faster than Math.Floor
48+
}
49+
}
50+
51+
public value(index: number): number {
52+
return Math.exp(index / this.multiplier) * (1 + this.relativeAccuracy);
3153
}
3254

33-
_powGamma(value: number): number {
34-
return Math.pow(2, value / this._multiplier);
55+
public equals(other: IndexMapping): boolean {
56+
if (!(other instanceof LogarithmicMapping)) {
57+
return false;
58+
}
59+
return withinTolerance(this.multiplier, other.multiplier, 1e-12);
3560
}
3661
}

0 commit comments

Comments
 (0)