Update distributionToCred contract (#1560)
Resolves #1317 Updates timeline cred to handle the case where the scoring nodes' total cred sums to zero in an interval. In practice, we've encountered this circumstance when a github.io repository contains timestamps that predates any User's contributions by several weeks, such as sfosc.github.io. Test Plan: - Added a test case to handle this circumstance - Updated a test case per discussion on #1317 to return a cred score of 0 for all nodes in all intervals when there are no scoring nodes passed to the function, so that we handle these cases consistently. Also loaded sfosc.github.io and observed that the cred output appeared to match expectations and didn't contain any `NaN` or `Infinity` values as it did before.
This commit is contained in:
parent
74acd1fa80
commit
dea45fb8c1
|
@ -30,6 +30,13 @@ export type FullTimelineCred = $ReadOnlyArray<{|
|
|||
* This implementation normalizes the scores so that in each interval, the
|
||||
* total score of every node matching scoringNodePrefix is equal to the
|
||||
* interval's weight.
|
||||
*
|
||||
* Edge cases:
|
||||
* - If in an interval the sum of the scoring nodes' distribution is 0,
|
||||
* return a total cred score of 0 for all nodes in the interval.
|
||||
* - If none of the nodes match a scoring node prefix, return
|
||||
* a total cred score of 0 for all nodes in all intervals.
|
||||
*
|
||||
*/
|
||||
export function distributionToCred(
|
||||
ds: TimelineDistributions,
|
||||
|
@ -49,15 +56,14 @@ export function distributionToCred(
|
|||
}
|
||||
cred[i] = new Array(intervals.length);
|
||||
}
|
||||
if (scoringNodeIndices.length === 0) {
|
||||
throw new Error("no nodes matched scoringNodePrefix");
|
||||
}
|
||||
|
||||
return ds.map(({interval, distribution, intervalWeight}) => {
|
||||
const intervalTotalScore = sum(
|
||||
scoringNodeIndices.map((x) => distribution[x])
|
||||
);
|
||||
const intervalNormalizer = intervalWeight / intervalTotalScore;
|
||||
|
||||
const intervalNormalizer =
|
||||
intervalTotalScore == 0 ? 0 : intervalWeight / intervalTotalScore;
|
||||
const cred = distribution.map((x) => x * intervalNormalizer);
|
||||
return {interval, cred};
|
||||
});
|
||||
|
|
|
@ -87,7 +87,7 @@ describe("src/analysis/timeline/distributionToCred", () => {
|
|||
];
|
||||
expect(expected).toEqual(actual);
|
||||
});
|
||||
it("errors when no nodes are scoring", () => {
|
||||
it("handles the case where no nodes are scoring", () => {
|
||||
const ds = [
|
||||
{
|
||||
interval: {startTimeMs: 0, endTimeMs: 10},
|
||||
|
@ -96,9 +96,35 @@ describe("src/analysis/timeline/distributionToCred", () => {
|
|||
},
|
||||
];
|
||||
const nodeOrder = [na("foo"), na("bar")];
|
||||
const fail = () => distributionToCred(ds, nodeOrder, []);
|
||||
expect(fail).toThrowError("no nodes matched scoringNodePrefix");
|
||||
const actual = distributionToCred(ds, nodeOrder, []);
|
||||
const expected = [
|
||||
{
|
||||
interval: {startTimeMs: 0, endTimeMs: 10},
|
||||
cred: new Float64Array([0, 0]),
|
||||
},
|
||||
];
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it("handles the case where all nodes' cred sums to zero", () => {
|
||||
const ds = [
|
||||
{
|
||||
interval: {startTimeMs: 0, endTimeMs: 10},
|
||||
intervalWeight: 2,
|
||||
distribution: new Float64Array([1, 0]),
|
||||
},
|
||||
];
|
||||
const nodeOrder = [na("foo"), na("bar")];
|
||||
const actual = distributionToCred(ds, nodeOrder, [na("bar")]);
|
||||
const expected = [
|
||||
{
|
||||
interval: {startTimeMs: 0, endTimeMs: 10},
|
||||
cred: new Float64Array([0, 0]),
|
||||
},
|
||||
];
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it("returns empty array if no intervals are present", () => {
|
||||
expect(distributionToCred([], [], [])).toEqual([]);
|
||||
});
|
||||
|
|
|
@ -242,11 +242,7 @@ export class TimelineCred {
|
|||
fullParams.intervalDecay,
|
||||
fullParams.alpha
|
||||
);
|
||||
const cred = distributionToCred(
|
||||
distribution,
|
||||
nodeOrder,
|
||||
userTypes.map((x) => x.prefix)
|
||||
);
|
||||
const cred = distributionToCred(distribution, nodeOrder, scorePrefixes);
|
||||
const addressToCred = new Map();
|
||||
for (let i = 0; i < nodeOrder.length; i++) {
|
||||
const addr = nodeOrder[i];
|
||||
|
|
Loading…
Reference in New Issue