refactor args to findStationaryDistribution (#1130)
In [#1128: Add support for seed vectors][#1128], we significantly increase the number of arguments to markovChain.findStationaryDistribution. To clean up the invocations, I added a followon PR (#1129) which converts findStationaryDistribution to use a `PagerankParams` object instead. However, I think it will be cleaner to land the PagerankParams refactor before adding new features in #1128, so I'm making this PR as pre-cleanup. Test plan: This is a trivial refactor. `yarn test` passes. [#1128]: https://github.com/sourcecred/sourcecred/pull/1128
This commit is contained in:
parent
6dd58a9c67
commit
a8a3f4fc3a
|
@ -19,7 +19,11 @@ import {
|
|||
|
||||
import {scoreByConstantTotal} from "./nodeScore";
|
||||
|
||||
import {findStationaryDistribution} from "../core/attribution/markovChain";
|
||||
import {
|
||||
findStationaryDistribution,
|
||||
type PagerankParams,
|
||||
type PagerankOptions as CorePagerankOptions,
|
||||
} from "../core/attribution/markovChain";
|
||||
|
||||
export type {NodeDistribution} from "../core/attribution/graphToMarkovChain";
|
||||
export type {PagerankNodeDecomposition} from "./pagerankNodeDecomposition";
|
||||
|
@ -63,12 +67,17 @@ export async function pagerank(
|
|||
fullOptions.selfLoopWeight
|
||||
);
|
||||
const osmc = createOrderedSparseMarkovChain(connections);
|
||||
const distributionResult = await findStationaryDistribution(osmc.chain, {
|
||||
const params: PagerankParams = {chain: osmc.chain};
|
||||
const coreOptions: CorePagerankOptions = {
|
||||
verbose: fullOptions.verbose,
|
||||
convergenceThreshold: fullOptions.convergenceThreshold,
|
||||
maxIterations: fullOptions.maxIterations,
|
||||
yieldAfterMs: 30,
|
||||
});
|
||||
};
|
||||
const distributionResult = await findStationaryDistribution(
|
||||
params,
|
||||
coreOptions
|
||||
);
|
||||
const pi = distributionToNodeDistribution(
|
||||
osmc.nodeOrder,
|
||||
distributionResult.pi
|
||||
|
|
|
@ -6,7 +6,10 @@ import {
|
|||
createConnections,
|
||||
createOrderedSparseMarkovChain,
|
||||
} from "../core/attribution/graphToMarkovChain";
|
||||
import {findStationaryDistribution} from "../core/attribution/markovChain";
|
||||
import {
|
||||
findStationaryDistribution,
|
||||
type PagerankParams,
|
||||
} from "../core/attribution/markovChain";
|
||||
import {
|
||||
decompose,
|
||||
type PagerankNodeDecomposition,
|
||||
|
@ -131,7 +134,8 @@ describe("analysis/pagerankNodeDecomposition", () => {
|
|||
const edgeWeight = () => ({toWeight: 6.0, froWeight: 3.0});
|
||||
const connections = createConnections(g, edgeWeight, 1.0);
|
||||
const osmc = createOrderedSparseMarkovChain(connections);
|
||||
const distributionResult = await findStationaryDistribution(osmc.chain, {
|
||||
const params: PagerankParams = {chain: osmc.chain};
|
||||
const distributionResult = await findStationaryDistribution(params, {
|
||||
verbose: false,
|
||||
convergenceThreshold: 1e-6,
|
||||
maxIterations: 255,
|
||||
|
@ -151,7 +155,8 @@ describe("analysis/pagerankNodeDecomposition", () => {
|
|||
const edgeWeight = () => ({toWeight: 6.0, froWeight: 3.0});
|
||||
const connections = createConnections(g, edgeWeight, 1.0);
|
||||
const osmc = createOrderedSparseMarkovChain(connections);
|
||||
const distributionResult = await findStationaryDistribution(osmc.chain, {
|
||||
const params: PagerankParams = {chain: osmc.chain};
|
||||
const distributionResult = await findStationaryDistribution(params, {
|
||||
verbose: false,
|
||||
convergenceThreshold: 1e-6,
|
||||
maxIterations: 255,
|
||||
|
|
|
@ -7,6 +7,36 @@
|
|||
*/
|
||||
export type Distribution = Float64Array;
|
||||
|
||||
/**
|
||||
* The data inputs to running PageRank.
|
||||
*
|
||||
* We keep these separate from the PagerankOptions below,
|
||||
* because we expect that within a given context, every call to
|
||||
* findStationaryDistribution (or other Pagerank functions) will
|
||||
* have different PagerankParams, but often have the same PagerankOptions.
|
||||
*/
|
||||
export type PagerankParams = {|
|
||||
+chain: SparseMarkovChain,
|
||||
|};
|
||||
|
||||
/**
|
||||
* PagerankOptions allows the user to tweak PageRank's behavior, especially around
|
||||
* convergence.
|
||||
*/
|
||||
export type PagerankOptions = {|
|
||||
// Causes runtime information to get logged to console.
|
||||
+verbose: boolean,
|
||||
// A distribution is considered stationary if the action of the Markov
|
||||
// chain on the distribution does not change any component by more than
|
||||
// `convergenceThreshold` in absolute value.
|
||||
+convergenceThreshold: number,
|
||||
// We will run maxIterations markov chain steps at most.
|
||||
+maxIterations: number,
|
||||
// To prevent locking the rest of the application, PageRank will yield control
|
||||
// after this many miliseconds, allowing UI updates, etc.
|
||||
+yieldAfterMs: number,
|
||||
|};
|
||||
|
||||
export type StationaryDistributionResult = {|
|
||||
// The final distribution after attempting to find the stationary distribution
|
||||
// of the Markov chain.
|
||||
|
@ -134,7 +164,7 @@ export function computeDelta(pi0: Distribution, pi1: Distribution) {
|
|||
}
|
||||
|
||||
function* findStationaryDistributionGenerator(
|
||||
chain: SparseMarkovChain,
|
||||
params: PagerankParams,
|
||||
options: {|
|
||||
+verbose: boolean,
|
||||
// A distribution is considered stationary if the action of the Markov
|
||||
|
@ -145,6 +175,7 @@ function* findStationaryDistributionGenerator(
|
|||
+maxIterations: number,
|
||||
|}
|
||||
): Generator<void, StationaryDistributionResult, void> {
|
||||
const {chain} = params;
|
||||
let pi = uniformDistribution(chain.length);
|
||||
let scratch = new Float64Array(pi.length);
|
||||
|
||||
|
@ -186,15 +217,10 @@ function* findStationaryDistributionGenerator(
|
|||
}
|
||||
|
||||
export function findStationaryDistribution(
|
||||
chain: SparseMarkovChain,
|
||||
options: {|
|
||||
+verbose: boolean,
|
||||
+convergenceThreshold: number,
|
||||
+maxIterations: number,
|
||||
+yieldAfterMs: number,
|
||||
|}
|
||||
params: PagerankParams,
|
||||
options: PagerankOptions
|
||||
): Promise<StationaryDistributionResult> {
|
||||
let gen = findStationaryDistributionGenerator(chain, {
|
||||
let gen = findStationaryDistributionGenerator(params, {
|
||||
verbose: options.verbose,
|
||||
convergenceThreshold: options.convergenceThreshold,
|
||||
maxIterations: options.maxIterations,
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
uniformDistribution,
|
||||
computeDelta,
|
||||
type StationaryDistributionResult,
|
||||
type PagerankParams,
|
||||
} from "./markovChain";
|
||||
|
||||
describe("core/attribution/markovChain", () => {
|
||||
|
@ -158,7 +159,8 @@ describe("core/attribution/markovChain", () => {
|
|||
[0.25, 0, 0.75],
|
||||
[0.25, 0.75, 0],
|
||||
]);
|
||||
const result = await findStationaryDistribution(chain, {
|
||||
const params: PagerankParams = {chain};
|
||||
const result = await findStationaryDistribution(params, {
|
||||
maxIterations: 255,
|
||||
convergenceThreshold: 1e-7,
|
||||
verbose: false,
|
||||
|
@ -184,7 +186,8 @@ describe("core/attribution/markovChain", () => {
|
|||
[0.5, 0, 0.25, 0, 0.25],
|
||||
[0.5, 0.25, 0, 0.25, 0],
|
||||
]);
|
||||
const result = await findStationaryDistribution(chain, {
|
||||
const params: PagerankParams = {chain};
|
||||
const result = await findStationaryDistribution(params, {
|
||||
maxIterations: 255,
|
||||
convergenceThreshold: 1e-7,
|
||||
verbose: false,
|
||||
|
@ -201,7 +204,8 @@ describe("core/attribution/markovChain", () => {
|
|||
|
||||
it("finds the stationary distribution of a periodic chain", async () => {
|
||||
const chain = sparseMarkovChainFromTransitionMatrix([[0, 1], [1, 0]]);
|
||||
const result = await findStationaryDistribution(chain, {
|
||||
const params: PagerankParams = {chain};
|
||||
const result = await findStationaryDistribution(params, {
|
||||
maxIterations: 255,
|
||||
convergenceThreshold: 1e-7,
|
||||
verbose: false,
|
||||
|
@ -218,7 +222,8 @@ describe("core/attribution/markovChain", () => {
|
|||
|
||||
it("returns initial distribution if maxIterations===0", async () => {
|
||||
const chain = sparseMarkovChainFromTransitionMatrix([[0, 1], [0, 1]]);
|
||||
const result = await findStationaryDistribution(chain, {
|
||||
const params: PagerankParams = {chain};
|
||||
const result = await findStationaryDistribution(params, {
|
||||
verbose: false,
|
||||
convergenceThreshold: 1e-7,
|
||||
maxIterations: 0,
|
||||
|
|
|
@ -21,7 +21,11 @@ import {
|
|||
createOrderedSparseMarkovChain,
|
||||
type EdgeWeight,
|
||||
} from "./attribution/graphToMarkovChain";
|
||||
import {findStationaryDistribution} from "../core/attribution/markovChain";
|
||||
import {
|
||||
findStationaryDistribution,
|
||||
type PagerankParams,
|
||||
type PagerankOptions,
|
||||
} from "../core/attribution/markovChain";
|
||||
import * as NullUtil from "../util/null";
|
||||
|
||||
export {Direction} from "./graph";
|
||||
|
@ -421,12 +425,17 @@ export class PagerankGraph {
|
|||
this._syntheticLoopWeight
|
||||
);
|
||||
const osmc = createOrderedSparseMarkovChain(connections);
|
||||
const distributionResult = await findStationaryDistribution(osmc.chain, {
|
||||
const params: PagerankParams = {chain: osmc.chain};
|
||||
const coreOptions: PagerankOptions = {
|
||||
verbose: false,
|
||||
convergenceThreshold: options.convergenceThreshold,
|
||||
maxIterations: options.maxIterations,
|
||||
yieldAfterMs: 30,
|
||||
});
|
||||
};
|
||||
const distributionResult = await findStationaryDistribution(
|
||||
params,
|
||||
coreOptions
|
||||
);
|
||||
this._scores = distributionToNodeDistribution(
|
||||
osmc.nodeOrder,
|
||||
distributionResult.pi
|
||||
|
|
Loading…
Reference in New Issue