227 lines
4.7 KiB
Go
227 lines
4.7 KiB
Go
package gago
|
|
|
|
import "errors"
|
|
|
|
// A Slice is a genome with a list-like structure.
|
|
type Slice interface {
|
|
At(i int) interface{}
|
|
Set(i int, v interface{})
|
|
Len() int
|
|
Swap(i, j int)
|
|
Slice(a, b int) Slice
|
|
Split(k int) (Slice, Slice)
|
|
Append(Slice) Slice
|
|
Replace(Slice)
|
|
Copy() Slice
|
|
}
|
|
|
|
// Search for the first index of an element in a Slice.
|
|
func search(v interface{}, s Slice) (int, error) {
|
|
for i := 0; i < s.Len(); i++ {
|
|
if s.At(i) == v {
|
|
return i, nil
|
|
}
|
|
}
|
|
// Element not in slice
|
|
return 0, errors.New("Value not contained in slice")
|
|
}
|
|
|
|
// Make a lookup table from a slice, mapping values to indexes.
|
|
func newIndexLookup(s Slice) map[interface{}]int {
|
|
var lookup = make(map[interface{}]int)
|
|
for i := 0; i < s.Len(); i++ {
|
|
lookup[s.At(i)] = i
|
|
}
|
|
return lookup
|
|
}
|
|
|
|
// getCycles determines the cycles that exist between two slices. A cycle is a
|
|
// list of indexes indicating mirroring values between each slice.
|
|
func getCycles(s1, s2 Slice) (cycles [][]int) {
|
|
var (
|
|
s1Lookup = newIndexLookup(s1) // Matches values to indexes for quick lookup
|
|
visited = make(map[int]bool) // Indicates if an index is already in a cycle or not
|
|
)
|
|
for i := 0; i < s1.Len(); i++ {
|
|
if !visited[i] {
|
|
visited[i] = true
|
|
var (
|
|
cycle = []int{i}
|
|
j = s1Lookup[s2.At(i)]
|
|
)
|
|
// Continue building the cycle until it closes in on itself
|
|
for j != cycle[0] {
|
|
cycle = append(cycle, j)
|
|
visited[j] = true
|
|
j = s1Lookup[s2.At(j)]
|
|
}
|
|
cycles = append(cycles, cycle)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// getNeighbours converts a slice into an adjacency map mapping values to left
|
|
// and right neighbours. The values of the map are sets.
|
|
func getNeighbours(s Slice) map[interface{}]set {
|
|
var (
|
|
neighbours = make(map[interface{}]set)
|
|
n = s.Len()
|
|
)
|
|
neighbours[s.At(0)] = set{s.At(n - 1): true, s.At(1): true}
|
|
for i := 1; i < n-1; i++ {
|
|
neighbours[s.At(i)] = set{s.At(i - 1): true, s.At(i + 1): true}
|
|
}
|
|
neighbours[s.At(n-1)] = set{s.At(n - 2): true, s.At(0): true}
|
|
return neighbours
|
|
}
|
|
|
|
// IntSlice attaches the methods of Slice to []float64
|
|
type IntSlice []int
|
|
|
|
// At method from Slice
|
|
func (s IntSlice) At(i int) interface{} {
|
|
return s[i]
|
|
}
|
|
|
|
// Set method from Slice
|
|
func (s IntSlice) Set(i int, v interface{}) {
|
|
s[i] = v.(int)
|
|
}
|
|
|
|
// Len method from Slice
|
|
func (s IntSlice) Len() int {
|
|
return len(s)
|
|
}
|
|
|
|
// Swap method from Slice
|
|
func (s IntSlice) Swap(i, j int) {
|
|
s[i], s[j] = s[j], s[i]
|
|
}
|
|
|
|
// Slice method from Slice
|
|
func (s IntSlice) Slice(a, b int) Slice {
|
|
return s[a:b]
|
|
}
|
|
|
|
// Split method from Slice
|
|
func (s IntSlice) Split(k int) (Slice, Slice) {
|
|
return s[:k], s[k:]
|
|
}
|
|
|
|
// Append method from Slice
|
|
func (s IntSlice) Append(t Slice) Slice {
|
|
return append(s, t.(IntSlice)...)
|
|
}
|
|
|
|
// Replace method from Slice
|
|
func (s IntSlice) Replace(t Slice) {
|
|
copy(s, t.(IntSlice))
|
|
}
|
|
|
|
// Copy method from Slice
|
|
func (s IntSlice) Copy() Slice {
|
|
var t = make(IntSlice, len(s))
|
|
copy(t, s)
|
|
return t
|
|
}
|
|
|
|
// Float64Slice attaches the methods of Slice to []float64
|
|
type Float64Slice []float64
|
|
|
|
// At method from Slice
|
|
func (s Float64Slice) At(i int) interface{} {
|
|
return s[i]
|
|
}
|
|
|
|
// Set method from Slice
|
|
func (s Float64Slice) Set(i int, v interface{}) {
|
|
s[i] = v.(float64)
|
|
}
|
|
|
|
// Len method from Slice
|
|
func (s Float64Slice) Len() int {
|
|
return len(s)
|
|
}
|
|
|
|
// Swap method from Slice
|
|
func (s Float64Slice) Swap(i, j int) {
|
|
s[i], s[j] = s[j], s[i]
|
|
}
|
|
|
|
// Slice method from Slice
|
|
func (s Float64Slice) Slice(a, b int) Slice {
|
|
return s[a:b]
|
|
}
|
|
|
|
// Split method from Slice
|
|
func (s Float64Slice) Split(k int) (Slice, Slice) {
|
|
return s[:k], s[k:]
|
|
}
|
|
|
|
// Append method from Slice
|
|
func (s Float64Slice) Append(t Slice) Slice {
|
|
return append(s, t.(Float64Slice)...)
|
|
}
|
|
|
|
// Replace method from Slice
|
|
func (s Float64Slice) Replace(t Slice) {
|
|
copy(s, t.(Float64Slice))
|
|
}
|
|
|
|
// Copy method from Slice
|
|
func (s Float64Slice) Copy() Slice {
|
|
var t = make(Float64Slice, len(s))
|
|
copy(t, s)
|
|
return t
|
|
}
|
|
|
|
// StringSlice attaches the methods of Slice to []float64
|
|
type StringSlice []string
|
|
|
|
// At method from Slice
|
|
func (s StringSlice) At(i int) interface{} {
|
|
return s[i]
|
|
}
|
|
|
|
// Set method from Slice
|
|
func (s StringSlice) Set(i int, v interface{}) {
|
|
s[i] = v.(string)
|
|
}
|
|
|
|
// Len method from Slice
|
|
func (s StringSlice) Len() int {
|
|
return len(s)
|
|
}
|
|
|
|
// Swap method from Slice
|
|
func (s StringSlice) Swap(i, j int) {
|
|
s[i], s[j] = s[j], s[i]
|
|
}
|
|
|
|
// Slice method from Slice
|
|
func (s StringSlice) Slice(a, b int) Slice {
|
|
return s[a:b]
|
|
}
|
|
|
|
// Split method from Slice
|
|
func (s StringSlice) Split(k int) (Slice, Slice) {
|
|
return s[:k], s[k:]
|
|
}
|
|
|
|
// Append method from Slice
|
|
func (s StringSlice) Append(t Slice) Slice {
|
|
return append(s, t.(StringSlice)...)
|
|
}
|
|
|
|
// Replace method from Slice
|
|
func (s StringSlice) Replace(t Slice) {
|
|
copy(s, t.(StringSlice))
|
|
}
|
|
|
|
// Copy method from Slice
|
|
func (s StringSlice) Copy() Slice {
|
|
var t = make(StringSlice, len(s))
|
|
copy(t, s)
|
|
return t
|
|
}
|