mirror of
https://github.com/status-im/sourcecred.git
synced 2025-02-17 06:56:36 +00:00
Add setEdgeEvaluator
to PagerankGraph (#1141)
This commit adds a `setEdgeEvaluator` method to `PagerankGraph`, and modifies the constructor to use that method. This will allow us to use PagerankGraph in the explorer UI, so that we can update edge weights without fully regenerating the graph. Test plan: I've added new unit tests that verify basic properties of how the edge weights are getting set and consumed.
This commit is contained in:
parent
f8c659a413
commit
f046dd06a5
@ -212,14 +212,23 @@ export class PagerankGraph {
|
||||
|
||||
// Initialize scores to the uniform distribution over every node
|
||||
this._scores = new Map();
|
||||
this._totalOutWeight = new Map();
|
||||
const graphNodes = Array.from(this._graph.nodes());
|
||||
for (const node of graphNodes) {
|
||||
this._scores.set(node, 1 / graphNodes.length);
|
||||
}
|
||||
this.setEdgeEvaluator(edgeEvaluator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes all of the PagerankGraph's edge weights
|
||||
* by applying the new EdgeEvaluator.
|
||||
*/
|
||||
setEdgeEvaluator(edgeEvaluator: EdgeEvaluator): this {
|
||||
this._totalOutWeight = new Map();
|
||||
this._edgeWeights = new Map();
|
||||
for (const node of this._graph.nodes()) {
|
||||
this._totalOutWeight.set(node, this._syntheticLoopWeight);
|
||||
}
|
||||
|
||||
this._edgeWeights = new Map();
|
||||
const addOutWeight = (node: NodeAddressT, weight: number) => {
|
||||
const previousWeight = NullUtil.get(this._totalOutWeight.get(node));
|
||||
const newWeight = previousWeight + weight;
|
||||
@ -231,6 +240,7 @@ export class PagerankGraph {
|
||||
addOutWeight(edge.src, weights.toWeight);
|
||||
addOutWeight(edge.dst, weights.froWeight);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,6 +50,38 @@ describe("core/pagerankGraph", () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe("setEdgeEvaluator", () => {
|
||||
it("is idempotent", () => {
|
||||
const e1 = examplePagerankGraph(defaultEvaluator);
|
||||
const e2 = examplePagerankGraph(defaultEvaluator);
|
||||
e2.setEdgeEvaluator(defaultEvaluator);
|
||||
expect(e1.equals(e2)).toBe(true);
|
||||
});
|
||||
it("graphs with changed edge weights are not equal", () => {
|
||||
const e1 = examplePagerankGraph();
|
||||
const e2 = examplePagerankGraph();
|
||||
e2.setEdgeEvaluator(() => ({toWeight: 3, froWeight: 9}));
|
||||
expect(e1.equals(e2)).toBe(false);
|
||||
});
|
||||
it("graphs are distinct but with identical scores if evaluators are the same modulo multiplication", async () => {
|
||||
// Think of this test as a bit more of an "e2e sanity check", verifying
|
||||
// a few properties at once.
|
||||
// We start with two example graphs with edge evaluators that are the same, except the scores
|
||||
// are different by a scalar multiple of 3.
|
||||
// So we know the scores should all turn out the same, but the graphs will be different,
|
||||
// because the edge weights are nominally distinct.
|
||||
const e1 = examplePagerankGraph(() => ({toWeight: 3, froWeight: 6}));
|
||||
const e2 = examplePagerankGraph(() => ({toWeight: 1, froWeight: 2}));
|
||||
expect(e1.equals(e2)).toBe(false);
|
||||
await e1.runPagerank();
|
||||
await e2.runPagerank();
|
||||
for (const {node, score} of e1.nodes()) {
|
||||
const otherScore = NullUtil.get(e2.node(node)).score;
|
||||
expect(otherScore).toBeCloseTo(score);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("node / nodes", () => {
|
||||
it("node returns null for node not in the graph", () => {
|
||||
const g = nonEmptyGraph();
|
||||
|
Loading…
x
Reference in New Issue
Block a user