├── .gitignore ├── README.md ├── vector └── vector.go ├── graphs ├── graph.go ├── shortest_path.go ├── shortest_path_test.go ├── weighted_graph_test.go ├── utils.go ├── utils_test.go ├── weighted_graph.go ├── digraph.go └── digraph_test.go ├── combinatorics ├── permutations.go └── permutations_test.go └── primes ├── naive_sieve_test.go └── naive_sieve.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | :hocho: 2 | -------------------------------------------------------------------------------- /vector/vector.go: -------------------------------------------------------------------------------- 1 | package vector 2 | 3 | type Vector interface { 4 | Scale(float64) Vector 5 | Magnitude() float64 6 | Distance(Vector) float64 7 | Add(Vector) Vector 8 | } 9 | -------------------------------------------------------------------------------- /graphs/graph.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | type Graph interface { 4 | AddVertex(label string) 5 | AddEdge(src, destination string) 6 | CountVertices() int 7 | CountEdges() int 8 | } 9 | -------------------------------------------------------------------------------- /graphs/shortest_path.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | /* 4 | Return a list of id's representing the shortest path 5 | Params: 6 | * startId label for start id 7 | * endId label for end id 8 | */ 9 | -------------------------------------------------------------------------------- /graphs/shortest_path_test.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func _() { 9 | fmt.Println("black x6") 10 | } 11 | 12 | func TestShortestBetween(t *testing.T) { 13 | } 14 | -------------------------------------------------------------------------------- /graphs/weighted_graph_test.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func _() { 9 | fmt.Println("...") 10 | } 11 | 12 | func TestWeightedDiGraphVertex(t *testing.T) { 13 | a := WeightedDiGraphVertex{"a", nil} 14 | 15 | if a.Label != "a" { 16 | t.Fail() 17 | } 18 | 19 | b := WeightedDiGraphVertex{"b", nil} 20 | b.AddEdge(&a, 10) 21 | 22 | if len(b.Edges) != 1 || b.Edges[0].dst != &a { 23 | t.Fail() 24 | } 25 | } 26 | 27 | func TestWeightedUGraph(t *testing.T) { 28 | a := NewWeightedUGraph() 29 | 30 | if len(a.vertices) != 0 { 31 | t.Fail() 32 | } 33 | 34 | a.AddVertex("a") 35 | 36 | if len(a.vertices) != 1 || a.vertices["a"].Label != "a" { 37 | t.Fail() 38 | } 39 | 40 | a.AddVertex("b") 41 | a.AddEdge("a", "b", 10) 42 | 43 | if len(a.vertices["a"].Edges) != 1 && a.vertices["a"].Edges[0].dst.Label != "b" { 44 | t.Fail() 45 | } 46 | } 47 | 48 | func TestWDiShortestDistances(t *testing.T) { 49 | a := NewWeightedUGraph() 50 | a.AddVertex("a").AddVertex("b").AddVertex("c") 51 | a.AddEdge("a", "b", 3) 52 | a.AddEdge("b", "c", 3) 53 | a.AddEdge("a", "c", 10) 54 | 55 | d := a.ShortestDistances("a") 56 | 57 | if d["a"] != 0 { 58 | t.Fail() 59 | } 60 | 61 | if d["b"] != 3 { 62 | t.Fail() 63 | } 64 | 65 | if d["c"] != 6 { 66 | t.Fail() 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /combinatorics/permutations.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | func PCount(n, k int) int { 4 | result := 1 5 | for i := n - k; i <= n; i++ { 6 | result *= i 7 | } 8 | return result 9 | } 10 | 11 | func extend(lhs, rhs []int) []int { 12 | result := make([]int, len(lhs)+len(rhs), len(lhs)+len(rhs)) 13 | 14 | for i, _ := range lhs { 15 | result[i] = lhs[i] 16 | } 17 | 18 | for i, _ := range rhs { 19 | result[i+len(lhs)] = rhs[i] 20 | } 21 | 22 | return result 23 | } 24 | 25 | func factorial(n int) int64 { 26 | if n == 0 { 27 | return 1 28 | } 29 | 30 | var result int64 31 | 32 | result = int64(1) 33 | 34 | for i := int64(2); i <= int64(n); i += 1 { 35 | result *= i 36 | } 37 | return result 38 | } 39 | 40 | func P(lis []int, k int) [][]int { 41 | var result [][]int 42 | 43 | switch { 44 | // Stop case 45 | case k == 0: 46 | return make([][]int, 0, 0) 47 | 48 | // Trivial case 49 | case k == 1: 50 | result = make([][]int, len(lis), len(lis)) 51 | 52 | for i, v := range lis { 53 | u := []int{v} 54 | result[i] = make([]int, 1, 1) 55 | copy(result[i], u) 56 | } 57 | 58 | return result 59 | } 60 | 61 | n := len(lis) 62 | result = make([][]int, 0, PCount(n, k)) 63 | 64 | for i, v := range lis { 65 | current := []int{v} 66 | others := extend(lis[:i], lis[i+1:]) 67 | 68 | for _, v := range P(others, k-1) { 69 | item := extend(current, v) 70 | result = append(result, item) 71 | } 72 | } 73 | 74 | return result 75 | } 76 | -------------------------------------------------------------------------------- /combinatorics/permutations_test.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestExtend(t *testing.T) { 8 | a := extend([]int{}, []int{}) 9 | 10 | if len(a) != 0 { 11 | t.Fail() 12 | } 13 | 14 | b := extend([]int{1, 2, 3}, []int{4, 5}) 15 | 16 | if len(b) != 5 { 17 | t.Fail() 18 | } 19 | 20 | if b[3] != 4 { 21 | t.Fail() 22 | } 23 | 24 | if b[4] != 5 { 25 | t.Fail() 26 | } 27 | } 28 | 29 | func TestX(t *testing.T) { 30 | } 31 | 32 | func IsEqualIntArray(lhs, rhs []int) bool { 33 | if len(lhs) != len(rhs) { 34 | return false 35 | } 36 | 37 | for i, _ := range lhs { 38 | if lhs[i] != rhs[i] { 39 | return false 40 | } 41 | } 42 | 43 | return true 44 | } 45 | 46 | func IsEqualIntArrayArray(lhs, rhs [][]int) bool { 47 | if len(lhs) != len(rhs) { 48 | return false 49 | } 50 | 51 | for i, _ := range lhs { 52 | if !IsEqualIntArray(lhs[i], rhs[i]) { 53 | return false 54 | } 55 | } 56 | 57 | return true 58 | } 59 | 60 | func TestC(t *testing.T) { 61 | vals := []int{1, 2, 3} 62 | 63 | if !IsEqualIntArrayArray(P(vals, 0), [][]int{}) { 64 | t.Fail() 65 | } 66 | 67 | x := [][]int{[]int{1}, []int{2}, []int{3}} 68 | 69 | if !IsEqualIntArrayArray(P(vals, 1), x) { 70 | t.Fail() 71 | } 72 | 73 | y := P(vals, 1) 74 | 75 | if len(y) != 3 { 76 | t.Fail() 77 | } 78 | 79 | z := P(vals, 2) 80 | 81 | if len(z) != 6 { 82 | t.Fail() 83 | } 84 | 85 | vals2 := []int{0, 1, 2, 3, 4} 86 | a := P(vals2, 5) 87 | 88 | if len(a) != 120 { 89 | t.Fail() 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /graphs/utils.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | func MinElement(values *map[string]float64) (string, float64) { 8 | minVal := math.Inf(1) 9 | minInd := "" 10 | 11 | for label, val := range *values { 12 | if val <= minVal { 13 | minVal = val 14 | minInd = label 15 | } 16 | } 17 | return minInd, minVal 18 | } 19 | 20 | func unpick(values *map[string]float64, keys ...string) map[string]float64 { 21 | picked := make(map[string]float64) 22 | 23 | for label, v := range *values { 24 | picked[label] = v 25 | } 26 | 27 | keyMap := make(map[string]bool) 28 | 29 | for _, label := range keys { 30 | keyMap[label] = true 31 | } 32 | 33 | for label, _ := range *values { 34 | _, exists := keyMap[label] 35 | 36 | if exists { 37 | delete(picked, label) 38 | } 39 | } 40 | 41 | return picked 42 | } 43 | 44 | func pick(values *map[string]float64, keys ...string) map[string]float64 { 45 | picked := make(map[string]float64) 46 | 47 | for _, v := range keys { 48 | value, exists := (*values)[v] 49 | if exists { 50 | picked[v] = value 51 | } 52 | } 53 | 54 | return picked 55 | } 56 | 57 | func keys(values *map[string]float64) []string { 58 | results := make([]string, len(*values)) 59 | i := 0 60 | 61 | for label, _ := range *values { 62 | results[i] = label 63 | i++ 64 | } 65 | 66 | return results 67 | } 68 | 69 | func keysBool(values *map[string]bool) []string { 70 | results := make([]string, len(*values)) 71 | i := 0 72 | 73 | for label, _ := range *values { 74 | results[i] = label 75 | i++ 76 | } 77 | 78 | return results 79 | } 80 | -------------------------------------------------------------------------------- /graphs/utils_test.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func _() { 9 | fmt.Println("...") 10 | } 11 | 12 | func StringsEqual(lhs, rhs []string) bool { 13 | if len(lhs) != len(rhs) { 14 | return false 15 | } 16 | 17 | for i, _ := range lhs { 18 | if lhs[i] != rhs[i] { 19 | return false 20 | } 21 | } 22 | 23 | return true 24 | } 25 | 26 | func TestMinElement(t *testing.T) { 27 | a := map[string]float64{ 28 | "red": 23.0, 29 | "blue": -200.0, 30 | "y": 200.0, 31 | } 32 | label, result := MinElement(&a) 33 | if label != "blue" || result != -200.0 { 34 | t.Fail() 35 | } 36 | } 37 | 38 | func TestPick(t *testing.T) { 39 | m := map[string]float64{ 40 | "a": 10.0, 41 | "b": 23.5, 42 | "c": 87.3, 43 | "d": 10.0, 44 | } 45 | 46 | keys := []string{"b", "c", "d"} 47 | 48 | if len(pick(&m, "a", "d")) != 2 { 49 | t.Fail() 50 | } 51 | 52 | if len(pick(&m, "whatever")) != 0 { 53 | t.Fail() 54 | } 55 | 56 | picked := pick(&m, keys...) 57 | 58 | if len(picked) != 3 { 59 | t.Fail() 60 | } 61 | 62 | if picked["b"] != 23.5 { 63 | t.Fail() 64 | } 65 | } 66 | 67 | func TestUnpick(t *testing.T) { 68 | m := map[string]float64{ 69 | "a": 10.0, 70 | "b": 23.5, 71 | "c": 87.3, 72 | "d": 10.0, 73 | } 74 | 75 | if len(unpick(&m, "a")) != 3 { 76 | t.Fail() 77 | } 78 | 79 | results := unpick(&m, "a", "b") 80 | 81 | if results["c"] != 87.3 { 82 | t.Fail() 83 | } 84 | } 85 | 86 | func TestKeys(t *testing.T) { 87 | m := map[string]float64{ 88 | "a": 10.0, 89 | "b": 23.5, 90 | "c": 87.3, 91 | "d": 10.0, 92 | } 93 | 94 | if len(keys(&m)) != 4 { 95 | t.Fail() 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /primes/naive_sieve_test.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func mapEquals(lhs, rhs map[int]int) bool { 9 | if len(lhs) != len(rhs) { 10 | return false 11 | } 12 | 13 | for k, _ := range lhs { 14 | if lhs[k] != rhs[k] { 15 | return false 16 | } 17 | } 18 | 19 | return true 20 | } 21 | 22 | func TestMapEquals(t *testing.T) { 23 | a := map[int]int{ 24 | 1: 10, 25 | 2: 2, 26 | } 27 | 28 | b := map[int]int{ 29 | 2: 2, 30 | 1: 10, 31 | } 32 | 33 | c := map[int]int{ 34 | 2: 2, 35 | 1: 10, 36 | 3: 5, 37 | } 38 | 39 | if !mapEquals(a, b) { 40 | t.Fail() 41 | } 42 | 43 | if mapEquals(a, c) { 44 | t.Fail() 45 | } 46 | } 47 | 48 | func TestNaiveSieve(t *testing.T) { 49 | sieve := NewNaiveSieve(10) 50 | 51 | if len(sieve.Primes()) != 4 { 52 | t.Fail() 53 | } 54 | 55 | if !sieve.Contains(3) { 56 | t.Fail() 57 | } 58 | 59 | if sieve.Contains(6) { 60 | t.Fail() 61 | } 62 | } 63 | 64 | func TestFactorize(t *testing.T) { 65 | sieve := NewNaiveSieve(1000) 66 | if len(sieve.PrimeFactorize(13)) != 1 { 67 | t.Fail() 68 | } 69 | 70 | if !mapEquals(sieve.PrimeFactorize(13), map[int]int{13: 1}) { 71 | t.Fail() 72 | } 73 | 74 | if !mapEquals(sieve.PrimeFactorize(169), map[int]int{13: 2}) { 75 | t.Fail() 76 | } 77 | } 78 | 79 | func TestTotient(t *testing.T) { 80 | s := NewNaiveSieve(1000) 81 | 82 | expected := map[int]int{ 83 | 2: 1, 84 | 3: 2, 85 | 4: 2, 86 | 5: 4, 87 | 6: 2, 88 | 7: 6, 89 | 8: 4, 90 | 9: 6, 91 | 10: 4, 92 | } 93 | 94 | for n, totient := range expected { 95 | v := s.Totient(n) 96 | if v != totient { 97 | fmt.Printf("T(%d) = %d != %d\n", n, v, totient) 98 | t.Fail() 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /primes/naive_sieve.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | type NaiveSieve struct { 8 | sieve map[int]bool 9 | primes []int 10 | } 11 | 12 | func NewNaiveSieve(limit int) NaiveSieve { 13 | 14 | /** Compute Prime Sieve **/ 15 | sieve := make(map[int]bool) 16 | primes := make([]int, 1) 17 | 18 | sieve[2] = true 19 | primes[0] = 2 20 | 21 | for n := 3; n < limit; n += 2 { 22 | if IsNaivePrime(n) { 23 | sieve[n] = true 24 | primes = append(primes, n) 25 | } 26 | } 27 | 28 | return NaiveSieve{sieve, primes} 29 | } 30 | 31 | func (self *NaiveSieve) Contains(n int) bool { 32 | _, ok := self.sieve[n] 33 | return ok 34 | } 35 | 36 | func (self *NaiveSieve) PrimeFactorize(n int) map[int]int { 37 | factors := make(map[int]int) 38 | 39 | i := 0 40 | v := self.primes[i] 41 | 42 | for v <= n { 43 | 44 | if n%v == 0 { 45 | n /= v 46 | factors[v] += 1 47 | } else { 48 | // Update conditions 49 | i += 1 50 | v = self.primes[i] 51 | } 52 | } 53 | 54 | return factors 55 | } 56 | 57 | /* 58 | Return the totient phi-function of a number n 59 | 60 | NOTE: This attempts to keep the value as low as possible, 61 | so it completed the totient function in 2-passes: 62 | 1. Reduce 63 | 2. Multiply 64 | */ 65 | func (s *NaiveSieve) Totient(n int) int { 66 | result := n 67 | factors := s.PrimeFactorize(n) 68 | primes := make([]int, 0) 69 | 70 | for p, _ := range factors { 71 | primes = append(primes, p) 72 | } 73 | 74 | for _, p := range primes { 75 | result /= p 76 | } 77 | 78 | for _, p := range primes { 79 | result *= p - 1 80 | } 81 | 82 | return result 83 | } 84 | 85 | func (self *NaiveSieve) Primes() []int { 86 | return self.primes 87 | } 88 | 89 | func IsNaivePrime(n int) bool { 90 | switch { 91 | case n == 1: 92 | return false 93 | case n == 2: 94 | return true 95 | case n%2 == 0: 96 | return false 97 | } 98 | 99 | limit := int(math.Sqrt(float64(n))) 100 | 101 | for i := 3; i <= limit; i += 2 { 102 | if n%i == 0 { 103 | return false 104 | } 105 | } 106 | 107 | return true 108 | } 109 | -------------------------------------------------------------------------------- /graphs/weighted_graph.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | type WeightedDiGraphEdge struct { 9 | weight float64 10 | src *WeightedDiGraphVertex 11 | dst *WeightedDiGraphVertex 12 | } 13 | 14 | func (s *WeightedDiGraphEdge) String() string { 15 | return fmt.Sprintf("[%s %s]: %0.1f", s.src.Label, s.dst.Label, s.weight) 16 | } 17 | 18 | type WeightedDiGraphVertex struct { 19 | Label string 20 | Edges []*WeightedDiGraphEdge 21 | } 22 | 23 | func (s *WeightedDiGraphVertex) AddEdge(n *WeightedDiGraphVertex, weight float64) { 24 | e := WeightedDiGraphEdge{weight, s, n} 25 | s.Edges = append(s.Edges, &e) 26 | } 27 | 28 | /* 29 | Graph Helper 30 | */ 31 | 32 | type WeightedUGraph struct { 33 | vertices map[string]*WeightedDiGraphVertex 34 | } 35 | 36 | func NewWeightedUGraph() WeightedUGraph { 37 | return WeightedUGraph{make(map[string]*WeightedDiGraphVertex)} 38 | } 39 | 40 | func (s *WeightedUGraph) AddVertex(label string) *WeightedUGraph { 41 | n := WeightedDiGraphVertex{label, nil} 42 | s.vertices[label] = &n 43 | return s 44 | } 45 | 46 | func (s *WeightedUGraph) AddEdge(src, dest string, weight float64) *WeightedUGraph { 47 | source := s.vertices[src] 48 | destination := s.vertices[dest] 49 | 50 | source.AddEdge(destination, weight) 51 | // destination.AddEdge(source, weight) 52 | 53 | return s 54 | } 55 | 56 | /* 57 | Djikstra's Shortest Path Algorithm (Poorly) Implemented 58 | Return a map of distances 59 | */ 60 | func (s *WeightedUGraph) ShortestDistances(src string) map[string]float64 { 61 | visited := make(map[string]bool) 62 | 63 | // Create vertex set 64 | q := make(map[string]bool) 65 | distances := make(map[string]float64) 66 | prev := make(map[string]*WeightedDiGraphVertex) 67 | 68 | for _, v := range s.vertices { 69 | q[v.Label] = true 70 | distances[v.Label] = math.Inf(1) 71 | prev[v.Label] = nil 72 | } 73 | 74 | distances[src] = 0 75 | 76 | for len(q) > 0 { 77 | unvisitedDistances := unpick(&distances, keysBool(&visited)...) 78 | label, _ := MinElement(&unvisitedDistances) 79 | delete(q, label) 80 | visited[label] = true 81 | 82 | u := s.vertices[label] 83 | 84 | for _, e := range u.Edges { 85 | _, ok := q[e.dst.Label] 86 | 87 | if !ok { 88 | continue 89 | } 90 | 91 | alt := distances[u.Label] + e.weight 92 | v := e.dst 93 | 94 | if alt < distances[v.Label] { 95 | distances[v.Label] = alt 96 | prev[v.Label] = u 97 | } 98 | } 99 | } 100 | 101 | return distances 102 | } 103 | 104 | func _() { 105 | fmt.Println() 106 | } 107 | -------------------------------------------------------------------------------- /graphs/digraph.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func extend(lhs, rhs []string) []string { 8 | result := make([]string, len(lhs)+len(rhs), len(lhs)+len(rhs)) 9 | 10 | for i, _ := range lhs { 11 | result[i] = lhs[i] 12 | } 13 | 14 | for i, _ := range rhs { 15 | result[i+len(lhs)] = rhs[i] 16 | } 17 | 18 | return result 19 | } 20 | 21 | func IndexOfString(slice []string, needle string) int { 22 | for i, v := range slice { 23 | if v == needle { 24 | return i 25 | } 26 | } 27 | return -1 28 | } 29 | 30 | type DiGraphNode struct { 31 | Label string 32 | Children []*DiGraphNode 33 | } 34 | 35 | func (self *DiGraphNode) ConnectNode(g *DiGraphNode) { 36 | for _, child := range self.Children { 37 | if child == g { 38 | return 39 | } 40 | } 41 | self.Children = append(self.Children, g) 42 | } 43 | 44 | func (self *DiGraphNode) GetEdgeLabels() []string { 45 | edgeLabels := make([]string, len(self.Children)) 46 | for i, h := range self.Children { 47 | edgeLabels[i] = h.Label 48 | } 49 | return edgeLabels 50 | } 51 | 52 | type DiGraph struct { 53 | vertices map[string]*DiGraphNode 54 | } 55 | 56 | func NewDiGraph() DiGraph { 57 | return DiGraph{make(map[string]*DiGraphNode)} 58 | } 59 | 60 | func (self *DiGraph) CountNodes() int { 61 | return len(self.vertices) 62 | } 63 | 64 | func (self *DiGraph) CountEdges() int { 65 | edges := make(map[string][]string) 66 | 67 | for _, g := range self.vertices { 68 | for _, h := range g.Children { 69 | edges[g.Label] = append(edges[g.Label], h.Label) 70 | } 71 | } 72 | 73 | size := 0 74 | 75 | for _, v := range edges { 76 | size += len(v) 77 | } 78 | 79 | return size 80 | } 81 | 82 | func (self *DiGraph) AddNode(label string) { 83 | if _, ok := self.vertices[label]; ok { 84 | panic("A node already exists with that label") 85 | } else { 86 | self.vertices[label] = &DiGraphNode{label, nil} 87 | } 88 | } 89 | 90 | func (self *DiGraph) AddConnection(src, dest string) { 91 | g, g_ok := self.vertices[src] 92 | h, h_ok := self.vertices[dest] 93 | 94 | if g_ok && h_ok { 95 | g.ConnectNode(h) 96 | } else { 97 | panic("One of the nodes is missing for this edge") 98 | } 99 | } 100 | 101 | func (self *DiGraph) GetCyclesFor(label string, size int) [][]string { 102 | return getCycles(self.vertices[label], []string{}, size) 103 | } 104 | 105 | func getCycles(g *DiGraphNode, visited []string, size int) [][]string { 106 | 107 | switch { 108 | case g == nil || visited == nil: 109 | return [][]string{} 110 | 111 | case len(visited) > 0 && visited[0] == g.Label: 112 | newVisited := extend(visited, []string{g.Label}) 113 | return [][]string{newVisited} 114 | 115 | case size == 0: 116 | return [][]string{} 117 | 118 | case IndexOfString(visited, g.Label) != -1: 119 | return [][]string{} 120 | } 121 | 122 | results := make([][]string, 0) 123 | newVisited := append(visited, g.Label) 124 | 125 | for _, h := range g.Children { 126 | 127 | newSize := size 128 | if newSize != -1 { 129 | newSize -= 1 130 | } 131 | 132 | for _, cycle := range getCycles(h, newVisited, newSize) { 133 | results = append(results, cycle) 134 | } 135 | } 136 | 137 | return results 138 | } 139 | 140 | func _() { 141 | fmt.Println("...") 142 | } 143 | -------------------------------------------------------------------------------- /graphs/digraph_test.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestDiGraphNode(t *testing.T) { 10 | g := DiGraphNode{"g", nil} 11 | h := DiGraphNode{"h", nil} 12 | 13 | if len(g.Children) != 0 { 14 | t.Fail() 15 | } 16 | 17 | g.ConnectNode(&h) 18 | 19 | if len(g.Children) != 1 { 20 | t.Fail() 21 | } 22 | 23 | if g.Children[0].Label != "h" { 24 | t.Fail() 25 | } 26 | 27 | h.Label = "whatever" 28 | 29 | if g.Children[0].Label != "whatever" { 30 | t.Fail() 31 | } 32 | } 33 | 34 | func TestDiGraph(t *testing.T) { 35 | g := NewDiGraph() 36 | 37 | if g.CountNodes() != 0 { 38 | t.Fail() 39 | } 40 | 41 | g.AddNode("start") 42 | g.AddNode("end") 43 | 44 | if g.CountNodes() != 2 { 45 | t.Fail() 46 | } 47 | 48 | if g.CountEdges() != 0 { 49 | t.Fail() 50 | } 51 | 52 | g.AddConnection("start", "end") 53 | 54 | if g.CountEdges() != 1 { 55 | fmt.Println(g.CountEdges()) 56 | t.Fail() 57 | } 58 | 59 | g.AddConnection("end", "start") 60 | 61 | if g.CountEdges() != 2 { 62 | fmt.Println(g.CountEdges()) 63 | t.Fail() 64 | } 65 | 66 | g.AddNode("whatever") 67 | g.AddConnection("whatever", "end") 68 | g.AddConnection("whatever", "start") 69 | g.AddConnection("start", "whatever") 70 | 71 | if g.CountEdges() != 5 { 72 | fmt.Println(g.CountEdges()) 73 | t.Fail() 74 | } 75 | } 76 | 77 | func TestSimpleDiGraph(t *testing.T) { 78 | g := NewDiGraph() 79 | g.AddNode("a") 80 | g.AddNode("b") 81 | g.AddNode("c") 82 | g.AddNode("d1") 83 | g.AddNode("d2") 84 | g.AddConnection("a", "b") 85 | g.AddConnection("b", "c") 86 | g.AddConnection("c", "d1") 87 | g.AddConnection("d1", "a") 88 | g.AddConnection("c", "d2") 89 | g.AddConnection("d2", "a") 90 | // g.AddConnection("d", "b") 91 | 92 | // g.AddConnection("e", "a") 93 | // g.AddConnection("a", "c") 94 | // g.AddConnection("e", "f") 95 | // g.AddConnection("a", "B2") 96 | // g.AddConnection("B2", "c") 97 | // g.AddConnection("B2", "d") 98 | // g.AddConnection("c", "a") 99 | 100 | cycles3 := getCycles(g.vertices["a"], []string{"a", "b", "c", "d2"}, -1) 101 | 102 | if strings.Join(cycles3[0], ",") != "a,b,c,d2,a" { 103 | t.Fail() 104 | } 105 | 106 | cycles := getCycles(g.vertices["a"], []string{}, -1) 107 | 108 | if len(cycles) != 2 { 109 | t.Fail() 110 | } 111 | 112 | cycles2 := getCycles(nil, nil, -1) 113 | 114 | if len(cycles2) != 0 { 115 | t.Fail() 116 | } 117 | 118 | g2 := NewDiGraph() 119 | g2.AddNode("a") 120 | g2.AddNode("b") 121 | g2.AddNode("c") 122 | g2.AddNode("d") 123 | g2.AddNode("f") 124 | g2.AddNode("g") 125 | g2.AddConnection("a", "b") 126 | g2.AddConnection("b", "c") 127 | g2.AddConnection("c", "a") 128 | g2.AddConnection("c", "d") 129 | g2.AddConnection("d", "a") 130 | g2.AddConnection("a", "f") 131 | g2.AddConnection("f", "g") 132 | g2.AddConnection("g", "a") 133 | 134 | cycles4 := g2.GetCyclesFor("a", -1) 135 | 136 | if len(cycles4) != 3 { 137 | t.Fail() 138 | } 139 | 140 | g3 := NewDiGraph() 141 | g3.AddNode("a") 142 | g3.AddNode("b") 143 | g3.AddNode("c") 144 | g3.AddConnection("b", "c") 145 | g3.AddConnection("c", "b") 146 | 147 | noCycles := g3.GetCyclesFor("a", -1) 148 | 149 | if len(noCycles) != 0 { 150 | t.Fail() 151 | } 152 | 153 | oneCycle := g3.GetCyclesFor("b", -1) 154 | 155 | if len(oneCycle) != 1 { 156 | t.Fail() 157 | } 158 | } 159 | 160 | func TestDiGraphMethods(t *testing.T) { 161 | g := NewDiGraph() 162 | g.AddNode("a") 163 | g.AddNode("b") 164 | g.AddNode("c") 165 | g.AddNode("d") 166 | g.AddConnection("a", "b") 167 | g.AddConnection("b", "c") 168 | g.AddConnection("c", "d") 169 | g.AddConnection("d", "a") 170 | 171 | if g.CountNodes() != 4 { 172 | t.Fail() 173 | } 174 | 175 | if g.CountEdges() != 4 { 176 | t.Fail() 177 | } 178 | } 179 | 180 | func _() { 181 | fmt.Println("NOOP") 182 | } 183 | --------------------------------------------------------------------------------