diff --git a/assignment-3/push-relabel.odin b/assignment-3/push-relabel.odin new file mode 100644 index 0000000..d16df21 --- /dev/null +++ b/assignment-3/push-relabel.odin @@ -0,0 +1,116 @@ +package main + +import "core:fmt" +import "core:math" +import "core:slice" + +// the graph starts with a source s and ends with a sink t, hence the 1s. +// then there is a stack of n nodes, then a chain of k nodes, then another stack of m nodes. +// all edges have weight 1, except the chain of k nodes, which all have weight c. +// ``` +// an bm +// / \ c c / \ +// s - .. - r1 - .. - rk - .. - t +// \ / \ / +// a1 b1 +// ``` +// we create and return an adjacency matrix representing the graphs. +create_graph :: proc($n, $m, $k: int, c: int) -> (res: [1 + n + k + m + 1][1 + n + k + m + 1]int) { + // source to n nodes + for i in 1 ..= n do res[0][i] = 1 + + // n nodes to r1 + r1 := n + 1 + for i in 1 ..= n do res[i][r1] = 1 + + // r1 through rk + rk := r1 + k + for i in r1 ..< rk - 1 do res[i][i + 1] = c + + // rk to m nodes + for i in rk ..< rk + m do res[rk - 1][i] = 1 + + // m nodes to sink + for i in rk ..< rk + m do res[i][rk + m] = 1 + + res += transpose_graph(res) + + return +} + +transpose_graph :: proc(g: [$row][$col]$T) -> (res: [col][row]T) { + for i in 0 ..< row { + for j in i ..< col { + res[i][j], res[j][i] = g[j][i], g[i][j] + } + } + return +} + +print_graph :: proc(g: [$row][$col]$T, elem_sep := " ", line_sep := "\n") { + // column markers + fmt.print(" ") + fmt.print(elem_sep) + for i in 0 ..< row { + fmt.print(rune('a' + i)) + fmt.print(elem_sep) + } + // body + fmt.print(line_sep) + for i in 0 ..< row { + fmt.print(rune('a' + i)) // row markers + fmt.print(elem_sep) + for j in 0 ..< col { + fmt.print(g[i][j]) + fmt.print(elem_sep) + } + fmt.print(line_sep) + } +} + +find_node_with_excess :: proc(excesses: []int) -> (u: int, ok: bool) { + for e, idx in excesses do if e > 0 do return idx, true + return -1, false +} + +find_admissible_edge :: proc(u: int, residuals, heights: []int) -> (v: int, ok: bool) { + if len(residuals) != len(heights) do return -1, false + for r, idx in residuals { + if r > 0 && heights[u] == heights[idx] + 1 { + return idx, true + } + } + return -1, false +} + +push :: proc(u, v: int, residuals, excesses: []int) -> (res: []int, ok: bool) { + if len(residuals) != excesses +} + +push_relabel :: proc(graph: [$n][n]int) -> (flow: [n][n]int) { + heights: [n]int + heights[0] = n + flow[0] += graph[0] + excesses: [n]int + excesses[0] = -math.sum(flow[0][:]) + excesses += flow[0] + for { + u := find_node_with_excess(excesses[1:n - 1]) or_break + u += 1 + residuals := graph[u] - flow[u] + if v, ok := find_admissible_edge(u, residuals[:], heights[:]); ok { + flow[u] = push(u, v, residuals[:], excesses[:]) + } else { + // relabel(u, v, graph, flow) + } + } + return +} + + +main :: proc() { + graph := create_graph(3, 3, 3, 3) + print_graph(graph, elem_sep = " ") + fmt.println() + print_graph(push_relabel(graph)) +}