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:
parent
7bc0d6956a
commit
7851c1b007
|
@ -1,5 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import deepEqual from "lodash.isequal";
|
||||||
|
|
||||||
import {Graph, type Edge, type NodeAddressT, type EdgeAddressT} from "./graph";
|
import {Graph, type Edge, type NodeAddressT, type EdgeAddressT} from "./graph";
|
||||||
import {
|
import {
|
||||||
distributionToNodeDistribution,
|
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() {
|
_verifyGraphNotModified() {
|
||||||
if (this._graph.modificationCount() !== this._graphModificationCount) {
|
if (this._graph.modificationCount() !== this._graphModificationCount) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|
|
@ -11,6 +11,11 @@ describe("core/pagerankGraph", () => {
|
||||||
const nonEmptyGraph = () =>
|
const nonEmptyGraph = () =>
|
||||||
new Graph().addNode(NodeAddress.fromParts(["hi"]));
|
new Graph().addNode(NodeAddress.fromParts(["hi"]));
|
||||||
|
|
||||||
|
function examplePagerankGraph() {
|
||||||
|
const g = advancedGraph().graph1();
|
||||||
|
return new PagerankGraph(g, defaultEvaluator);
|
||||||
|
}
|
||||||
|
|
||||||
it("cannot construct PagerankGraph with empty Graph", () => {
|
it("cannot construct PagerankGraph with empty Graph", () => {
|
||||||
const eg1 = new Graph();
|
const eg1 = new Graph();
|
||||||
const eg2 = new Graph()
|
const eg2 = new Graph()
|
||||||
|
@ -126,11 +131,6 @@ describe("core/pagerankGraph", () => {
|
||||||
expect(total).toBeCloseTo(1);
|
expect(total).toBeCloseTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function examplePagerankGraph() {
|
|
||||||
const g = advancedGraph().graph1();
|
|
||||||
return new PagerankGraph(g, defaultEvaluator);
|
|
||||||
}
|
|
||||||
|
|
||||||
it("promise rejects if the graph was modified", async () => {
|
it("promise rejects if the graph was modified", async () => {
|
||||||
const pg = examplePagerankGraph();
|
const pg = examplePagerankGraph();
|
||||||
pg.graph().addNode(NodeAddress.empty);
|
pg.graph().addNode(NodeAddress.empty);
|
||||||
|
@ -175,4 +175,58 @@ describe("core/pagerankGraph", () => {
|
||||||
checkProbabilityDistribution(pg);
|
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");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue