UNPKG

gramoloss

Version:

Graph theory package for edition and computation

491 lines (490 loc) 17.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.hasLightTournamentExtension2 = exports.isTournamentLight = exports.searchHeavyArcDigraph = exports.searchHeavyArcDigraphAUX = exports.searchLocalHeavyArcMatrix = exports.searchHeavyArcDigraphAUXlocal = exports.searchHeavyArc = void 0; /** * @param m is the TRANSPOSED adjacency matrix of a directed graph * @todo CHECK for loops * * An arc u->v is said to be heavy if there exists vertices a, b, c such that * - a -> b -> c -> a is a cycle * - a,b,c -> u * - v -> a,b,c * * @returns undefined if there is no heavy arc (in that case the matrix is light) * @returns [u,v,a,b,c] where u->v is an heavy arc */ function searchHeavyArc(m) { let n = m.length; const order = new Array(); for (let u = 0; u < n; u++) { for (let v = 0; v < n; v++) { if (m[v][u] == false) { continue; } ; // Suppose m[v][u] = true so v <- u // If u->v is not heavy then the vertices x such that v -> x -> u should be acyclic // So there should be a partial order for them // So we reconstruct the partial order incrementally // If there is a vertex that cannot be inserted without conflicting with the current partial order then there is a triangle order.splice(0, order.length); for (let b = 0; b < n; b++) { if (m[b][v]) { // b <- v if (m[u][b] == false) { // u <- b continue; } if (u == 4 && v == 1) { console.log("---", b); } let i = 0; while (i < order.length) { const a = order[i]; if (m[a][b]) { // if a <- b break, it is the first in order, so order[k] -> b for every k<i break; } i++; } let isCycle = false; let j = i + 1; while (j < order.length) { const c = order[j]; if (m[b][c]) { // b <- order[j] isCycle = true; break; } j++; } if (u == 4 && v == 1) { console.log(i, j, order, isCycle); } if (isCycle) { return [u, v, order[j], b, order[i]]; } else { order.splice(i, 0, b); } } } } } return undefined; } exports.searchHeavyArc = searchHeavyArc; /** * We suppose u->v * @param outNeighbors * @param inNeighbors * @param u * @param v * @returns */ function searchHeavyArcDigraphAUXlocal(outNeighbors, inNeighbors, u, v) { const n = outNeighbors.length; // Type 1 conflict with uv (u->v is an heavy arc) const vertices = new Array(); for (const x of inNeighbors[u]) { if (outNeighbors[v].includes(x)) { vertices.push(x); } } for (const a of vertices) { for (const b of vertices) { if (outNeighbors[a].includes(b)) { for (const c of vertices) { if (outNeighbors[b].includes(c) && inNeighbors[a].includes(c)) { // console.log("type 1") return [u, v, a, b, c]; } } } } } // Type 2: uv is in the triangle (search for w the third vertex of the triangle) for (const w of outNeighbors[v]) { if (outNeighbors[w].includes(u)) { const dominated = new Array(); for (const a of outNeighbors[v]) { if (outNeighbors[u].includes(a) && outNeighbors[w].includes(a)) { dominated.push(a); } } for (const b of inNeighbors[v]) { if (inNeighbors[u].includes(b) && inNeighbors[w].includes(b)) { for (const a of dominated) { if (outNeighbors[a].includes(b)) { // console.log("type 2") return [a, b, u, v, w]; } } } } } } // Type 3: v is in the triangle and u is endvertex of the searched heavy arc for (const w of outNeighbors[v]) { if (outNeighbors[u].includes(w)) { for (const x of outNeighbors[w]) { if (outNeighbors[u].includes(x) && outNeighbors[x].includes(v)) { for (const y of outNeighbors[v]) { if (outNeighbors[x].includes(y) && outNeighbors[w].includes(y) && outNeighbors[y].includes(u)) { // console.log("type 3") return [y, u, v, w, x]; } } } } } } // Type 4: u is in the triangle and v is the start vertex of the searched heavy arc for (const w of outNeighbors[u]) { if (outNeighbors[w].includes(v)) { for (const x of outNeighbors[w]) { if (outNeighbors[x].includes(v) && outNeighbors[x].includes(u)) { for (const y of outNeighbors[v]) { if (outNeighbors[y].includes(u) && outNeighbors[y].includes(w) && outNeighbors[y].includes(x)) { // console.log("type 4") return [v, y, u, w, x]; } } } } } } return []; } exports.searchHeavyArcDigraphAUXlocal = searchHeavyArcDigraphAUXlocal; function searchLocalHeavyArcMatrix(matrix, u, v) { const n = matrix.length; // Type 1 conflict with uv (u->v is an heavy arc) const vertices = new Array(); for (let x = 0; x < n; x++) { if (matrix[x][u] && matrix[v][x]) { vertices.push(x); } } for (const a of vertices) { for (const b of vertices) { if (matrix[a][b]) { for (const c of vertices) { if (matrix[b][c] && matrix[c][a]) { // console.log("type 1") return [u, v, a, b, c]; } } } } } // Type 2: uv is in the triangle (search for w the third vertex of the triangle) for (let w = 0; w < n; w++) { if (matrix[v][w] && matrix[w][u]) { const dominated = new Array(); for (let a = 0; a < n; a++) { if (matrix[v][a] && matrix[u][a] && matrix[w][a]) { dominated.push(a); } } for (let b = 0; b < n; b++) { if (matrix[b][v] && matrix[b][u] && matrix[b][w]) { for (const a of dominated) { if (matrix[a][b]) { // console.log("type 2") return [a, b, u, v, w]; } } } } } } // Type 3: v is in the triangle and u is endvertex of the searched heavy arc for (let w = 0; w < n; w++) { if (matrix[v][w] && matrix[u][w]) { for (let x = 0; x < n; x++) { if (matrix[w][x] && matrix[u][x] && matrix[x][v]) { for (let y = 0; y < n; y++) { if (matrix[v][y] && matrix[x][y] && matrix[w][y] && matrix[y][u]) { // console.log("type 3") return [y, u, v, w, x]; } } } } } } // Type 4: u is in the triangle and v is the start vertex of the searched heavy arc for (let w = 0; w < n; w++) { if (matrix[u][w] && matrix[w][v]) { for (let x = 0; x < n; x++) { if (matrix[w][x] && matrix[x][v] && matrix[x][u]) { for (let y = 0; y < n; y++) { if (matrix[v][y] && matrix[y][u] && matrix[y][w] && matrix[y][x]) { // console.log("type 4") return [v, y, u, w, x]; } } } } } } return []; } exports.searchLocalHeavyArcMatrix = searchLocalHeavyArcMatrix; function searchHeavyArcDigraphAUX(g) { for (const u of g.vertices.values()) { for (const v of u.outNeighbors.values()) { const vertices = new Array(); for (const x of u.inNeighbors.values()) { if (v.outNeighbors.has(x.index)) { vertices.push(x); } } for (const a of vertices) { for (const b of vertices) { if (a.outNeighbors.has(b.index)) { for (const c of vertices) { if (b.outNeighbors.has(c.index) && a.inNeighbors.has(c.index)) { return [u, v, a, b, c]; } } } } } } } return []; } exports.searchHeavyArcDigraphAUX = searchHeavyArcDigraphAUX; function searchHeavyArcDigraph(g) { return searchHeavyArcDigraphAUX(g); } exports.searchHeavyArcDigraph = searchHeavyArcDigraph; /** * A tournament is light if there is no arc uv such that there exists a cycle abc such that abc dominates u and v dominates abcs. * If you want to get a conflict, if there is some, use the function tournamentLightConflict * @param g * @returns */ function isTournamentLight(g) { // const m = g.getDirectedMatrix(); return searchHeavyArcDigraph(g).length == 0; } exports.isTournamentLight = isTournamentLight; function findDeductions(outNeighbors, inNeighbors, u, v) { const n = outNeighbors.length; const pairs = new Array(); const inDominators = new Array(); const outDominators = new Array(); for (let w = 0; w < n; w++) { if (outNeighbors[v].includes(w) && inNeighbors[u].includes(w)) { inDominators.splice(0, inDominators.length); outDominators.splice(0, outDominators.length); for (let a = 0; a < n; a++) { let c = 0; for (const x of outNeighbors[a]) { if (x == u || x == v || x == w) { c++; } } if (c == 3) { inDominators.push(a); for (const b of outDominators) { if (outNeighbors[a].includes(b) == false) { pairs.push([a, b]); } } continue; } c = 0; for (const x of inNeighbors[a]) { if (x == u || x == v || x == w) { c++; } } if (c == 3) { outDominators.push(a); for (const b of inDominators) { if (inNeighbors[a].includes(b) == false) { pairs.push([b, a]); } } } } } } return pairs; } // ------------------- // V 2 with matrix function findDeductionsMatrix(matrix, u, v) { const n = matrix.length; const pairs = new Array(); const inDominators = new Array(); const outDominators = new Array(); for (let w = 0; w < n; w++) { if (matrix[v][w] && matrix[w][u]) { inDominators.splice(0, inDominators.length); outDominators.splice(0, outDominators.length); for (let a = 0; a < n; a++) { let c = 0; for (let x = 0; x < n; x++) { if (matrix[a][x] && (x == u || x == v || x == w)) { c++; } } if (c == 3) { inDominators.push(a); for (const b of outDominators) { if (matrix[a][b] == false) { pairs.push([a, b]); } } continue; } c = 0; for (let x = 0; x < n; x++) { if (matrix[x][a] && (x == u || x == v || x == w)) { c++; } } if (c == 3) { outDominators.push(a); for (const b of inDominators) { if (matrix[b][a] == false) { pairs.push([b, a]); } } } } } } return pairs; } function hasLightTournamentExtension2(g) { const n = g.vertices.size; const m = new Array(n); for (let i = 0; i < n; i++) { m[i] = new Array(n); } const todo = new Array(); for (let i = 0; i < n; i++) { for (let j = i + 1; j < n; j++) { if (m[i][j] == false && m[j][i] == false) { todo.push([i, j, false]); } } } // console.log(todo); const done = new Array(); while (true) { // console.log("-------") // console.log("todo", todo) // console.log("done", done); let edge = todo.pop(); if (typeof edge == "undefined") { // console.log(done) return [true, done]; } let [u, v, b] = edge; if (b == false) { if (m[u][v]) { done.push([u, v, false, [], true]); // console.log("yo") continue; } } else { if (m[v][u]) { done.push([u, v, true, [], true]); // console.log("ya") continue; } } if (b == false) { if (g.matrix[u][v] > 0) { console.log("BUG", u, v); } m[u][v] = true; if (searchLocalHeavyArcMatrix(m, u, v).length > 0) { m[u][v] = false; todo.push([u, v, true]); } else { const pairs = findDeductionsMatrix(m, u, v); for (const [a, b] of pairs) { m[a][b] = true; } let isDeductionOK = true; for (const [a, b] of pairs) { if (searchLocalHeavyArcMatrix(m, u, v).length > 0) { isDeductionOK = false; } } if (isDeductionOK == false) { m[u][v] = false; for (const [a, b] of pairs) { m[a][b] = false; } todo.push([u, v, true]); } else { done.push([u, v, false, pairs, false]); } } } else { m[v][u] = true; let isBad = searchLocalHeavyArcMatrix(m, v, u).length > 0; let deductions = new Array; let isDeductionOK = true; if (isBad == false) { deductions = findDeductionsMatrix(m, u, v); for (const [a, b] of deductions) { m[a][b] = true; } for (const [a, b] of deductions) { if (searchLocalHeavyArcMatrix(m, a, b).length > 0) { isDeductionOK = false; } } } if (isBad || isDeductionOK == false) { m[v][u] = false; for (const [a, b] of deductions) { m[a][b] = false; } todo.push([u, v, false]); let i = 0; // backtrack while (true) { i++; const pair = done.pop(); if (typeof pair == "undefined") { return [false, []]; } else { const [x, y, t, pairs, isDeduced] = pair; if (isDeduced) { continue; } for (const [a, b] of pairs) { m[a][b] = false; } if (t == false) { m[x][y] = false; todo.push([x, y, true]); break; } else { m[y][x] = false; todo.push([x, y, false]); } } } } else { done.push([u, v, true, deductions, false]); } } } console.log("empty graph case"); return [true, []]; } exports.hasLightTournamentExtension2 = hasLightTournamentExtension2;