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:
Dandelion Mané 2019-05-17 17:07:18 +03:00 committed by GitHub
parent f8c659a413
commit f046dd06a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 3 deletions

View File

@ -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;
}
/**

View File

@ -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();