08-27-周三_17-09-29

This commit is contained in:
2025-08-27 17:10:05 +08:00
commit 86df397d8f
12735 changed files with 1145479 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
import _ from 'lodash'
function addSubgraphConstraints (g, cg, vs) {
const prev = {}
let rootPrev
_.forEach(vs, function (v) {
let child = g.parent(v)
let parent
let prevChild
while (child) {
parent = g.parent(child)
if (parent) {
prevChild = prev[parent]
prev[parent] = child
} else {
prevChild = rootPrev
rootPrev = child
}
if (prevChild && prevChild !== child) {
cg.setEdge(prevChild, child)
return
}
child = parent
}
})
/*
function dfs(v) {
const children = v ? g.children(v) : g.children();
if (children.length) {
const min = Number.POSITIVE_INFINITY,
subgraphs = [];
_.forEach(children, function(child) {
const childMin = dfs(child);
if (g.children(child).length) {
subgraphs.push({ v: child, order: childMin });
}
min = Math.min(min, childMin);
});
_.reduce(_.sortBy(subgraphs, "order"), function(prev, curr) {
cg.setEdge(prev.v, curr.v);
return curr;
});
return min;
}
return g.node(v).order;
}
dfs(undefined);
*/
}
export default addSubgraphConstraints

27
node_modules/dagre-layout/lib/order/barycenter.js generated vendored Normal file
View File

@@ -0,0 +1,27 @@
import _ from 'lodash'
function barycenter (g, movable) {
return _.map(movable, function (v) {
const inV = g.inEdges(v)
if (!inV.length) {
return { v: v }
} else {
const result = _.reduce(inV, function (acc, e) {
const edge = g.edge(e)
const nodeU = g.node(e.v)
return {
sum: acc.sum + (edge.weight * nodeU.order),
weight: acc.weight + edge.weight
}
}, { sum: 0, weight: 0 })
return {
v: v,
barycenter: result.sum / result.weight,
weight: result.weight
}
}
})
}
export default barycenter

View File

@@ -0,0 +1,73 @@
import _ from 'lodash'
import { Graph } from 'graphlibrary'
/*
* Constructs a graph that can be used to sort a layer of nodes. The graph will
* contain all base and subgraph nodes from the request layer in their original
* hierarchy and any edges that are incident on these nodes and are of the type
* requested by the "relationship" parameter.
*
* Nodes from the requested rank that do not have parents are assigned a root
* node in the output graph, which is set in the root graph attribute. This
* makes it easy to walk the hierarchy of movable nodes during ordering.
*
* Pre-conditions:
*
* 1. Input graph is a DAG
* 2. Base nodes in the input graph have a rank attribute
* 3. Subgraph nodes in the input graph has minRank and maxRank attributes
* 4. Edges have an assigned weight
*
* Post-conditions:
*
* 1. Output graph has all nodes in the movable rank with preserved
* hierarchy.
* 2. Root nodes in the movable layer are made children of the node
* indicated by the root attribute of the graph.
* 3. Non-movable nodes incident on movable nodes, selected by the
* relationship parameter, are included in the graph (without hierarchy).
* 4. Edges incident on movable nodes, selected by the relationship
* parameter, are added to the output graph.
* 5. The weights for copied edges are aggregated as need, since the output
* graph is not a multi-graph.
*/
function buildLayerGraph (g, rank, relationship) {
const root = createRootNode(g)
const result = new Graph({ compound: true }).setGraph({ root: root })
.setDefaultNodeLabel(function (v) { return g.node(v) })
_.forEach(g.nodes(), function (v) {
const node = g.node(v)
const parent = g.parent(v)
if (node.rank === rank || (node.minRank <= rank && rank <= node.maxRank)) {
result.setNode(v)
result.setParent(v, parent || root)
// This assumes we have only short edges!
_.forEach(g[relationship](v), function (e) {
const u = e.v === v ? e.w : e.v
const edge = result.edge(u, v)
const weight = !_.isUndefined(edge) ? edge.weight : 0
result.setEdge(u, v, { weight: g.edge(e).weight + weight })
})
if (_.has(node, 'minRank')) {
result.setNode(v, {
borderLeft: node.borderLeft[rank],
borderRight: node.borderRight[rank]
})
}
}
})
return result
}
function createRootNode (g) {
let v
while (g.hasNode((v = _.uniqueId('_root'))));
return v
}
export default buildLayerGraph

70
node_modules/dagre-layout/lib/order/cross-count.js generated vendored Normal file
View File

@@ -0,0 +1,70 @@
import _ from 'lodash'
/*
* A function that takes a layering (an array of layers, each with an array of
* ordererd nodes) and a graph and returns a weighted crossing count.
*
* Pre-conditions:
*
* 1. Input graph must be simple (not a multigraph), directed, and include
* only simple edges.
* 2. Edges in the input graph must have assigned weights.
*
* Post-conditions:
*
* 1. The graph and layering matrix are left unchanged.
*
* This algorithm is derived from Barth, et al., "Bilayer Cross Counting."
*/
function crossCount (g, layering) {
let cc = 0
for (let i = 1; i < layering.length; ++i) {
cc += twoLayerCrossCount(g, layering[i - 1], layering[i])
}
return cc
}
function twoLayerCrossCount (g, northLayer, southLayer) {
// Sort all of the edges between the north and south layers by their position
// in the north layer and then the south. Map these edges to the position of
// their head in the south layer.
const southPos = _.zipObject(southLayer,
_.map(southLayer, function (v, i) { return i }))
const southEntries = _.flatten(_.map(northLayer, function (v) {
return _.chain(g.outEdges(v))
.map(function (e) {
return { pos: southPos[e.w], weight: g.edge(e).weight }
})
.sortBy('pos')
.value()
}), true)
// Build the accumulator tree
let firstIndex = 1
while (firstIndex < southLayer.length) {
firstIndex <<= 1
}
const treeSize = 2 * firstIndex - 1
firstIndex -= 1
const tree = _.map(new Array(treeSize), function () { return 0 })
// Calculate the weighted crossings
let cc = 0
_.forEach(southEntries.forEach(function (entry) {
let index = entry.pos + firstIndex
tree[index] += entry.weight
let weightSum = 0
while (index > 0) {
if (index % 2) {
weightSum += tree[index + 1]
}
index = (index - 1) >> 1
tree[index] += entry.weight
}
cc += entry.weight * weightSum
}))
return cc
}
export default crossCount

78
node_modules/dagre-layout/lib/order/index.js generated vendored Normal file
View File

@@ -0,0 +1,78 @@
import _ from 'lodash'
import { Graph } from 'graphlibrary'
import initOrder from './init-order'
import crossCount from './cross-count'
import sortSubgraph from './sort-subgraph'
import buildLayerGraph from './build-layer-graph'
import addSubgraphConstraints from './add-subgraph-constraints'
import util from '../util'
/*
* Applies heuristics to minimize edge crossings in the graph and sets the best
* order solution as an order attribute on each node.
*
* Pre-conditions:
*
* 1. Graph must be DAG
* 2. Graph nodes must be objects with a "rank" attribute
* 3. Graph edges must have the "weight" attribute
*
* Post-conditions:
*
* 1. Graph nodes will have an "order" attribute based on the results of the
* algorithm.
*/
function order (g) {
const maxRank = util.maxRank(g)
const downLayerGraphs = buildLayerGraphs(g, _.range(1, maxRank + 1), 'inEdges')
const upLayerGraphs = buildLayerGraphs(g, _.range(maxRank - 1, -1, -1), 'outEdges')
let layering = initOrder(g)
assignOrder(g, layering)
let bestCC = Number.POSITIVE_INFINITY
let best
for (let i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2)
layering = util.buildLayerMatrix(g)
const cc = crossCount(g, layering)
if (cc < bestCC) {
lastBest = 0
best = _.cloneDeep(layering)
bestCC = cc
}
}
assignOrder(g, best)
}
function buildLayerGraphs (g, ranks, relationship) {
return _.map(ranks, function (rank) {
return buildLayerGraph(g, rank, relationship)
})
}
function sweepLayerGraphs (layerGraphs, biasRight) {
const cg = new Graph()
_.forEach(layerGraphs, function (lg) {
const root = lg.graph().root
const sorted = sortSubgraph(lg, root, cg, biasRight)
_.forEach(sorted.vs, function (v, i) {
lg.node(v).order = i
})
addSubgraphConstraints(lg, cg, sorted.vs)
})
}
function assignOrder (g, layering) {
_.forEach(layering, function (layer) {
_.forEach(layer, function (v, i) {
g.node(v).order = i
})
})
}
export default order

36
node_modules/dagre-layout/lib/order/init-order.js generated vendored Normal file
View File

@@ -0,0 +1,36 @@
import _ from 'lodash'
/*
* Assigns an initial order value for each node by performing a DFS search
* starting from nodes in the first rank. Nodes are assigned an order in their
* rank as they are first visited.
*
* This approach comes from Gansner, et al., "A Technique for Drawing Directed
* Graphs."
*
* Returns a layering matrix with an array per layer and each layer sorted by
* the order of its nodes.
*/
function initOrder (g) {
const visited = {}
const simpleNodes = _.filter(g.nodes(), function (v) {
return !g.children(v).length
})
const maxRank = _.max(_.map(simpleNodes, function (v) { return g.node(v).rank }))
const layers = _.map(_.range(maxRank + 1), function () { return [] })
function dfs (v) {
if (_.has(visited, v)) return
visited[v] = true
const node = g.node(v)
layers[node.rank].push(v)
_.forEach(g.successors(v), dfs)
}
const orderedVs = _.sortBy(simpleNodes, function (v) { return g.node(v).rank })
_.forEach(orderedVs, dfs)
return layers
}
export default initOrder

View File

@@ -0,0 +1,121 @@
import _ from 'lodash'
/*
* Given a list of entries of the form {v, barycenter, weight} and a
* constraint graph this function will resolve any conflicts between the
* constraint graph and the barycenters for the entries. If the barycenters for
* an entry would violate a constraint in the constraint graph then we coalesce
* the nodes in the conflict into a new node that respects the contraint and
* aggregates barycenter and weight information.
*
* This implementation is based on the description in Forster, "A Fast and
* Simple Hueristic for Constrained Two-Level Crossing Reduction," thought it
* differs in some specific details.
*
* Pre-conditions:
*
* 1. Each entry has the form {v, barycenter, weight}, or if the node has
* no barycenter, then {v}.
*
* Returns:
*
* A new list of entries of the form {vs, i, barycenter, weight}. The list
* `vs` may either be a singleton or it may be an aggregation of nodes
* ordered such that they do not violate constraints from the constraint
* graph. The property `i` is the lowest original index of any of the
* elements in `vs`.
*/
function resolveConflicts (entries, cg) {
const mappedEntries = {}
_.forEach(entries, function (entry, i) {
const tmp = mappedEntries[entry.v] = {
indegree: 0,
'in': [],
out: [],
vs: [entry.v],
i: i
}
if (!_.isUndefined(entry.barycenter)) {
tmp.barycenter = entry.barycenter
tmp.weight = entry.weight
}
})
_.forEach(cg.edges(), function (e) {
const entryV = mappedEntries[e.v]
const entryW = mappedEntries[e.w]
if (!_.isUndefined(entryV) && !_.isUndefined(entryW)) {
entryW.indegree++
entryV.out.push(mappedEntries[e.w])
}
})
const sourceSet = _.filter(mappedEntries, function (entry) {
return !entry.indegree
})
return doResolveConflicts(sourceSet)
}
function doResolveConflicts (sourceSet) {
const entries = []
function handleIn (vEntry) {
return function (uEntry) {
if (uEntry.merged) {
return
}
if (_.isUndefined(uEntry.barycenter) ||
_.isUndefined(vEntry.barycenter) ||
uEntry.barycenter >= vEntry.barycenter) {
mergeEntries(vEntry, uEntry)
}
}
}
function handleOut (vEntry) {
return function (wEntry) {
wEntry['in'].push(vEntry)
if (--wEntry.indegree === 0) {
sourceSet.push(wEntry)
}
}
}
while (sourceSet.length) {
const entry = sourceSet.pop()
entries.push(entry)
_.forEach(entry['in'].reverse(), handleIn(entry))
_.forEach(entry.out, handleOut(entry))
}
return _.chain(entries)
.filter(function (entry) { return !entry.merged })
.map(function (entry) {
return _.pick(entry, ['vs', 'i', 'barycenter', 'weight'])
})
.value()
}
function mergeEntries (target, source) {
let sum = 0
let weight = 0
if (target.weight) {
sum += target.barycenter * target.weight
weight += target.weight
}
if (source.weight) {
sum += source.barycenter * source.weight
weight += source.weight
}
target.vs = source.vs.concat(target.vs)
target.barycenter = sum / weight
target.weight = weight
target.i = Math.min(source.i, target.i)
source.merged = true
}
export default resolveConflicts

77
node_modules/dagre-layout/lib/order/sort-subgraph.js generated vendored Normal file
View File

@@ -0,0 +1,77 @@
import _ from 'lodash'
import barycenter from './barycenter'
import resolveConflicts from './resolve-conflicts'
import sort from './sort'
function sortSubgraph (g, v, cg, biasRight) {
let movable = g.children(v)
const node = g.node(v)
const bl = node ? node.borderLeft : undefined
const br = node ? node.borderRight : undefined
const subgraphs = {}
if (bl) {
movable = _.filter(movable, function (w) {
return w !== bl && w !== br
})
}
const barycenters = barycenter(g, movable)
_.forEach(barycenters, function (entry) {
if (g.children(entry.v).length) {
const subgraphResult = sortSubgraph(g, entry.v, cg, biasRight)
subgraphs[entry.v] = subgraphResult
if (_.has(subgraphResult, 'barycenter')) {
mergeBarycenters(entry, subgraphResult)
}
}
})
const entries = resolveConflicts(barycenters, cg)
expandSubgraphs(entries, subgraphs)
const result = sort(entries, biasRight)
if (bl) {
result.vs = _.flatten([bl, result.vs, br], true)
if (g.predecessors(bl).length) {
const blPred = g.node(g.predecessors(bl)[0])
const brPred = g.node(g.predecessors(br)[0])
if (!_.has(result, 'barycenter')) {
result.barycenter = 0
result.weight = 0
}
result.barycenter = (result.barycenter * result.weight +
blPred.order + brPred.order) / (result.weight + 2)
result.weight += 2
}
}
return result
}
function expandSubgraphs (entries, subgraphs) {
_.forEach(entries, function (entry) {
entry.vs = _.flatten(entry.vs.map(function (v) {
if (subgraphs[v]) {
return subgraphs[v].vs
}
return v
}), true)
})
}
function mergeBarycenters (target, other) {
if (!_.isUndefined(target.barycenter)) {
target.barycenter = (target.barycenter * target.weight +
other.barycenter * other.weight) /
(target.weight + other.weight)
target.weight += other.weight
} else {
target.barycenter = other.barycenter
target.weight = other.weight
}
}
export default sortSubgraph

58
node_modules/dagre-layout/lib/order/sort.js generated vendored Normal file
View File

@@ -0,0 +1,58 @@
import _ from 'lodash'
import util from '../util'
function sort (entries, biasRight) {
const parts = util.partition(entries, function (entry) {
return _.has(entry, 'barycenter')
})
const sortable = parts.lhs
const unsortable = _.sortBy(parts.rhs, function (entry) { return -entry.i })
const vs = []
let sum = 0
let weight = 0
let vsIndex = 0
sortable.sort(compareWithBias(!!biasRight))
vsIndex = consumeUnsortable(vs, unsortable, vsIndex)
_.forEach(sortable, function (entry) {
vsIndex += entry.vs.length
vs.push(entry.vs)
sum += entry.barycenter * entry.weight
weight += entry.weight
vsIndex = consumeUnsortable(vs, unsortable, vsIndex)
})
const result = { vs: _.flatten(vs, true) }
if (weight) {
result.barycenter = sum / weight
result.weight = weight
}
return result
}
function consumeUnsortable (vs, unsortable, index) {
let last
while (unsortable.length && (last = _.last(unsortable)).i <= index) {
unsortable.pop()
vs.push(last.vs)
index++
}
return index
}
function compareWithBias (bias) {
return function (entryV, entryW) {
if (entryV.barycenter < entryW.barycenter) {
return -1
} else if (entryV.barycenter > entryW.barycenter) {
return 1
}
return !bias ? entryV.i - entryW.i : entryW.i - entryV.i
}
}
export default sort