gramoloss
Version:
Graph theory package for edition and computation
538 lines (537 loc) • 19.6 kB
JavaScript
"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})`);
}