-
Notifications
You must be signed in to change notification settings - Fork 8
/
partition.go
167 lines (151 loc) · 3.7 KB
/
partition.go
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package align
import (
"bytes"
"fmt"
)
type PartitionSet struct {
names []string // The name of each partition
partitions []int // The partition of each site
models []string // The name of the model for each partition
length int // Length of alignment
}
func NewPartitionSet(alignmentLength int) (ps *PartitionSet) {
partitions := make([]int, alignmentLength)
for i := 0; i < alignmentLength; i++ {
partitions[i] = -1
}
ps = &PartitionSet{
names: make([]string, 0),
models: make([]string, 0),
partitions: partitions,
length: alignmentLength,
}
return
}
func (ps *PartitionSet) AddRange(partName, modelName string, start, end, modulo int) (err error) {
if start < 0 {
err = fmt.Errorf("Start of partition is outside of alignment: %d", start)
return
}
if end >= ps.length {
err = fmt.Errorf("End of partition is outside of alignment: %d", end)
return
}
if modulo <= 0 {
err = fmt.Errorf("'Modulo' value is not authorized: %d", modulo)
return
}
partitionIndex := -1
for i, p := range ps.names {
if p == partName {
partitionIndex = i
break
}
}
// New partition name
if partitionIndex == -1 {
ps.names = append(ps.names, partName)
ps.models = append(ps.models, modelName)
partitionIndex = len(ps.names) - 1
}
for i := start; i <= end; i += modulo {
if ps.partitions[i] != -1 {
err = fmt.Errorf("Several partitions are defined for site %d ", i)
return
}
ps.partitions[i] = partitionIndex
}
return
}
// If not all sites are in a partition, returns an error
func (ps *PartitionSet) CheckSites() (err error) {
for j, p := range ps.partitions {
if p == -1 {
err = fmt.Errorf("Not all sites are in a partition (%d)", j)
return
}
}
return
}
func (ps *PartitionSet) String() string {
var buffer bytes.Buffer
for i, pn := range ps.names {
buffer.WriteString(ps.models[i])
buffer.WriteString(",")
buffer.WriteString(pn)
buffer.WriteString("=")
start, end := -1, -1
first := true
for j, p := range ps.partitions {
if p == i {
if start == -1 {
start = j
end = j
} else if j == end+1 {
end = j
}
if j > end+1 || j == len(ps.partitions)-1 {
if !first {
buffer.WriteString(",")
}
if start == end {
buffer.WriteString(fmt.Sprintf("%d", start+1))
} else {
buffer.WriteString(fmt.Sprintf("%d-%d", start+1, end+1))
}
first = false
start = j
end = j
}
} else {
if end != -1 {
if !first {
buffer.WriteString(",")
}
if start == end {
buffer.WriteString(fmt.Sprintf("%d", start+1))
} else {
buffer.WriteString(fmt.Sprintf("%d-%d", start+1, end+1))
}
first = false
}
start = -1
end = -1
}
}
buffer.WriteString("\n")
}
return buffer.String()
}
func (ps *PartitionSet) NPartitions() int {
return len(ps.names)
}
// Returns the partition code associated to the given position
//
// If the position is outside the alignment, then returns -1
func (ps *PartitionSet) Partition(position int) int {
if position < 0 || position >= len(ps.partitions) {
return -1
}
return ps.partitions[position]
}
// Returns the name of the partition associated to the given index
// If the code does not exist, then returns ""
func (ps *PartitionSet) PartitionName(code int) string {
if code < 0 || code > len(ps.names) {
return ""
}
return ps.names[code]
}
// Returns the name of the modele associated to the given index
// If the code does not exist, then returns ""
func (ps *PartitionSet) ModeleName(code int) string {
if code < 0 || code > len(ps.models) {
return ""
}
return ps.models[code]
}
// returns the length of the alignment
func (ps *PartitionSet) AliLength() int {
return ps.length
}