From c6ac5ed28eca83fbce5417bfa4fde988b8a9b807 Mon Sep 17 00:00:00 2001 From: "yuqi.pyq" Date: Wed, 12 Jul 2023 17:03:24 +0800 Subject: [PATCH] fix: avoid complex calculation when inertialModularity disabled --- package.json | 5 +- packages/graph/benchmarks/louvain.js | 98 ++++++++++++++++++++++++++++ packages/graph/package.json | 13 +++- packages/graph/src/louvain.ts | 4 +- 4 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 packages/graph/benchmarks/louvain.js diff --git a/package.json b/package.json index 7eb944a..63c463f 100644 --- a/package.json +++ b/package.json @@ -15,5 +15,6 @@ }, "devDependencies": { "lerna": "^3.20.2" - } -} + }, + "repository": "https://github.com/antvis/algorithm.git" +} \ No newline at end of file diff --git a/packages/graph/benchmarks/louvain.js b/packages/graph/benchmarks/louvain.js new file mode 100644 index 0000000..a8c2e04 --- /dev/null +++ b/packages/graph/benchmarks/louvain.js @@ -0,0 +1,98 @@ +/** + * Graphology x 173,947 ops/sec ±0.22% (98 runs sampled) + * NGraph x 60,245 ops/sec ±0.24% (99 runs sampled) + * @antv/algorithm x 436 ops/sec ±0.53% (85 runs sampled) + * Fastest is Graphology + */ +var Benchmark = require('benchmark'); +var suite = new Benchmark.Suite(); + +/** + * Graphology + * @see https://graphology.github.io/standard-library/communities-louvain.html + */ +var louvain = require('graphology-communities-louvain'); + +/** + * @antv/algorithm + * @see https://g6.antv.antgroup.com/api/algorithm#louvain + */ +var Algorithm = require('../lib'); + +/** + * ngraph.louvain + * @see https://github.com/anvaka/ngraph.louvain + */ +var createNGraph = require('ngraph.graph'); +var ngraphLouvain = require('ngraph.louvain'); +var ngraphCoarsen = require('ngraph.coarsen'); +var nGraph = createNGraph(); +function collectNGraphCommunities(g, result) { + var map = {}; + g.forEachNode((n) => { + map[n.id] = result.getClass(n.id); + }); + return map; +} +function ngraphLouvainHierarchy(g) { + var clusters = ngraphLouvain(g); + while (clusters.canCoarse()) { + g = ngraphCoarsen(g, clusters); + clusters = ngraphLouvain(g); + } + return collectNGraphCommunities(g, clusters); +} + +/** + * Generate graph with clusters. + */ +var Graph = require('graphology'); +var randomClusters = require('graphology-generators/random/clusters'); +var seedrandom = require('seedrandom'); +var rng = function () { + return seedrandom('bench'); +}; +const NODE_NUM = 10; +const EDGE_NUM = 30; +const g6graph = { nodes: [], edges: [] }; +var graph = randomClusters(Graph, { + order: NODE_NUM, + size: EDGE_NUM, + clusters: 5, + rng: rng(), +}); +graph.nodes().forEach(function (node) { + nGraph.addNode(node); + g6graph.nodes.push({ id: node }); +}); +graph.edges().forEach(function (edge) { + graph.setEdgeAttribute(edge, 'weight', 1); + const source = graph.source(edge); + const target = graph.target(edge); + nGraph.addLink(source, target); + g6graph.edges.push({ source, target, weight: 1 }); +}); + +function distinctSize(o) { + var keys = new Set(); + for (var k in o) keys.add(o[k]); + return keys.size; +} + +suite + .add('Graphology', function () { + const clusters = louvain(graph); + }) + .add('NGraph', function () { + const clusters = ngraphLouvainHierarchy(nGraph); + }) + .add('@antv/algorithm', function () { + const clusters = Algorithm.louvain(g6graph, false); + }) + .on('cycle', function (event) { + console.log(String(event.target)); + }) + .on('complete', function () { + console.log('Fastest is ' + this.filter('fastest').map('name')); + }) + .run({ async: true }); diff --git a/packages/graph/package.json b/packages/graph/package.json index 81960da..d0bc145 100644 --- a/packages/graph/package.json +++ b/packages/graph/package.json @@ -34,7 +34,8 @@ "test-live": "npm run build:umd && DEBUG_MODE=1 jest --watch ./tests/unit/louvain-spec.ts", "test-live:async": "npm run build:umd && DEBUG_MODE=1 jest --watch ./tests/unit/louvain-async-spec.ts", "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx", - "cdn": "antv-bin upload -n @antv/algorithm" + "cdn": "antv-bin upload -n @antv/algorithm", + "benchmark": "node benchmarks/louvain.js" }, "homepage": "https://g6.antv.vision", "bugs": { @@ -54,6 +55,16 @@ "@types/jest": "^26.0.18", "@umijs/fabric": "^2.5.6", "babel-loader": "^8.2.2", + "benchmark": "^2.1.4", + "graphology": "^0.25.1", + "graphology-communities-louvain": "latest", + "graphology-generators": "^0.11.2", + "graphology-types": "^0.24.7", + "graphology-metrics": "^2.1.0", + "ngraph.graph": "", + "ngraph.louvain": "", + "ngraph.coarsen": "", + "seedrandom": "^3.0.5", "father": "^2.30.0", "jest": "^26.6.3", "jest-electron": "^0.1.11", diff --git a/packages/graph/src/louvain.ts b/packages/graph/src/louvain.ts index 75abc49..4d25aa2 100644 --- a/packages/graph/src/louvain.ts +++ b/packages/graph/src/louvain.ts @@ -256,7 +256,7 @@ const louvain = ( propertiesWeightRemove[index] = allPropertiesWeight[nodeRemove.originIndex]; }) // the inertialModularity for **removing** the node i from the origin cluster of node i - const removeInertialModularity = getInertialModularity(selfClusterNodesAfterRemove, allPropertiesWeight) * inertialWeight; + const removeInertialModularity = inertialModularity ? getInertialModularity(selfClusterNodesAfterRemove, allPropertiesWeight) * inertialWeight : 0; // the neightbors of the node const nodeNeighborIds = neighbors[node.id]; @@ -288,7 +288,7 @@ const louvain = ( propertiesWeightAdd[index] = allPropertiesWeight[nodeAdd.originIndex]; }) // the inertialModularity for **adding** node i into this neighbor cluster - const addInertialModularity = getInertialModularity(clusterNodesAfterAdd, allPropertiesWeight) * inertialWeight; + const addInertialModularity = inertialModularity ? getInertialModularity(clusterNodesAfterAdd, allPropertiesWeight) * inertialWeight : 0; // the increase modurarity is the difference between addModurarity and removeModurarity let increase = addModurarity - removeModurarity;