UNPKG

gramoloss

Version:

Graph theory package for edition and computation

538 lines (537 loc) 19.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateUnitDisk = exports.generateCirculantTournament = exports.generatePaleyGraph = exports.generateRandomTree = exports.generateIndependentCircle = exports.generateCliqueCircle = exports.generateRandomTournament = exports.generateRandomGNP = exports.generateStar = exports.generateCompleteBipartite = exports.generateCompleteMultipartite = exports.generateGrid = exports.generateAztecDiamond = exports.generateTestTournament = exports.generateUGTournament = exports.generateAcyclicTournament = exports.generateUTournament = exports.generateGraph = exports.EmbeddedGraph = exports.EmbeddedVertexData = exports.GeneratorId = void 0; const coord_1 = require("./coord"); const graph_1 = require("./graph"); const link_1 = require("./link"); const utils_1 = require("./utils"); var GeneratorId; (function (GeneratorId) { GeneratorId["CliqueCircle"] = "CliqueCircle"; GeneratorId["IndependentCircle"] = "IndependentCircle"; GeneratorId["RandomTournament"] = "RandomTournament"; GeneratorId["RandomGNP"] = "RandomGNP"; GeneratorId["Star"] = "Star"; GeneratorId["CompleteBipartite"] = "CompleteBipartite"; GeneratorId["CompleteMultipartite"] = "CompleteMultipartite"; GeneratorId["Grid"] = "Grid"; GeneratorId["AztecDiamond"] = "AztecDiamond"; GeneratorId["Paley"] = "Paley"; GeneratorId["UnitDisk"] = "UnitDisk"; GeneratorId["UGTournament"] = "UGTournament"; GeneratorId["AcyclicTournament"] = "AcyclicTournament"; })(GeneratorId = exports.GeneratorId || (exports.GeneratorId = {})); class EmbeddedVertexData { constructor(pos) { this.pos = pos; } } exports.EmbeddedVertexData = EmbeddedVertexData; class EmbeddedGraph extends graph_1.Graph { } exports.EmbeddedGraph = EmbeddedGraph; function generateGraph(generatorId, params) { if (generatorId == GeneratorId.CliqueCircle) { if (params.length != 1) { logErrorNbParams(params.length, 1); return undefined; } const n = params[0]; if (typeof n != "number") return undefined; return generateCliqueCircle(n); } else if (generatorId == GeneratorId.IndependentCircle) { if (params.length != 1) { logErrorNbParams(params.length, 1); return undefined; } const n = params[0]; if (typeof n != "number") { return undefined; } return generateIndependentCircle(n); } else if (generatorId == GeneratorId.RandomTournament) { if (params.length != 1) { logErrorNbParams(params.length, 1); return undefined; } const n = params[0]; if (typeof n != "number") return undefined; return generateRandomTournament(n); } else if (generatorId == GeneratorId.RandomGNP) { if (params.length != 2) { logErrorNbParams(params.length, 2); return undefined; } const n = params[0]; if (typeof n != "number") return undefined; const p = params[1]; if (typeof p != "number") return undefined; return generateRandomGNP(n, p); } else if (generatorId == GeneratorId.Star) { if (params.length != 1) { logErrorNbParams(params.length, 1); return undefined; } const n = params[0]; if (typeof n != "number") return undefined; return generateStar(n); } else if (generatorId == GeneratorId.CompleteBipartite) { if (params.length != 2) { logErrorNbParams(params.length, 2); return undefined; } const n = params[0]; if (typeof n != "number") return undefined; const m = params[1]; if (typeof m != "number") return undefined; return generateCompleteBipartite(n, m); } else if (generatorId == GeneratorId.Grid) { if (params.length != 2) { logErrorNbParams(params.length, 2); return undefined; } const n = params[0]; if (typeof n != "number") return undefined; const m = params[1]; if (typeof m != "number") return undefined; return generateGrid(n, m); } else if (generatorId == GeneratorId.AztecDiamond) { if (params.length != 1) { logErrorNbParams(params.length, 1); return undefined; } const n = params[0]; if (typeof n != "number") return undefined; return generateAztecDiamond(n); } else if (generatorId == GeneratorId.Paley) { if (params.length != 1) { logErrorNbParams(params.length, 1); return undefined; } const n = params[0]; if (typeof n != "number") return undefined; return generatePaleyGraph(n); } else if (generatorId == GeneratorId.UnitDisk) { if (params.length != 2) { logErrorNbParams(params.length, 2); return undefined; } const n = params[0]; if (typeof n != "number") return undefined; const d = params[1]; if (typeof n != "number") return undefined; return generateUnitDisk(n, d); } else if (generatorId == GeneratorId.UGTournament) { if (params.length != 2) { logErrorNbParams(params.length, 2); return undefined; } const n = params[0]; const m = params[1]; if (typeof n != "number" || typeof m != "number") return undefined; return generateUGTournament(n, m); } else if (generatorId == GeneratorId.AcyclicTournament) { if (params.length != 1) { logErrorNbParams(params.length, 1); return undefined; } const n = params[0]; if (typeof n != "number") { return undefined; } return generateAcyclicTournament(n); } return undefined; } exports.generateGraph = generateGraph; /** * OBSOLETE generateUGTOurnament is a generalisation. * @param n number of vertices * @returns */ function generateUTournament(n) { const graph = new EmbeddedGraph(); const r = 50; for (let i = 0; i < n; i++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(i * 50, 0))); if (i > 0) { graph.addLink(i, i - 1, link_1.ORIENTATION.DIRECTED, undefined); } for (let j = 0; j < i - 1; j++) { graph.addLink(j, i, link_1.ORIENTATION.DIRECTED, undefined); } } return graph; } exports.generateUTournament = generateUTournament; /** * An acyclic tournament is a tournament which contains no directed cycle. * Such a graph is a Directed Acyclic Graph (DAG). * @param n number of vertices */ function generateAcyclicTournament(n) { return generateUGTournament(n, 0); } exports.generateAcyclicTournament = generateAcyclicTournament; /** * v(i) -> v(i-j) for all j in [1,k] * @param n number of vertices * @param k order * @example k = 0: acyclic * @example k = 1: U-tournaments */ function generateUGTournament(n, k) { const graph = new EmbeddedGraph(); for (let i = 0; i < n; i++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(i * 50, 0))); for (let j = 1; j <= k; j++) { if (i - j >= 0) { graph.addLink(i, i - j, link_1.ORIENTATION.DIRECTED, undefined); } } for (let j = 0; j < i - k; j++) { graph.addLink(j, i, link_1.ORIENTATION.DIRECTED, undefined); } } return graph; } exports.generateUGTournament = generateUGTournament; /** * for every i < j, i -> j iff i+j is prime * @param n */ function generateTestTournament(n) { const graph = new EmbeddedGraph(); for (let i = 0; i < n; i++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(i * 50, 0))); for (let j = 0; j < i; j++) { if ((0, utils_1.isPrime)(i + j)) { graph.addLink(j, i, link_1.ORIENTATION.DIRECTED, undefined); } else { graph.addLink(i, j, link_1.ORIENTATION.DIRECTED, undefined); } } } return graph; } exports.generateTestTournament = generateTestTournament; function generateAztecDiamond(n) { const graph = new EmbeddedGraph(); function check(i, j, n) { return (i + j >= n - 1 && i + j <= 3 * n + 1 && j - i <= n + 1 && i - j <= n + 1); } const indices = new Array(); for (let i = 0; i < 2 * n + 1; i++) { indices.push(new Array()); for (let j = 0; j < 2 * n + 1; j++) { indices[i].push(-1); if (check(i, j, n)) { const v = graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(i * 30 - n * 30, j * 30 - n * 30))); indices[i][j] = v.index; } } } for (let i = 0; i < 2 * n + 1; i++) { for (let j = 0; j < 2 * n + 1; j++) { if (indices[i][j] != -1) { if (check(i + 1, j, n) && i + 1 < 2 * n + 1) { graph.addLink(indices[i][j], indices[i + 1][j], link_1.ORIENTATION.UNDIRECTED, undefined); } if (check(i, j + 1, n) && j + 1 < 2 * n + 1) { graph.addLink(indices[i][j], indices[i][j + 1], link_1.ORIENTATION.UNDIRECTED, undefined); } } } } return graph; } exports.generateAztecDiamond = generateAztecDiamond; function generateGrid(n, m) { const graph = new EmbeddedGraph(); for (let i = 0; i < n; i++) { for (let j = 0; j < m; j++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(i * 30, j * 30))); } } for (let i = 0; i < n; i++) { for (let j = 0; j < m; j++) { let current_index = i * m + j; if (j < m - 1) { graph.addLink(current_index, current_index + 1, link_1.ORIENTATION.UNDIRECTED, undefined); } if (i < n - 1) { graph.addLink(current_index, current_index + m, link_1.ORIENTATION.UNDIRECTED, undefined); } } } return graph; } exports.generateGrid = generateGrid; /** * Returns a graph with vertex set indices [0, sum(sizes)-1] * Vi = sum( sizes[k], k < i) + [0, sizes[i]-1] * For every i and j, every vertex of Vi is adjacent to every vertex of Vj * @param sizes list of the sizes of the parts * @example * For sizes = [5,4,3], the graph has 5+4+3 vertices * The sum of the degrees is 5*(4+3) + 4*(5+3) + 3*(5+4). */ function generateCompleteMultipartite(sizes) { const graph = new EmbeddedGraph(); const k = sizes.length; const r = 50; for (let i = 0; i < k; i++) { for (let ki = 0; ki < sizes[i]; ki++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(r * Math.cos((2 * Math.PI * i) / k) + (-Math.sin((2 * Math.PI * i) / k)) * (ki - sizes[i] / 2), r * Math.sin((2 * Math.PI * i) / k) + (Math.cos((2 * Math.PI * i) / k)) * (ki - sizes[i] / 2)))); } } let sumi = 0; for (let i = 0; i < k; i++) { let sumj = 0; for (let j = 0; j < i; j++) { for (let ki = 0; ki < sizes[i]; ki++) { for (let kj = 0; kj < sizes[j]; kj++) { graph.addLink(sumi + ki, sumj + kj, link_1.ORIENTATION.UNDIRECTED, undefined); } } sumj += sizes[j]; } sumi += sizes[i]; } return graph; } exports.generateCompleteMultipartite = generateCompleteMultipartite; function generateCompleteBipartite(n, m) { const graph = new EmbeddedGraph(); for (let i = 0; i < n; i++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(i * 30, 0))); } for (let j = 0; j < m; j++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(j * 30, 100))); } for (let i = 0; i < n; i++) { for (let j = 0; j < m; j++) { graph.addLink(i, n + j, link_1.ORIENTATION.UNDIRECTED, undefined); } } return graph; } exports.generateCompleteBipartite = generateCompleteBipartite; function generateStar(n) { const graph = new EmbeddedGraph(); const r = 50; if (n > 0) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(0, 0))); for (let i = 1; i <= n; i++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(r * Math.cos((2 * Math.PI * i) / n), r * Math.sin((2 * Math.PI * i) / n)))); graph.addLink(0, i, link_1.ORIENTATION.UNDIRECTED, undefined); } } return graph; } exports.generateStar = generateStar; function generateRandomGNP(n, p) { const graph = new EmbeddedGraph(); const r = 50; for (let i = 0; i < n; i++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(r * Math.cos((2 * Math.PI * i) / n), r * Math.sin((2 * Math.PI * i) / n)))); for (let j = 0; j < i; j++) { if (Math.random() < p) { graph.addLink(j, i, link_1.ORIENTATION.UNDIRECTED, undefined); } } } return graph; } exports.generateRandomGNP = generateRandomGNP; function generateRandomTournament(n) { const graph = new EmbeddedGraph(); const r = 50; for (let i = 0; i < n; i++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(r * Math.cos((2 * Math.PI * i) / n), r * Math.sin((2 * Math.PI * i) / n)))); for (let j = 0; j < i; j++) { if (Math.random() < 0.5) { graph.addLink(j, i, link_1.ORIENTATION.DIRECTED, undefined); } else { graph.addLink(i, j, link_1.ORIENTATION.DIRECTED, undefined); } } } return graph; } exports.generateRandomTournament = generateRandomTournament; function generateCliqueCircle(n) { const graph = new EmbeddedGraph(); const r = 50; for (let i = 0; i < n; i++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(r * Math.cos((2 * Math.PI * i) / n), r * Math.sin((2 * Math.PI * i) / n)))); for (let j = 0; j < i; j++) { graph.addLink(j, i, link_1.ORIENTATION.UNDIRECTED, undefined); } } return graph; } exports.generateCliqueCircle = generateCliqueCircle; function generateIndependentCircle(n) { const graph = new EmbeddedGraph(); const r = 50; for (let i = 0; i < n; i++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(r * Math.cos((2 * Math.PI * i) / n), r * Math.sin((2 * Math.PI * i) / n)))); } return graph; } exports.generateIndependentCircle = generateIndependentCircle; // -------------------------------- // Generate Random Tree with markov chain function generateRandomTree(n) { const root = Math.floor(n / 2); const leaves = [0, n - 1]; const kids = new Array(); const parents = new Array(); for (let i = 0; i < n; i++) { parents.push(root); kids.push(new Set()); } for (let i = root; i - 1 >= 0; i--) { parents[i - 1] = i; kids[i].add(i - 1); } for (let i = root; i + 1 < n; i++) { parents[i + 1] = i; kids[i].add(i + 1); } for (let k = 0; k < 20; k++) { const leafId = Math.floor(Math.random() * leaves.length); const leaf = leaves[leafId]; // Delete edge kids[parents[leaf]].delete(leaf); let newParent = Math.floor(Math.random() * n); if (newParent >= leaf) { newParent += 1; } if (kids[newParent].size == 0) { leaves; // remove newp } kids[newParent].add(leaf); parents[leaf] = newParent; } const graph = new EmbeddedGraph(); const r = 50; for (let i = 0; i < n; i++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(i * 50, 0))); } for (let i = 0; i < n - 1; i++) { graph.addLink(i, i + 1, link_1.ORIENTATION.UNDIRECTED, undefined); } return graph; } exports.generateRandomTree = generateRandomTree; /** * PaleyGraph is unoriented if p = 1 mod 4. * It is oriented if p = -1 mod 4. * @param p should be a prime number = +-1 mod 4 * @returns Error if p is not such a number * @example undirected: 5 13 17, directed: 3 7 11 */ function generatePaleyGraph(p) { if (Number.isInteger(p) == false) throw Error(`p (given ${p}) should be an integer`); if ((p - 1) % 4 != 0 && (p + 1) % 4 != 0) throw Error(`param p (given ${p}) should be = +-1 mod 4 (here p = ${p % 4} mod 4)`); const orientation = (p - 1) % 4 == 0 ? link_1.ORIENTATION.UNDIRECTED : link_1.ORIENTATION.DIRECTED; const graph = new EmbeddedGraph(); const r = 50; for (let i = 0; i < p; i++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(r * Math.cos((2 * Math.PI * i) / p), r * Math.sin((2 * Math.PI * i) / p)))); } if (orientation == link_1.ORIENTATION.UNDIRECTED) { for (let i = 0; i < p; i++) { for (let j = i + 1; j < p; j++) { if ((0, utils_1.isModSquare)(j - i, p)) { graph.addLink(i, j, link_1.ORIENTATION.UNDIRECTED, undefined); } } } } else { for (let i = 0; i < p; i++) { for (let j = 0; j < p; j++) { if (i != j && (0, utils_1.isModSquare)(j - i, p)) { graph.addLink(i, j, link_1.ORIENTATION.DIRECTED, undefined); } } } } return graph; } exports.generatePaleyGraph = generatePaleyGraph; function generateCirculantTournament(n, gaps) { const graph = new EmbeddedGraph(); const r = 50; for (let i = 0; i < (2 * n + 1); i++) { graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(r * Math.cos((2 * Math.PI * i) / (2 * n + 1)), r * Math.sin((2 * Math.PI * i) / (2 * n + 1))))); } for (let i = 0; i < (2 * n + 1); i++) { for (const k of gaps) { const j = ((2 * n + 1) + i + k) % (2 * n + 1); graph.addLink(i, j, link_1.ORIENTATION.DIRECTED, undefined); } } return graph; } exports.generateCirculantTournament = generateCirculantTournament; /** * Return a random Unit Disk graph where vertices are set uniformely randomly in [-50,50]^2. * @param n integer >= 0, the number of vertices * @param d maximum distance between adjacent vertiecs */ function generateUnitDisk(n, d) { const graph = new EmbeddedGraph(); const vertices = new Array(); for (let i = 0; i < n; i++) { vertices.push(graph.addVertex(new EmbeddedVertexData(new coord_1.Coord(Math.random() * 100 - 50, Math.random() * 100 - 50)))); } for (let i = 0; i < n; i++) { for (let j = i + 1; j < n; j++) { const dist = Math.sqrt(vertices[i].data.pos.dist2(vertices[j].data.pos)); if (dist < d) { graph.addLink(i, j, link_1.ORIENTATION.UNDIRECTED, undefined); } } } return graph; } exports.generateUnitDisk = generateUnitDisk; function logErrorNbParams(received, expected) { console.log(`Error: not enough parameters (received: ${received} expected: ${expected})`); } function logErrorTypeParam(received, expected) { console.log(`Error: wrong type of param (received: ${received} expected: ${expected})`); }