Adding algorithms max flow.

master
Tomasz Półgrabia 2022-03-05 17:10:14 +01:00
parent aeaf0dd687
commit c96f6aa699
2 changed files with 234 additions and 0 deletions

View File

@ -0,0 +1,226 @@
"use strict";
const fs = require('fs');
const {EOL} = require('os');
const eps = 1e-6;
function increasingFlowPath(c, s, t) {
console.log(`Look for increasing flow path ${s} -> ${t}`);
let queue = [];
let processed = new Set();
queue.unshift(s);
processed.add(s);
let precedessor = {vi: null}; // i -> precedessor
while (queue.length) {
let vi = queue.pop();
if (vi === t) {
break;
}
for (let i = 0; i < c.length; i++) {
if (Math.abs(c[vi][i]) > eps && !processed.has(i)) {
precedessor[i] = vi;
queue.unshift(i);
processed.add(i);
}
}
}
if (!precedessor[t]) {
return {path: [], flow: 0};
}
let path = [];
let i = t;
path.push(t);
let flow = Infinity;
while (typeof(precedessor[i]) === 'number') {
console.log(`Precedessor ${i} is ${precedessor[i]}`);
flow = Math.min(flow, c[precedessor[i]][i]);
path.unshift(precedessor[i]);
i = precedessor[i];
}
return {path, flow};
}
function findMaximumFlow(graph) {
let nodes = [];
let m = {};
for (let el of graph.nodes) {
nodes.push(el);
}
for (let i = 0; i < nodes.length; i++) {
m[nodes[i]] = i;
}
const n = nodes.length;
let c = new Array(n);
let f = new Array(n);
for (let i = 0; i < n; i++) {
c[i] = new Array(n);
f[i] = new Array(n);
}
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
c[i][j] = 0;
f[i][j] = 0;
}
}
for (let v in graph.edges) {
for (let {node, weight} of graph.edges[v]) {
let vi = m[v]
let nodei = m[node];
c[vi][nodei] = weight;
}
}
console.log('C weights', c);
// let's find increasing flow path
let p, fl;
do {
let {path, flow} = increasingFlowPath(c, m[graph.source], m[graph.target]);
p = path;
fl = flow;
console.log(`Increasing flow ${flow} path ${path}`);
if (path) {
// new increasing flow path
// f increase
// c decrease
for (let i = 1; i < path.length; i++) {
c[path[i-1]][path[i]] -= flow;
f[path[i-1]][path[i]] += flow;
}
}
} while (fl);
console.log(`Flow`, c);
let flow = 0;
for (let i = 0; i < nodes.length; i++) {
flow += f[m[graph.source]][i];
}
return flow;
}
function sourceCmdLine(ctx, cmdLine) {
ctx.source = cmdLine.slice(
'source'.length,
cmdLine.indexOf(';')
).trim();
}
function targetCmdLine(ctx, cmdLine) {
ctx.target = cmdLine.slice(
'target'.length,
cmdLine.indexOf(';')
).trim();
}
function edgeCmdLine(ctx, cmdLine) {
let edgeLine = cmdLine.slice(
'edge'.length,
cmdLine.indexOf(';')
).trim();
console.log(`Edge line ${edgeLine}`);
const matches = edgeLine.match(/^([a-zA-Z]*) -> ([a-zA-Z]*): ([0-9.]*)$/);
// console.log('Matches', matches);
const v = matches[1];
const z = matches[2];
const weight = Number.parseFloat(matches[3]);
console.log(`Parsed ${v} -> ${z} : ${weight}`);
ctx.nodes.add(v);
ctx.nodes.add(z);
let targetEdges = ctx.edges[v] || [];
targetEdges.push({node: z, weight});
ctx.edges[v] = targetEdges;
}
function processCmdLine(ctx, cmdLine) {
console.log(`Processing command line ${cmdLine}`);
if (cmdLine.startsWith('source')) {
sourceCmdLine(ctx, cmdLine);
} else if (cmdLine.startsWith('target')) {
targetCmdLine(ctx, cmdLine);
} else if (cmdLine.startsWith('edge')) {
edgeCmdLine(ctx, cmdLine);
}
}
console.log(`Process argv: ${process.argv}`);
const inputPath = process.argv.length > 2 ? process.argv[2] : '-';
const outputPath = process.argv.length > 3 ? process.argv[3] : '-';
console.log(`Input path ${inputPath}, output path: ${outputPath}`);
const inputStream = inputPath === '-'
? process.stdin
: fs.createReadStream(inputPath);
// const outputStream = outputPath === '-'
// ? process.stdout
// : fs.createWriteStream(outputStream);
let inputBuffer = "";
let ctx = {
source: '',
target: '',
edges: {},
nodes: new Set()
};
function processChunk(chunk) {
inputBuffer += chunk;
console.log(`Chunk: ${chunk}`);
let eolIdx;
do {
eolIdx = inputBuffer.indexOf(EOL);
if (eolIdx < 0 && !chunk) {
eolIdx = inputBuffer.length;
}
let cmdLine = null;
if (eolIdx >= 0) {
console.log(`We got new line ${eolIdx}`);
cmdLine = inputBuffer.slice(0, eolIdx);
processCmdLine(ctx, cmdLine);
inputBuffer = inputBuffer.slice(eolIdx+EOL.length);
}
} while (eolIdx >= 0 && inputBuffer.length);
}
inputStream.on('data', (chunk) => {
processChunk(chunk);
});
inputStream.on('end', (chunk) => {
console.log(`end chunk ${chunk}`);
processChunk(chunk);
console.log('Got following graph', ctx);
for (let v in ctx.edges) {
for (let {node, weight} of ctx.edges[v]) {
console.log(`${v} ${node} : ${weight}`);
}
}
let mflow = findMaximumFlow(ctx);
console.log(`Maximum flow is ${mflow}`);
});

View File

@ -0,0 +1,8 @@
source s;
target t;
edge s -> u: 10;
edge u -> t: 5;
edge s -> v: 5;
edge v -> t: 10;
edge u -> v: 15;