Add `PagerankGraph.equals` (#1087)

Part of ongoing work for #1020.

Adds an equals method for the PagerankGraph. This is really quite
straightforward, the logic is based on the matching logic for
`Graph.equals`.

Tests added.

Test plan: The added tests are comprehensive, and they pass.
This commit is contained in:
Dandelion Mané 2019-02-16 11:52:38 -07:00 committed by GitHub
parent 7bc0d6956a
commit 7851c1b007
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 84 additions and 5 deletions

View File

@ -1,5 +1,7 @@
// @flow
import deepEqual from "lodash.isequal";
import {Graph, type Edge, type NodeAddressT, type EdgeAddressT} from "./graph";
import {
distributionToNodeDistribution,
@ -271,6 +273,29 @@ export class PagerankGraph {
};
}
/**
* Returns whether another PagerankGraph is equal to this one.
*
* PagerankGraphs are considered equal if they have the same nodes with
* the same scores, and the same edges with the same weights, and the same
* syntheticLoopWeight.
*
* The modification history of the underlying Graph is irrelevant to
* equality.
*/
equals(that: PagerankGraph): boolean {
if (!(that instanceof PagerankGraph)) {
throw new Error(`Expected PagerankGraph, got ${String(that)}`);
}
this._verifyGraphNotModified();
return (
this.graph().equals(that.graph()) &&
deepEqual(this._scores, that._scores) &&
deepEqual(this._edgeWeights, that._edgeWeights) &&
this._syntheticLoopWeight === that._syntheticLoopWeight
);
}
_verifyGraphNotModified() {
if (this._graph.modificationCount() !== this._graphModificationCount) {
throw new Error(

View File

@ -11,6 +11,11 @@ describe("core/pagerankGraph", () => {
const nonEmptyGraph = () =>
new Graph().addNode(NodeAddress.fromParts(["hi"]));
function examplePagerankGraph() {
const g = advancedGraph().graph1();
return new PagerankGraph(g, defaultEvaluator);
}
it("cannot construct PagerankGraph with empty Graph", () => {
const eg1 = new Graph();
const eg2 = new Graph()
@ -126,11 +131,6 @@ describe("core/pagerankGraph", () => {
expect(total).toBeCloseTo(1);
}
function examplePagerankGraph() {
const g = advancedGraph().graph1();
return new PagerankGraph(g, defaultEvaluator);
}
it("promise rejects if the graph was modified", async () => {
const pg = examplePagerankGraph();
pg.graph().addNode(NodeAddress.empty);
@ -175,4 +175,58 @@ describe("core/pagerankGraph", () => {
checkProbabilityDistribution(pg);
});
});
describe("equals", () => {
it("PagerankGraph is equal to itself", () => {
const pg = examplePagerankGraph();
expect(pg.equals(pg)).toBe(true);
});
it("two identicalPagerankGraphs are equal", () => {
const pg1 = examplePagerankGraph();
const pg2 = examplePagerankGraph();
expect(pg1.equals(pg2)).toBe(true);
});
it("unequal syntheticLoopWeight => unequal", () => {
const pg1 = new PagerankGraph(nonEmptyGraph(), defaultEvaluator, 0.1);
const pg2 = new PagerankGraph(nonEmptyGraph(), defaultEvaluator, 0.2);
expect(pg1.equals(pg2)).toBe(false);
});
it("unequal graph => unequal", () => {
const pg1 = new PagerankGraph(nonEmptyGraph(), defaultEvaluator, 0.1);
const g2 = nonEmptyGraph().addNode(NodeAddress.empty);
const pg2 = new PagerankGraph(g2, defaultEvaluator, 0.1);
expect(pg1.equals(pg2)).toBe(false);
});
it("unequal scores => unequal", async () => {
const pg1 = examplePagerankGraph();
const pg2 = examplePagerankGraph();
await pg1.runPagerank({maxIterations: 2, convergenceThreshold: 0.001});
expect(pg1.equals(pg2)).toBe(false);
});
it("unequal edge weights => unequal", () => {
const evaluator1 = (_unused_edge) => ({toWeight: 1, froWeight: 1});
const evaluator2 = (_unused_edge) => ({toWeight: 0, froWeight: 1});
const pg1 = new PagerankGraph(advancedGraph().graph1(), evaluator1);
const pg2 = new PagerankGraph(advancedGraph().graph1(), evaluator2);
expect(pg1.equals(pg2)).toBe(false);
});
it("different modification history => still equal", () => {
// advancedGraph.graph1 and graph2 are identical except for their
// construction history
const pg1 = new PagerankGraph(advancedGraph().graph1(), defaultEvaluator);
const pg2 = new PagerankGraph(advancedGraph().graph2(), defaultEvaluator);
expect(pg1.equals(pg2)).toBe(true);
});
it("throws an error if comparing PagerankGraph to non-PagerankGraph", () => {
const pg = examplePagerankGraph();
const g = new Graph();
// $ExpectFlowError
expect(() => pg.equals(g)).toThrowError("Expected PagerankGraph");
});
it("throws an error if the underlying graph is modified", () => {
const pg = examplePagerankGraph();
pg.graph().addNode(NodeAddress.fromParts(["modification"]));
expect(() => pg.equals(pg)).toThrowError("has been modified");
});
});
});