Skip to content

Commit b1887a3

Browse files
author
Ubuntu
committed
add push relabel; biograph max match support multiple max flow algorithms
1 parent 4fcc63b commit b1887a3

File tree

2 files changed

+173
-16
lines changed

2 files changed

+173
-16
lines changed

graph/flowGraph.go

Lines changed: 131 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,21 @@ func (g *adjacencyMatrixResidual) init() *adjacencyMatrixResidual {
2121
func (g *adjacencyMatrixResidual) AddEdgeWithFlow(e edge, f int) {
2222
g.adjacencyMatrixWithFlow.AddEdgeWithFlow(e, f)
2323
if g.RCap(e) == 0 {
24-
g.DeleteEdge(e)
24+
//delete edge but keep cap and flow, because if residual flow (RCap) change, this edge should be added back
25+
g.adjacencyMatrix.DeleteEdge(e)
2526
}
2627
}
2728

2829
func (g *adjacencyMatrixResidual) RCap(e edge) int {
2930
return g.Cap(e) - g.Flow(e)
3031
}
3132

32-
func newResidualGraph() residualGraph {
33-
return new(adjacencyMatrixResidual).init()
33+
func newResidualGraph(g flowGraph) residualGraph {
34+
residualG := new(adjacencyMatrixResidual).init()
35+
for _, e := range g.AllEdges() {
36+
residualG.AddEdgeWithCap(e, g.Cap(e))
37+
}
38+
return residualG
3439
}
3540

3641
func augmentingPath(g residualGraph, s interface{}, t interface{}) (int, []edge) {
@@ -64,20 +69,135 @@ func updateFlow(rg residualGraph, g flowGraph, rc int, edges []edge) {
6469
}
6570
}
6671

67-
func edmondsKarp(g flowGraph, s interface{}, t interface{}) {
68-
residualG := newResidualGraph()
69-
for _, e := range g.AllEdges() {
70-
g.AddEdgeWithFlow(e, 0)
71-
residualG.AddEdgeWithCap(e, g.Cap(e))
72-
}
72+
func edmondesKarp(g flowGraph, s interface{}, t interface{}) {
73+
residualG := newResidualGraph(g)
7374

7475
for rc, edges := augmentingPath(residualG, s, t); len(edges) > 0; rc, edges = augmentingPath(residualG, s, t) {
7576
updateFlow(residualG, g, rc, edges)
7677
}
7778

7879
}
7980

80-
func bioGraphMaxMatch(g graph, l []interface{}) graph {
81+
type preFlowGraph interface {
82+
residualGraph
83+
SetHeight(interface{}, int)
84+
SetExcess(interface{}, int)
85+
Height(interface{}) int
86+
Excess(interface{}) int
87+
Push(edge) bool
88+
Relabel(interface{}) bool
89+
Overflow(interface{}) bool
90+
}
91+
92+
type adjacencyMatrixPreFlow struct {
93+
adjacencyMatrixResidual
94+
height, excess map[interface{}]int
95+
s, t interface{}
96+
}
97+
98+
func (g *adjacencyMatrixPreFlow) init(s, t interface{}) *adjacencyMatrixPreFlow {
99+
g.adjacencyMatrixResidual.init()
100+
g.height = make(map[interface{}]int)
101+
g.excess = make(map[interface{}]int)
102+
g.s = s
103+
g.t = t
104+
return g
105+
}
106+
107+
func (g *adjacencyMatrixPreFlow) SetHeight(v interface{}, h int) {
108+
g.height[v] = h
109+
}
110+
111+
func (g *adjacencyMatrixPreFlow) Height(v interface{}) int {
112+
if _, ok := g.height[v]; !ok {
113+
return 0
114+
}
115+
return g.height[v]
116+
}
117+
118+
func (g *adjacencyMatrixPreFlow) SetExcess(v interface{}, e int) {
119+
g.excess[v] = e
120+
}
121+
122+
func (g *adjacencyMatrixPreFlow) Excess(v interface{}) int {
123+
if _, ok := g.excess[v]; !ok {
124+
return 0
125+
}
126+
return g.excess[v]
127+
}
128+
129+
func (g *adjacencyMatrixPreFlow) Push(e edge) bool {
130+
if g.Overflow(e.Start) && g.RCap(e) > 0 && g.Height(e.Start) == g.Height(e.End)+1 {
131+
d := g.RCap(e)
132+
if g.Excess(e.Start) < d {
133+
d = g.Excess(e.Start)
134+
}
135+
flow := g.Flow(e) + d
136+
g.AddEdgeWithFlow(e, flow)
137+
re := edge{e.End, e.Start}
138+
g.AddEdgeWithFlow(re, 0-flow)
139+
g.SetExcess(e.Start, g.Excess(e.Start)-d)
140+
g.SetExcess(e.End, g.Excess(e.End)+d)
141+
return true
142+
}
143+
return false
144+
}
145+
146+
func (g *adjacencyMatrixPreFlow) Relabel(v interface{}) bool {
147+
if !g.Overflow(v) {
148+
return false
149+
}
150+
iter := g.IterConnectedVertices(v)
151+
minH := math.MaxInt32
152+
for end := iter.Value(); end != nil; end = iter.Next() {
153+
if g.Height(end) < minH {
154+
minH = g.Height(end)
155+
}
156+
if g.Height(v) > g.Height(end) {
157+
return false
158+
}
159+
}
160+
g.SetHeight(v, minH+1)
161+
return true
162+
}
163+
164+
func (g *adjacencyMatrixPreFlow) Overflow(v interface{}) bool {
165+
//According to definition, start and target vertex never overflow
166+
return v != g.s && v != g.t && g.Excess(v) > 0
167+
}
168+
169+
func newPreFlowGraph(g flowGraph, s interface{}, t interface{}) preFlowGraph {
170+
preFlowG := new(adjacencyMatrixPreFlow).init(s, t)
171+
vertices := g.AllVertices()
172+
for _, e := range g.AllEdges() {
173+
preFlowG.AddEdgeWithCap(e, g.Cap(e))
174+
}
175+
preFlowG.SetHeight(s, len(vertices))
176+
iter := g.IterConnectedVertices(s)
177+
for v := iter.Value(); v != nil; v = iter.Next() {
178+
c := g.Cap(edge{s, v})
179+
preFlowG.AddEdgeWithFlow(edge{s, v}, c)
180+
preFlowG.AddEdgeWithFlow(edge{v, s}, 0-c)
181+
preFlowG.SetExcess(v, c)
182+
preFlowG.SetExcess(s, preFlowG.Excess(s)-c)
183+
}
184+
return preFlowG
185+
}
186+
187+
func pushRelabel(g flowGraph, s interface{}, t interface{}) {
188+
preFlowG := newPreFlowGraph(g, s, t)
189+
for stop := false; !stop; {
190+
stop = true
191+
for _, e := range preFlowG.AllEdges() {
192+
stop = stop && !preFlowG.Push(e) && !preFlowG.Relabel(e.Start) && !preFlowG.Relabel(e.End)
193+
}
194+
}
195+
for _, e := range g.AllEdges() {
196+
g.AddEdgeWithFlow(e, preFlowG.Flow(e))
197+
}
198+
}
199+
200+
func bioGraphMaxMatch(g graph, l []interface{}, flowAlg func(g flowGraph, s interface{}, t interface{})) graph {
81201
//build flow graph
82202
fG := newFlowGraph()
83203
s := struct{ start string }{"s"}
@@ -91,7 +211,7 @@ func bioGraphMaxMatch(g graph, l []interface{}) graph {
91211
}
92212
}
93213

94-
edmondsKarp(fG, s, t)
214+
flowAlg(fG, s, t)
95215
matchG := newGraph()
96216
for _, e := range fG.AllEdges() {
97217
if fG.Flow(e) > 0 && e.Start != s && e.End != t {

graph/flowGraph_test.go

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,24 @@ func flowGraphGolden(g flowGraph) flowGraph {
3737
return flowG
3838
}
3939

40+
func pushRelabelGolden(g flowGraph) flowGraph {
41+
flowG := newFlowGraph()
42+
for _, e := range g.AllEdges() {
43+
flowG.AddEdgeWithCap(e, g.Cap(e))
44+
}
45+
flowG.AddEdgeWithFlow(edge{"s", "v1"}, 13)
46+
flowG.AddEdgeWithFlow(edge{"s", "v2"}, 10)
47+
flowG.AddEdgeWithFlow(edge{"v2", "v1"}, -1)
48+
flowG.AddEdgeWithFlow(edge{"v1", "v2"}, 1)
49+
flowG.AddEdgeWithFlow(edge{"v1", "v3"}, 12)
50+
flowG.AddEdgeWithFlow(edge{"v3", "v2"}, 0)
51+
flowG.AddEdgeWithFlow(edge{"v2", "v4"}, 11)
52+
flowG.AddEdgeWithFlow(edge{"v4", "v3"}, 7)
53+
flowG.AddEdgeWithFlow(edge{"v3", "t"}, 19)
54+
flowG.AddEdgeWithFlow(edge{"v4", "t"}, 4)
55+
return flowG
56+
}
57+
4058
func bioGraphMaxMatchSetup() (graph, []interface{}) {
4159
g := newGraph()
4260
g.AddEdgeBi(edge{"l0", "r0"})
@@ -50,14 +68,22 @@ func bioGraphMaxMatchSetup() (graph, []interface{}) {
5068
return g, []interface{}{"l0", "l1", "l2", "l3", "l4"}
5169
}
5270

53-
func bioGraphMaxMatchGolden() graph {
71+
func bioGraphMaxMatchGoldenByEdmondesKarp() graph {
5472
g := newGraph()
5573
g.AddEdgeBi(edge{"l0", "r0"})
5674
g.AddEdgeBi(edge{"l1", "r2"})
5775
g.AddEdgeBi(edge{"l2", "r1"})
5876
return g
5977
}
6078

79+
func bioGraphMaxMatchGoldenByPushRelabel() graph {
80+
g := newGraph()
81+
g.AddEdgeBi(edge{"l1", "r0"})
82+
g.AddEdgeBi(edge{"l4", "r2"})
83+
g.AddEdgeBi(edge{"l2", "r1"})
84+
return g
85+
}
86+
6187
func checkFlowGraphOutOfOrder(t *testing.T, g, gGolden flowGraph) {
6288
comparator := func(t *testing.T, v, vExp []interface{}, e, eExp []edge) {
6389
for _, e := range eExp {
@@ -74,15 +100,26 @@ func checkFlowGraphOutOfOrder(t *testing.T, g, gGolden flowGraph) {
74100
checkGraphOutOfOrderInString(t, g, gGolden, comparator)
75101
}
76102

77-
func TestEdmondsKarp(t *testing.T) {
103+
func TestEdmondesKarp(t *testing.T) {
78104
g := flowGraphSetup()
79-
edmondsKarp(g, "s", "t")
105+
edmondesKarp(g, "s", "t")
80106
gGolden := flowGraphGolden(g)
81107
checkFlowGraphOutOfOrder(t, g, gGolden)
82108
}
83109

110+
func TestPushRelabel(t *testing.T) {
111+
g := flowGraphSetup()
112+
pushRelabel(g, "s", "t")
113+
gGolden := pushRelabelGolden(g)
114+
checkFlowGraphOutOfOrder(t, g, gGolden)
115+
}
116+
84117
func TestBioGraphMaxMatch(t *testing.T) {
85-
g := bioGraphMaxMatch(bioGraphMaxMatchSetup())
86-
gGolden := bioGraphMaxMatchGolden()
118+
bioG, l := bioGraphMaxMatchSetup()
119+
gGolden := bioGraphMaxMatchGoldenByEdmondesKarp()
120+
g := bioGraphMaxMatch(bioG, l, edmondesKarp)
121+
checkGraphOutOfOrderInString(t, g, gGolden, nil)
122+
g = bioGraphMaxMatch(bioG, l, pushRelabel)
123+
gGolden = bioGraphMaxMatchGoldenByPushRelabel()
87124
checkGraphOutOfOrderInString(t, g, gGolden, nil)
88125
}

0 commit comments

Comments
 (0)