Skip to content

Commit

Permalink
Merge branch 'feature/pregel-test-wcc' into test/pregel-test-scc
Browse files Browse the repository at this point in the history
# Conflicts:
#	js/common/modules/@arangodb/graph/graphs-generation.js
#	tests/js/common/shell/shell-pregel-components.js
  • Loading branch information
romanatarango committed Jun 24, 2022
2 parents d2f94dc + 1f1af37 commit 9111cc7
Show file tree
Hide file tree
Showing 4 changed files with 686 additions and 401 deletions.
335 changes: 181 additions & 154 deletions js/common/modules/@arangodb/graph/graphs-generation.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*jshint globalstrict:false, strict:false */
/*global assertEqual, assertTrue, assertNotEqual, JSON */
/*global assertTrue */
'use strict';

// //////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -28,189 +28,216 @@
// / @author Roman Rabinovich
// //////////////////////////////////////////////////////////////////////////////

const makeEdge = (from, to, vColl, name_prefix) => {
return {
_from: `${vColl}/${name_prefix}_${from}`,
_to: `${vColl}/${name_prefix}_${to}`,
vertex: `${name_prefix}_${from}`
};
const communityGenerator = function (vColl, label) {
return {
makeEdge: function (from, to) {
return {
_from: `${vColl}/${label}_${from}`,
_to: `${vColl}/${label}_${to}`,
vertex: `${label}_${from}`
};
}, makeVertex: function (name) {
return {
_key: `${label}_${name}`,
label: `${label}`
};
}
};
};

function makeVertex(name, name_prefix) {
return {_key: `${name_prefix}_${name}`};
}
const graphGenerator = function (verticesEdgesGenerator) {
const {makeVertex, makeEdge} = verticesEdgesGenerator;

function makeVertices(length, name_prefix) {
let vertices = [];
for (let i = 0; i < length; ++i) {
vertices.push(makeVertex(i, name_prefix));
}
return vertices;
}
const makeVertices = function (length) {
let vertices = [];
for (let i = 0; i < length; ++i) {
vertices.push(makeVertex(i));
}
return vertices;
};

function makeSingleVertex(name_prefix) {
const vertices = makeVertices(1, name_prefix);
const edges = [];
return {vertices, edges};
}
const makeOneVertex = function () {
return makeVertices(1)[0];
};

// length must be at least 2, shorter cycles make no sense and throw
// because then the test is wrong
function makeDirectedCycle(length, vColl, name_prefix) {
if (length < 2) {
console.error(`createDirectedCycle: error: length must be at least 2, instead got ${length}`);
assertTrue(false);
}
let vertices = makeVertices(length, name_prefix);
let edges = [];
for (let i = 0; i < length - 1; ++i) {
edges.push(makeEdge(i, i + 1, vColl, name_prefix));
}
edges.push(makeEdge(length - 1, 0, vColl, name_prefix));
return {vertices, edges};
}
const makeSingleVertexNoEdges = function () {
const vertices = makeVertices(1);
const edges = [];
return {vertices, edges};
};

// An alternating cycle is obtained from a directed cycle
// by replacing every second edge (v,w) by (w,v).
// Note that if length is odd,
// there may be a sub-path of length 2: (length-1) -> 0 -> 1.
function makeAlternatingCycle(length, vColl, name_prefix) {
if (length < 2) {
return {};
}
let vertices = makeVertices(length, name_prefix);
let edges = [];
for (let i = 0; i < length - 1; ++i) {
if (i % 2 === 0) {
edges.push(makeEdge(i+1, i, vColl, name_prefix));
} else {
edges.push(makeEdge(i, i + 1, vColl, name_prefix));
// length must be at least 2, shorter cycles make no sense and throw
// because then the test is wrong
const makeDirectedCycle = function (length) {
if (length < 2) {
console.error(`createDirectedCycle: error: length must be at least 2, instead got ${length}`);
assertTrue(false);
}
}
// special case: if length == 2, this would produce the edge (1, 0), but it has been already produced above
if (length > 2) {
if ((length - 1) % 2 === 0) {
edges.push(makeEdge(0, length - 1, vColl, name_prefix));
} else {
edges.push(makeEdge(length - 1, 0, vColl, name_prefix));
let vertices = makeVertices(length);
let edges = [];
for (let i = 0; i < length - 1; ++i) {
edges.push(makeEdge(i, i + 1));
}
}
return {vertices, edges};
}
edges.push(makeEdge(length - 1, 0));
return {vertices, edges};
};

// Creates a full binary tree of depth treeDepth (0 means: only the root) with edges directed away from the root.
// If alternating is true, on every second level of edges starting from the first, the edges are inverted:
// (v,w) is replaced by (w,v). (I.e., if alternating is true, two edges point to the root of the tree.)
function makeFullBinaryTree(treeDepth, vColl, name_prefix, alternating = false) {
if (treeDepth === 0) {
return {vertices: [0], edges: []};
}
if (treeDepth > 14) {
console.warn(`createFullBinaryTree WARNING: creating ${Math.pow(2, treeDepth + 1) - 1} vertices!`);
}
let vertices = makeVertices(Math.pow(2, treeDepth + 1) - 1, name_prefix);
// We create edges level by level top-down.
// variable firstFree: the least index of a vertex not yet connected by an edge.
// variable leaves: the set of current leaves (vertices on the lowest connected level). Acts as a FIFO queue.
// We always add an edge from the first leaf to firstFree (and update them).
let edges = [];
let firstFree = 1; // vertex with index 1 exists as treeDepth is > 0 here
let leaves = [0];
for (let d = 0; d < treeDepth; ++d) {
let leavesNestLevel = [];
const inverted = alternating && d % 2 === 0;
for (const leaf of leaves) {
if (inverted) {
edges.push(makeEdge(firstFree, leaf, vColl, name_prefix));
// An alternating cycle is obtained from a directed cycle
// by replacing every second edge (v,w) by (w,v).
// Note that if length is odd,
// there may be a sub-path of length 2: (length-1) -> 0 -> 1.
const makeAlternatingCycle = function (length) {
if (length < 2) {
return {};
}
let vertices = makeVertices(length);
let edges = [];
for (let i = 0; i < length - 1; ++i) {
if (i % 2 === 0) {
edges.push(makeEdge(i + 1, i));
} else {
edges.push(makeEdge(leaf, firstFree, vColl, name_prefix));
edges.push(makeEdge(i, i + 1));
}
++firstFree;
if (inverted) {
edges.push(makeEdge(firstFree, leaf, vColl, name_prefix));
}
// special case: if length == 2, this would produce the edge (1, 0), but it has been already produced above
if (length > 2) {
if ((length - 1) % 2 === 0) {
edges.push(makeEdge(0, length - 1));
} else {
edges.push(makeEdge(leaf, firstFree, vColl, name_prefix));
edges.push(makeEdge(length - 1, 0));
}
++firstFree;
// the last level of vertices is not collected to leavesNestLevel: its vertices have no children
if (d <= treeDepth - 2) {
leavesNestLevel.push(firstFree - 2);
leavesNestLevel.push(firstFree - 1);
}
return {vertices, edges};
};

// Creates a full binary tree of depth treeDepth (0 means: only the root) with edges directed away from the root.
// If alternating is true, on every second level of edges starting from the first, the edges are inverted:
// (v,w) is replaced by (w,v). (I.e., if alternating is true, two edges point to the root of the tree.)
const makeFullBinaryTree = function (treeDepth, alternating = false) {
if (treeDepth === 0) {
return {vertices: [0], edges: []};
}
if (treeDepth > 14) {
console.warn(`createFullBinaryTree WARNING: creating ${Math.pow(2, treeDepth + 1) - 1} vertices!`);
}
let vertices = makeVertices(Math.pow(2, treeDepth + 1) - 1);
// We create edges level by level top-down.
// variable firstFree: the least index of a vertex not yet connected by an edge.
// variable leaves: the set of current leaves (vertices on the lowest connected level). Acts as a FIFO queue.
// We always add an edge from the first leaf to firstFree (and update them).
let edges = [];
let firstFree = 1; // vertex with index 1 exists as treeDepth is > 0 here
let leaves = [0];
for (let d = 0; d < treeDepth; ++d) {
let leavesNestLevel = [];
const inverted = alternating && d % 2 === 0;
for (const leaf of leaves) {
if (inverted) {
edges.push(makeEdge(firstFree, leaf));
} else {
edges.push(makeEdge(leaf, firstFree));
}
++firstFree;
if (inverted) {
edges.push(makeEdge(firstFree, leaf));
} else {
edges.push(makeEdge(leaf, firstFree));
}
++firstFree;
// the last level of vertices is not collected to leavesNestLevel: its vertices have no children
if (d <= treeDepth - 2) {
leavesNestLevel.push(firstFree - 2);
leavesNestLevel.push(firstFree - 1);
}
leaves = leavesNestLevel;
}
leaves = leavesNestLevel;
}
}
return {vertices, edges};
}
return {vertices, edges};
};

// Creates a graph with size many vertices such that for each pair (v,w) of distinct vertices,
// Creates a graph with size many vertices such that for each pair (v,w) of distinct vertices,
// (v,w) or (w,v) is an edge (or both). There are no self-loops.
// The parameter kind has the following meaning:
// - "bidirected": for all distinct vertices v,w, there are edges (v,w) and (w,v)
// - "linear": the edges constitute a linear order <:
// there is an edge from v to w if and only if index of v < index of w.
// Note that the number of edges grows quadratically in size!
function makeClique(size, vColl, name_prefix, kind = "bidirected") {
let vertices = makeVertices(size, name_prefix);
let edges = [];
for (let v = 0; v < size; ++v) {
for (let w = v + 1; w < size; ++w) {
const makeClique = function (size, kind = "bidirected") {
let vertices = makeVertices(size);
let edges = [];
for (let v = 0; v < size; ++v) {
for (let w = v + 1; w < size; ++w) {
switch (kind) {
case "bidirected":
edges.push(makeEdge(v, w));
edges.push(makeEdge(w, v));
break;
case "linear":
edges.push(makeEdge(v, w));
break;
}
}
}
return {vertices, edges};
};

// a wrapper to unify the call of createDirectedCycle, createAlternatingCycle, createFullBinaryTree
const makeBidirectedClique = function (size) {
return makeClique(size, "bidirected");
};

// Creates a path of length length.
// The parameter kind has the following meaning:
// - "directed" (default): directed path
// - "bidirected": as "directed" but for every edge (v,w), we also have the edge (w,v)
// - "alternating": as "directed" but every second edge is inverted
const makePath = function (length, kind = "directed") {
let vertices = makeVertices(length, name_prefix);
let edges = [];
for (let v = 0; v < length - 1; ++v) {
switch (kind) {
case "directed":
edges.push(makeEdge(v, v + 1));
break;
case "bidirected":
edges.push(makeEdge(v, w, vColl, name_prefix));
edges.push(makeEdge(w, v, vColl, name_prefix));
edges.push(makeEdge(v, v + 1));
edges.push(makeEdge(v + 1, v));
break;
case "linear":
edges.push(makeEdge(v, w, vColl, name_prefix));
case "alternating":
const inverted = v % 2 === 0;
if (inverted) {
edges.push(makeEdge(v + 1, v));
} else {
edges.push(makeEdge(v, v + 1));
}
break;
}
}
}
return {vertices, edges};
}

// Creates a path of length length.
// The parameter kind has the following meaning:
// - "directed" (default): directed path
// - "bidirected": as "directed" but for every edge (v,w), we also have the edge (w,v)
// - "alternating": as "directed" but every second edge is inverted
function makePath(length, vColl, name_prefix, kind = "directed") {
let vertices = makeVertices(length, name_prefix);
let edges = [];
for (let v = 0; v < length - 1; ++v) {
switch (kind) {
case "directed":
edges.push(makeEdge(v, v + 1, name_prefix));
break;
case "bidirected":
edges.push(makeEdge(v, v + 1, vColl, name_prefix));
edges.push(makeEdge(v + 1, v, vColl, name_prefix));
break;
case "alternating":
const inverted = v % 2 === 0;
if (inverted) {
edges.push(makeEdge(v + 1, v, vColl, name_prefix));
} else {
edges.push(makeEdge(v, v + 1, vColl, name_prefix));
}
break;
}
return {vertices, edges};
};

}
return {vertices, edges};
return {
makeVertices,
makeOneVertex,
makeSingleVertexNoEdges,
makeDirectedCycle,
makeAlternatingCycle,
makeFullBinaryTree,
makeClique,
makeBidirectedClique,
makePath
};
}

// a wrapper to unify the call of createDirectedCycle, createAlternatingCycle, createFullBinaryTree
function makeBidirectedClique(size, vColl, name_prefix) {
return makeClique(size, vColl, name_prefix, "bidirected");
}
const makeEdgeBetweenVertices = function(vColl, from, fromLabel, to, toLabel) {
return {
_from: `${vColl}/${fromLabel}_${from}`,
_to: `${vColl}/${toLabel}_${to}`,
vertex: `${fromLabel}_${from}`
};
};

exports.makeVertex = makeVertex;
exports.makeEdge = makeEdge;
exports.makeDirectedCycle = makeDirectedCycle;
exports.makeAlternatingCycle = makeAlternatingCycle;
exports.makeFullBinaryTree = makeFullBinaryTree;
exports.makeClique = makeClique;
exports.makeBidirectedClique = makeBidirectedClique;
exports.makeSingleVertex = makeSingleVertex;
exports.makePath = makePath;
exports.communityGenerator = communityGenerator;
exports.graphGenerator = graphGenerator;
exports.makeEdgeBetweenVertices = makeEdgeBetweenVertices;
Loading

0 comments on commit 9111cc7

Please sign in to comment.