diff --git a/src/analysis/timeline/timelineCred.js b/src/analysis/timeline/timelineCred.js index d8faf83..72cec81 100644 --- a/src/analysis/timeline/timelineCred.js +++ b/src/analysis/timeline/timelineCred.js @@ -8,7 +8,7 @@ import {toCompat, fromCompat, type Compatible} from "../../util/compat"; import {type Interval} from "./interval"; import {timelinePagerank} from "./timelinePagerank"; import {distributionToCred} from "./distributionToCred"; -import {type PluginDeclaration, combineTypes} from "../pluginDeclaration"; +import {type PluginDeclaration} from "../pluginDeclaration"; import {type NodeAddressT, NodeAddress, type Node} from "../../core/graph"; import * as WeightedGraph from "../../core/weightedGraph"; import {type Weights as WeightsT} from "../../core/weights"; @@ -189,16 +189,13 @@ export class TimelineCred { plugins: $ReadOnlyArray, |}): Promise { const {weightedGraph, params, plugins} = opts; - const {graph, weights} = weightedGraph; + const {graph} = weightedGraph; const fullParams = params == null ? defaultParams() : partialParams(params); const nodeOrder = Array.from(graph.nodes()).map((x) => x.address); - const types = combineTypes(plugins); const userTypes = [].concat(...plugins.map((x) => x.userTypes)); const scorePrefixes = userTypes.map((x) => x.prefix); const distribution = await timelinePagerank( - graph, - types, - weights, + weightedGraph, fullParams.intervalDecay, fullParams.alpha ); diff --git a/src/analysis/timeline/timelinePagerank.js b/src/analysis/timeline/timelinePagerank.js index 9cf2b09..24c60af 100644 --- a/src/analysis/timeline/timelinePagerank.js +++ b/src/analysis/timeline/timelinePagerank.js @@ -7,8 +7,7 @@ import deepFreeze from "deep-freeze"; import {sum} from "d3-array"; import * as NullUtil from "../../util/null"; import {Graph, type NodeAddressT, type Edge, type Node} from "../../core/graph"; -import {type NodeAndEdgeTypes} from "../types"; -import {type Weights} from "../../core/weights"; +import {type WeightedGraph} from "../../core/weightedGraph"; import {type Interval, partitionGraph} from "./interval"; import { nodeWeightEvaluator, @@ -98,9 +97,7 @@ export type TimelineDistributions = $ReadOnlyArray<{| * the pieces and run PageRank for each interval. */ export async function timelinePagerank( - graph: Graph, - types: NodeAndEdgeTypes, - weights: Weights, + weightedGraph: WeightedGraph, intervalDecay: number, alpha: number ): Promise { @@ -112,24 +109,26 @@ export async function timelinePagerank( } // Produce the evaluators we will use to get the baseline weight for each // node and edge - const nodeEvaluator = nodeWeightEvaluator(types.nodeTypes, weights); - const edgeEvaluator = edgeWeightEvaluator(types.edgeTypes, weights); + const nodeEvaluator = nodeWeightEvaluator(weightedGraph.weights); + const edgeEvaluator = edgeWeightEvaluator(weightedGraph.weights); - const graphPartitionSlices = partitionGraph(graph); + const graphPartitionSlices = partitionGraph(weightedGraph.graph); if (graphPartitionSlices.length === 0) { return []; } const intervals = graphPartitionSlices.map((x) => x.interval); const nodeCreationHistory = graphPartitionSlices.map((x) => x.nodes); const edgeCreationHistory = graphPartitionSlices.map((x) => x.edges); - const nodeOrder = Array.from(graph.nodes()).map((x) => x.address); + const nodeOrder = Array.from(weightedGraph.graph.nodes()).map( + (x) => x.address + ); const nodeWeightIterator = _timelineNodeWeights( nodeCreationHistory, nodeEvaluator, intervalDecay ); const markovChainIterator = _timelineMarkovChain( - graph, + weightedGraph.graph, edgeCreationHistory, edgeEvaluator, intervalDecay diff --git a/src/analysis/weightEvaluator.js b/src/analysis/weightEvaluator.js index 81d80c6..89cf4f2 100644 --- a/src/analysis/weightEvaluator.js +++ b/src/analysis/weightEvaluator.js @@ -1,13 +1,11 @@ // @flow import type {NodeAddressT, EdgeAddressT} from "../core/graph"; -import type {NodeType, EdgeType} from "./types"; import type { Weights as WeightsT, EdgeWeight, NodeWeight, } from "../core/weights"; -import * as Weights from "../core/weights"; import {NodeTrie, EdgeTrie} from "../core/trie"; export type NodeWeightEvaluator = (NodeAddressT) => NodeWeight; @@ -26,19 +24,9 @@ export type EdgeWeightEvaluator = (EdgeAddressT) => EdgeWeight; * legacy affordance; shortly we will remove the NodeTypes and require that the * plugins provide the type weights when the Weights object is constructed. */ -export function nodeWeightEvaluator( - types: $ReadOnlyArray, - weights: WeightsT -): NodeWeightEvaluator { - const {nodeWeights} = Weights.copy(weights); - - for (const {prefix, defaultWeight} of types) { - if (!nodeWeights.has(prefix)) { - nodeWeights.set(prefix, defaultWeight); - } - } +export function nodeWeightEvaluator(weights: WeightsT): NodeWeightEvaluator { const nodeTrie: NodeTrie = new NodeTrie(); - for (const [prefix, weight] of nodeWeights.entries()) { + for (const [prefix, weight] of weights.nodeWeights.entries()) { nodeTrie.add(prefix, weight); } return function nodeWeight(a: NodeAddressT): NodeWeight { @@ -61,18 +49,9 @@ export function nodeWeightEvaluator( * directly in the weights object, so that producing weight evaluators will no * longer depend on having plugin declarations on hand. */ -export function edgeWeightEvaluator( - types: $ReadOnlyArray, - weights: WeightsT -): EdgeWeightEvaluator { - const {edgeWeights} = Weights.copy(weights); - for (const {prefix, defaultWeight} of types) { - if (!edgeWeights.has(prefix)) { - edgeWeights.set(prefix, defaultWeight); - } - } +export function edgeWeightEvaluator(weights: WeightsT): EdgeWeightEvaluator { const edgeTrie: EdgeTrie = new EdgeTrie(); - for (const [prefix, weight] of edgeWeights.entries()) { + for (const [prefix, weight] of weights.edgeWeights.entries()) { edgeTrie.add(prefix, weight); } return function evaluator(address: EdgeAddressT): EdgeWeight { diff --git a/src/analysis/weightEvaluator.test.js b/src/analysis/weightEvaluator.test.js index ca5d099..8b7f8c2 100644 --- a/src/analysis/weightEvaluator.test.js +++ b/src/analysis/weightEvaluator.test.js @@ -1,6 +1,5 @@ // @flow -import deepFreeze from "deep-freeze"; import {NodeAddress, EdgeAddress} from "../core/graph"; import {nodeWeightEvaluator, edgeWeightEvaluator} from "./weightEvaluator"; import * as Weights from "../core/weights"; @@ -11,79 +10,33 @@ describe("src/analysis/weightEvaluator", () => { const foo = NodeAddress.fromParts(["foo"]); const foobar = NodeAddress.fromParts(["foo", "bar"]); - const fooNodeType = deepFreeze({ - name: "", - pluralName: "", - prefix: foo, - defaultWeight: 2, - description: "", - }); - - const fooBarNodeType = deepFreeze({ - name: "", - pluralName: "", - prefix: foobar, - defaultWeight: 3, - description: "", - }); - - const types = deepFreeze([fooNodeType, fooBarNodeType]); - it("gives every node weight 1 with empty types and weights", () => { - const evaluator = nodeWeightEvaluator([], Weights.empty()); + const evaluator = nodeWeightEvaluator(Weights.empty()); expect(evaluator(empty)).toEqual(1); expect(evaluator(foo)).toEqual(1); }); it("composes matching weights multiplicatively", () => { - const evaluator = nodeWeightEvaluator(types, Weights.empty()); + const weights = Weights.empty(); + weights.nodeWeights.set(foo, 2); + weights.nodeWeights.set(foobar, 3); + const evaluator = nodeWeightEvaluator(weights); expect(evaluator(empty)).toEqual(1); expect(evaluator(foo)).toEqual(2); expect(evaluator(foobar)).toEqual(6); }); - it("explicitly set weights on type prefixes override the type weights", () => { - const weights = Weights.empty(); - weights.nodeWeights.set(foo, 3); - weights.nodeWeights.set(foobar, 4); - const evaluator = nodeWeightEvaluator(types, weights); - expect(evaluator(empty)).toEqual(1); - expect(evaluator(foo)).toEqual(3); - expect(evaluator(foobar)).toEqual(12); - }); - it("uses manually-specified weights", () => { - const weights = Weights.empty(); - weights.nodeWeights.set(foo, 3); - const evaluator = nodeWeightEvaluator([], weights); - expect(evaluator(empty)).toEqual(1); - expect(evaluator(foo)).toEqual(3); - expect(evaluator(foobar)).toEqual(3); - }); }); describe("edgeEvaluator", () => { const foo = EdgeAddress.fromParts(["foo"]); const foobar = EdgeAddress.fromParts(["foo", "bar"]); - const fooType = deepFreeze({ - forwardName: "", - backwardName: "", - defaultWeight: {forwards: 2, backwards: 3}, - prefix: foo, - description: "", - }); - const fooBarType = deepFreeze({ - forwardName: "", - backwardName: "", - defaultWeight: {forwards: 4, backwards: 5}, - prefix: foobar, - description: "", - }); it("gives default 1,1 weights if no matching type", () => { - const evaluator = edgeWeightEvaluator([], Weights.empty()); + const evaluator = edgeWeightEvaluator(Weights.empty()); expect(evaluator(foo)).toEqual({forwards: 1, backwards: 1}); }); it("composes weights multiplicatively for all matching types", () => { - const evaluator = edgeWeightEvaluator( - [fooType, fooBarType], - Weights.empty() - ); + const weights = Weights.empty(); + weights.edgeWeights.set(foo, {forwards: 2, backwards: 3}); + weights.edgeWeights.set(foobar, {forwards: 4, backwards: 5}); + const evaluator = edgeWeightEvaluator(weights); expect(evaluator(foo)).toEqual({forwards: 2, backwards: 3}); expect(evaluator(foobar)).toEqual({forwards: 8, backwards: 15}); expect(evaluator(EdgeAddress.fromParts(["foo", "bar", "qox"]))).toEqual({ @@ -91,12 +44,5 @@ describe("src/analysis/weightEvaluator", () => { backwards: 15, }); }); - it("explicit weights override defaults from types", () => { - const weights = Weights.empty(); - weights.edgeWeights.set(foo, {forwards: 99, backwards: 101}); - const evaluator = edgeWeightEvaluator([fooType, fooBarType], weights); - expect(evaluator(foo)).toEqual({forwards: 99, backwards: 101}); - expect(evaluator(foobar)).toEqual({forwards: 4 * 99, backwards: 5 * 101}); - }); }); }); diff --git a/src/analysis/weightsToEdgeEvaluator.js b/src/analysis/weightsToEdgeEvaluator.js index 88b0db8..2477ae6 100644 --- a/src/analysis/weightsToEdgeEvaluator.js +++ b/src/analysis/weightsToEdgeEvaluator.js @@ -1,7 +1,6 @@ // @flow import type {Edge} from "../core/graph"; -import type {NodeAndEdgeTypes} from "./types"; import type {Weights} from "../core/weights"; import type {EdgeEvaluator} from "./pagerank"; import {nodeWeightEvaluator, edgeWeightEvaluator} from "./weightEvaluator"; @@ -27,12 +26,9 @@ import {nodeWeightEvaluator, edgeWeightEvaluator} from "./weightEvaluator"; * cred weighting) rather than as a component of the edge weight. This method * will be removed when the 'legacy cred' UI is removed. */ -export function weightsToEdgeEvaluator( - weights: Weights, - types: NodeAndEdgeTypes -): EdgeEvaluator { - const nodeWeight = nodeWeightEvaluator(types.nodeTypes, weights); - const edgeWeight = edgeWeightEvaluator(types.edgeTypes, weights); +export function weightsToEdgeEvaluator(weights: Weights): EdgeEvaluator { + const nodeWeight = nodeWeightEvaluator(weights); + const edgeWeight = edgeWeightEvaluator(weights); return function evaluator(edge: Edge) { const srcWeight = nodeWeight(edge.src); diff --git a/src/analysis/weightsToEdgeEvaluator.test.js b/src/analysis/weightsToEdgeEvaluator.test.js index 58f2607..30c501d 100644 --- a/src/analysis/weightsToEdgeEvaluator.test.js +++ b/src/analysis/weightsToEdgeEvaluator.test.js @@ -1,6 +1,5 @@ // @flow -import deepFreeze from "deep-freeze"; import {NodeAddress, EdgeAddress} from "../core/graph"; import {type Weights as WeightsT} from "../core/weights"; import * as Weights from "../core/weights"; @@ -16,57 +15,19 @@ describe("analysis/weightsToEdgeEvaluator", () => { timestampMs: 0, }; - const fallbackNodeType = deepFreeze({ - name: "", - pluralName: "", - prefix: NodeAddress.empty, - defaultWeight: 1, - description: "", - }); - - const srcNodeType = deepFreeze({ - name: "", - pluralName: "", - prefix: src, - defaultWeight: 2, - description: "", - }); - - const fallbackEdgeType = deepFreeze({ - forwardName: "", - backwardName: "", - defaultWeight: {forwards: 1, backwards: 1}, - prefix: EdgeAddress.empty, - description: "", - }); - function evaluateEdge(weights: WeightsT) { - const evaluator = weightsToEdgeEvaluator(weights, { - nodeTypes: [fallbackNodeType, srcNodeType], - edgeTypes: [fallbackEdgeType], - }); + const evaluator = weightsToEdgeEvaluator(weights); return evaluator(edge); } it("applies default weights when none are specified", () => { - expect(evaluateEdge(Weights.empty())).toEqual({forwards: 1, backwards: 2}); + expect(evaluateEdge(Weights.empty())).toEqual({forwards: 1, backwards: 1}); }); it("matches all prefixes of the nodes in scope", () => { const weights = Weights.empty(); weights.nodeWeights.set(NodeAddress.empty, 99); - expect(evaluateEdge(weights)).toEqual({forwards: 99, backwards: 2 * 99}); - }); - - it("takes manually specified edge type weights into account", () => { - const weights = Weights.empty(); - // Note that here we grab the fallout edge type. This also verifies that - // we are doing prefix matching on the types (rather than exact matching). - weights.edgeWeights.set(EdgeAddress.empty, { - forwards: 6, - backwards: 12, - }); - expect(evaluateEdge(weights)).toEqual({forwards: 6, backwards: 24}); + expect(evaluateEdge(weights)).toEqual({forwards: 99, backwards: 99}); }); it("an explicit weight on a prefix overrides the type weight", () => { @@ -76,10 +37,7 @@ describe("analysis/weightsToEdgeEvaluator", () => { }); it("uses 1 as a default weight for unmatched nodes and edges", () => { - const evaluator = weightsToEdgeEvaluator(Weights.empty(), { - nodeTypes: [], - edgeTypes: [], - }); + const evaluator = weightsToEdgeEvaluator(Weights.empty()); expect(evaluator(edge)).toEqual({forwards: 1, backwards: 1}); }); diff --git a/src/explorer/legacy/state.js b/src/explorer/legacy/state.js index 1647664..592663f 100644 --- a/src/explorer/legacy/state.js +++ b/src/explorer/legacy/state.js @@ -15,10 +15,7 @@ import {TimelineCred} from "../../analysis/timeline/timelineCred"; import type {Weights} from "../../core/weights"; import {weightsToEdgeEvaluator} from "../../analysis/weightsToEdgeEvaluator"; -import { - combineTypes, - type PluginDeclarations, -} from "../../analysis/pluginDeclaration"; +import {type PluginDeclarations} from "../../analysis/pluginDeclaration"; /* This models the UI states of the credExplorer/App as a state machine. @@ -157,11 +154,10 @@ export class StateTransitionMachine implements StateTransitionMachineInterface { this.setState(loadingState); const graph = state.timelineCred.weightedGraph().graph; let newState: ?AppState; - const types = combineTypes(state.pluginDeclarations); try { const pagerankNodeDecomposition = await this.pagerank( graph, - weightsToEdgeEvaluator(weights, types), + weightsToEdgeEvaluator(weights), { verbose: true, totalScoreNodePrefix: totalScoreNodePrefix,