File: union.go

package info (click to toggle)
golang-github-yourbasic-graph 1.0.5-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 400 kB
  • sloc: makefile: 2
file content (90 lines) | stat: -rw-r--r-- 2,161 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package build

// Union returns the graph union g1 ∪ g2, which
// consists of the union of the two vertex sets
// and the union of the two edge sets of g1 and g2.
// The edges of the new graph will have zero cost.
func (g1 *Virtual) Union(g2 *Virtual) *Virtual {
	return g1.union(g2, false)
}

// If cost is true keep costs and use g1's cost for edges that belong to both g1 and g2.
func (g1 *Virtual) union(g2 *Virtual, cost bool) *Virtual {
	switch {
	case g1.order == 0:
		if cost {
			return g2
		}
		return g2.AddCost(0)
	case g2.order == 0:
		if cost {
			return g1
		}
		return g1.AddCost(0)
	}

	newCost := zero
	if cost {
		newCost = func(v, w int) int64 {
			if g2.edge(v, w) && !g1.edge(v, w) {
				return g2.cost(v, w)
			}
			return g1.cost(v, w)
		}
	}
	var res *Virtual
	switch {
	case g1.order == g2.order:
		res = generic(g1.order, newCost, func(v, w int) bool {
			return g1.edge(v, w) || g2.edge(v, w)
		})
	case g1.order < g2.order:
		res = generic(g2.order, newCost, func(v, w int) bool {
			return v < g1.order && w < g1.order && g1.edge(v, w) || g2.edge(v, w)
		})
	default:
		res = generic(g1.order, newCost, func(v, w int) bool {
			return v < g2.order && w < g2.order && g2.edge(v, w) || g1.edge(v, w)
		})
	}

	res.visit = func(v int, a int, do func(w int, c int64) bool) (aborted bool) {
		next := 0
		if v < g1.order && g1.visit(v, a, func(w int, c int64) (skip bool) {
			// First all neighbors from g2 that are less than w...
			if next != w && v < g2.order && a <= w {
				if more := false; g2.visit(v, max(next, a), func(w0 int, c0 int64) (skip bool) {
					if w0 >= w {
						more, skip = true, true
						return
					}
					if cost {
						return do(w0, c0)
					}
					return do(w0, 0)
				}) && !more {
					return true
				}
			}
			// ...then w.
			switch {
			case cost && do(w, c):
				return true
			case !cost && do(w, 0):
				return true
			}
			next = w + 1
			return
		}) {
			return true
		}
		// When done with g1, produce any leftovers from g2.
		return v < g2.order && g2.visit(v, max(next, a), func(w int, c int64) (skip bool) {
			if cost {
				return do(w, c)
			}
			return do(w, 0)
		})
	}
	return res
}