-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvector.go
More file actions
271 lines (238 loc) · 7.3 KB
/
vector.go
File metadata and controls
271 lines (238 loc) · 7.3 KB
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
package matrix
import (
"fmt"
"log"
"math"
"math/rand"
)
//Vector type
type Vector struct {
row []float64
}
//NewVector returns a vector type
func NewVector(slice []float64) Vector {
return Vector{row: slice}
}
// PrintVector prints the vector components
func PrintVector(vec Vector) {
fmt.Println(vec.row)
}
//VecToArray returns a slice of vector elements.
func VecToArray(vec Vector) []float64 {
slice := make([]float64, len(vec.row))
for i := range vec.row {
slice = append(slice, vec.row[i])
}
return slice
}
//RandomVector returns a random valued vector.
func RandomVector(size int) Vector {
slice := make([]float64, size)
for i := 0; i < size; i++ {
slice = append(slice, rand.Float64()/0.3)
}
return NewVector(slice)
}
// InnerProduct returns the inner product of two vectors via the matrix.
// Check the dotProduct function for a simplified dot product of two vectors.
func InnerProduct(matrix Matrix, vector1, vector2 Vector) float64 {
var product Vector
for _, r := range matrix.slice {
for i := 0; i < len(r); i++ {
product.row[i] = r[i] * vector1.row[i]
}
}
return vector2.DotProduct(product)
}
//NumberOfElements returns the number of elements.
func (v Vector) NumberOfElements() int {
return len(v.row)
}
// Slice returns vector.slice.
// You can perform indexing with this method.
func (v Vector) Slice() []float64 {
return v.row
}
//DotProduct returns the dot product of two vectors.
func (v Vector) DotProduct(v2 Vector) float64 {
var sum float64
for i := 0; i < len(v.row); i++ {
sum += v.row[i] * v2.row[i]
}
return sum
}
//ApplyMatrix returns the vector through a matrix transformation.
func (v Vector) ApplyMatrix(matrix Matrix) Vector {
var product Vector
for _, r := range matrix.slice {
for i := 0; i < len(r); i++ {
product.row[i] = r[i] * v.row[i]
}
}
return product
}
//Add returns an elementary operation on two vectors.
func (v Vector) Add(v2 Vector) Vector {
var resultVector Vector
for i := 0; i < len(v.row); i++ {
resultVector.row[i] = v.row[i] + v2.row[i]
}
return resultVector
}
//Substract returns an elementary operation on two vectors.
func (v Vector) Substract(v2 Vector) Vector {
var resultVector Vector
for i := 0; i < len(v.row); i++ {
resultVector.row[i] = v.row[i] - v2.row[i]
}
return resultVector
}
//AddMany takes a slice of vectors and outputs their sum.
func (v Vector) AddMany(vectors []Vector) Vector {
var resultVector Vector
for _, vec := range vectors {
for i := 0; i < len(v.row); i++ {
resultVector.row[i] = v.row[i] + vec.row[i]
}
}
return resultVector
}
//SubstractMany takes a slice of vectors and outputs their divergence.
func (v Vector) SubstractMany(vectors []Vector) Vector {
var resultVector Vector
for _, vec := range vectors {
for i := 0; i < len(v.row); i++ {
resultVector.row[i] = v.row[i] - vec.row[i]
}
}
return resultVector
}
// VecZeros returns a vector of zeros
func VecZeros(size int) Vector {
slc := make([]float64, size)
for i := 0; i < size; i++ {
slc = append(slc, 0)
}
return Vector{row: slc}
}
// VecOnes returns a vector of zeros
func VecOnes(size int) Vector {
slc := make([]float64, size)
for i := 0; i < size; i++ {
slc = append(slc, 1)
}
return Vector{row: slc}
}
// VecAllSameNumber returns a vector of zeros
func VecAllSameNumber(size int, number float64) Vector {
slc := make([]float64, size)
for i := 0; i < size; i++ {
slc = append(slc, number)
}
return Vector{row: slc}
}
//Map maps the vector by with the function
func (v Vector) Map(f func(float64) float64) Vector {
for i := range v.row {
v.row[i] = f(v.row[i])
}
return v
}
//GetLength returns the length of a vector.
func (v Vector) GetLength() float64 {
var result float64
for _, g := range v.row {
result += math.Pow(g, 2)
}
return math.Sqrt(result)
}
//AngleBetween returns the angle between two vectors.
func (v Vector) AngleBetween(v2 Vector) float64 {
return math.Cos(v.DotProduct(v2) / (v.GetLength() * v2.GetLength()))
}
//ScalarProjection returns the scalar projection of v onto v2.
func (v Vector) ScalarProjection(v2 Vector) float64 {
x := v2.GetLength() * v.AngleBetween(v2)
return x
}
//MultiplyByScalar operates by adding a scalar elementary.
func (v Vector) MultiplyByScalar(scalar float64) Vector {
for _, g := range v.row {
g = g * scalar
}
return v
}
//VectorProjection returns the vector projection of v onto v2.
func (v Vector) VectorProjection(v2 Vector) Vector {
x := v.DotProduct(v2)
y := v2.DotProduct(v2)
return v.MultiplyByScalar(x / y)
}
//ChangingBasis returns the transformed vector if we were to change its basis vectors.
//Similar to a simple matrix transformation but inputs are two basis vectors.
//Basis vectors have to be perpendicular to each other in order to apply this transformation.
//The function takes care of this for you by sending back an error
func (v Vector) ChangingBasis(b1, b2 Vector) (Vector, error) {
var newVector Vector
var db1, db2 float64
if b1.AngleBetween(b2) != 0 {
return Vector{}, fmt.Errorf("basis vectors have to be perpendicular")
}
db1 = v.DotProduct(b1) / math.Pow(b1.GetLength(), 2)
db2 = v.DotProduct(b2) / math.Pow(b2.GetLength(), 2)
newVector.row[0] = db1
newVector.row[1] = db2
return newVector, nil
}
//GramSchmidt function returns the concatenated matrix of orthogonal based vectors out of the vectors dataset.
//Based on the Mathematics for Machine learning Specialization.
func GramSchmidt(vectors []Vector) ([]Vector, error) {
var normalizedvectors []Vector
var xs []Vector
for i, vector := range vectors {
normalized := vectors[i-1].MultiplyByScalar(1 / vector.GetLength())
if i != 1 {
s := vectors[i].DotProduct(normalized)
x := normalized.MultiplyByScalar(s)
xs = append(xs, x)
normalizedvectors[i] = vectors[i].Substract(vectors[i].SubstractMany(xs))
}
}
return normalizedvectors, nil
}
//PageRank algorithm returns the probabilites of randomly ending up on either of the pages.
//Page connections should be put inside the link matrix.
func PageRank(linkMatrix Matrix, pages int) {
slice := make([]float64, pages)
for i := range slice {
slice[i] = 1 / float64(pages)
}
initVector := Vector{row: slice}
for i := 0; i < len(initVector.row); i++ {
initVector = initVector.ApplyMatrix(linkMatrix)
}
}
//CalculateEigenvectors2x2 returns the eigenvectors of the given 2x2 matrix
func CalculateEigenvectors2x2(m Matrix) ([]Vector, error) {
var vectors []Vector
q := m.slice
det := m.Find2x2Determinant()
lambda1, lambda2 := Quadratic(1, q[0][0]+q[1][1], det)
vec1 := []float64{lambda1, 0}
vec2 := []float64{0, lambda2}
vector1 := Vector{row: vec1}
vector2 := Vector{row: vec2}
vectors = append(vectors, vector1)
vectors = append(vectors, vector2)
return vectors, nil
}
//Quadratic takes a,b,c parameters of a quadratic equation as inputs and returns both solutions via the discriminant.
func Quadratic(a, b, c float64) (float64, float64) {
disc := math.Pow(b, 2) - 4*a*c
if disc < 0 {
log.Fatalf("The discriminant is negative. Therefore solutions will be complex numbers. ")
}
x1 := (-b + math.Sqrt(disc)) / 2 * a
x2 := (-b - math.Sqrt(disc)) / 2 * a
return x1, x2
}