func randmatmul(n int) matrix.MatrixRO { a := matrix.Zeros(n, n) b := matrix.Zeros(n, n) for i := 0; i < n; i++ { for k := 0; k < n; k++ { a.Set(i, k, rand.Float64()) b.Set(i, k, rand.Float64()) } } return matrix.Product(a, b) }
/* Weights returns the weight vector obtained during the fitting process. If Fit() has not been executed yet, then the behavior of this method is undefined. Returns ======= a column vector of weights (including an additional weight for the bias) */ func (self SGD) Weights() mat.DenseMatrix { if self.f != nil { return self.f.Weights } else { return *mat.Zeros(1, 1) } }
// Covariance test against R func TestCovariance(t *testing.T) { fmt.Println("Covariance test against R") data := GetData() out := SCov(data) //known values dist := [...]float64{1.773643, -0.3381504, 0.4803343, -0.8050336, 0.3154475, 0.2026154, 0.5576372, -0.3982494, 0.2083944, 0.1306447, -0.3381504, 0.8108673, 0.1696915, 0.5268912, -0.1279332, -0.0810701, 0.4332097, -0.01344127, 0.3683854, -0.1976432, 0.4803343, 0.1696915, 0.4986279, 0.02131043, 0.2643708, -0.3654575, 0.6973307, -0.3021538, -0.221391, -0.07286902, -0.8050336, 0.5268912, 0.02131043, 0.7320278, 0.01051328, -0.4524992, 0.0321159, -0.1932133, 0.1346962, 0.003491767, 0.3154475, -0.1279332, 0.2643708, 0.01051328, 0.4088249, -0.3923959, 0.2455576, -0.3880454, -0.2810396, 0.1249063, 0.2026154, -0.0810701, -0.3654575, -0.4524992, -0.3923959, 0.8562731, -0.3241916, 0.5470234, 0.3595004, -0.1266668, 0.5576372, 0.4332097, 0.6973307, 0.0321159, 0.2455576, -0.3241916, 1.149185, -0.1579107, -0.3901415, -0.3014224, -0.3982494, -0.01344127, -0.3021538, -0.1932133, -0.3880454, 0.5470234, -0.1579107, 0.7091816, -0.2188541, -0.3055508, 0.2083944, 0.3683854, -0.221391, 0.1346962, -0.2810396, 0.3595004, -0.3901415, -0.2188541, 1.283379, 0.2383891, 0.1306447, -0.1976432, -0.07286902, 0.003491767, 0.1249063, -0.1266668, -0.3014224, -0.3055508, 0.2383891, 0.2644874} cols := data.Cols() known := mtx.Zeros(cols, cols) for i := 0; i < cols; i++ { for j := i + 1; j < cols; j++ { known.Set(i, j, dist[i*cols+j]) } } // check for i := 0; i < cols; i++ { for j := i + 1; j < cols; j++ { if !check(out.Get(i, j), known.Get(i, j)) { t.Error() fmt.Println(i, j, out.Get(i, j), known.Get(i, j)) } } } }
/* LinearFitAndReturnMSE is used to test linear FunctionApproximators. It generates a collection of samples according to a 1-d linear function, fits the function approximator with the training samples, and then returns the Mean Squared Error (MSE). The training set is purposefully equal to the test set so that we can test that the passed function approximator learns the training data. The targets of the linear function are perturbed by a small amount of Gaussian noise. Input ===== fa : a function approximator t : a testing instance Returns ======= the MSE of the fa on samples from the linear function */ func LinearFitAndReturnMSE(fa FunctionApproximator, t *testing.T) float64 { n := 100 x := mat.Zeros(n, 1) y := mat.Zeros(n, 1) for i := 0; i < n; i++ { fi := float64(i) fn := float64(n) fx := fi / fn fy := (0.25*fx - 0.5) + rand.NormFloat64()*LINEAR_NOISE x.Set(i, 0, fx) y.Set(i, 0, fy) } err := fa.Fit(x, y) if err != nil { t.Error(err) } // Test bulk prediction yhatM, err := fa.PredictM(x) if err != nil { t.Error(err) } sqErrM := 0.0 diffM, err := y.Minus(yhatM) if err != nil { t.Error(err) } sqErr := 0.0 for i := 0; i < n; i++ { sqErrM += diffM.Get(i, 0) * diffM.Get(i, 0) v, err := fa.Predict(x.GetRowVector(i)) if err != nil { t.Error(err) } diff := y.Get(i, 0) - v sqErr += diff * diff } mse := math.Max(sqErr, sqErrM) / float64(n) return mse }
/* M is r x c, o x i Sigma is r x r, o x o Phi is c x c, i x i Sigma matches Y o x 1 output dimension Phi matches X i x 1 input dimension */ func NewKnownVarianceLRPosterior(M, Sigma, Phi *mx.DenseMatrix) (this *KnownVarianceLRPosterior) { if M.Rows() != Sigma.Rows() { panic("M.Rows != Sigma.Rows") } if M.Cols() != Phi.Cols() { panic("M.Cols != Phi.Cols") } if Sigma.Rows() != Sigma.Cols() { panic("Sigma is not square") } if Phi.Rows() != Phi.Cols() { panic("Phi is not square") } this = &KnownVarianceLRPosterior{ M: M, Sigma: Sigma, Phi: Phi, XXt: mx.Zeros(Phi.Cols(), Phi.Cols()), YXt: mx.Zeros(Sigma.Cols(), Phi.Cols()), } return }
/* Apply applies the function f to each element in A and returns a new matrix with the results. Input ===== A : a matrix f : a function from scalar values to scalar values Returns ======= a matrix derived by applying f to each element in A. If f is nil, then this function just returns A. */ func Apply(A mat.MatrixRO, f SFunction) mat.MatrixRO { if f == nil { return A } B := mat.Zeros(A.Rows(), A.Cols()) for r := 0; r < A.Rows(); r++ { for c := 0; c < A.Cols(); c++ { x := A.Get(r, c) y := f(x) B.Set(r, c, y) } } return B }
func Wishart(n int, V *m.DenseMatrix) func() *m.DenseMatrix { p := V.Rows() zeros := m.Zeros(p, 1) rowGen := MVNormal(zeros, V) return func() *m.DenseMatrix { x := make([][]float64, n) for i := 0; i < n; i++ { x[i] = rowGen().Array() } X := m.MakeDenseMatrixStacked(x) S, _ := X.Transpose().TimesDense(X) return S } }
func MatrixT(M, Omega, Sigma *mx.DenseMatrix, n int) func() (T *mx.DenseMatrix) { checkMatrixT(M, Omega, Sigma, n) fmt.Println("M:", M) fmt.Println("Sigma:", Sigma) fmt.Println("Omega:", Omega) p := M.Rows() m := M.Cols() OmegaInv, err := Omega.Inverse() if err != nil { panic(err) } Sdist := Wishart(n+p-1, OmegaInv) Xdist := MatrixNormal(mx.Zeros(p, m), mx.Eye(p), Sigma) return func() (T *mx.DenseMatrix) { S := Sdist() Sinv, err := S.Inverse() if err != nil { panic(err) } Sinvc, err := Sinv.Cholesky() if err != nil { panic(err) } X := Xdist() fmt.Println("Sinvc:", Sinvc) fmt.Println("X:", X) T, err = Sinvc.Transpose().TimesDense(X) if err != nil { panic(err) } err = T.AddDense(M) if err != nil { panic(err) } return } }
func randmatstat(t int) (float64, float64) { n := 5 var v stats.Stats var w stats.Stats for i := 0; i < t; i++ { a := matrix.Zeros(n, n) b := matrix.Zeros(n, n) c := matrix.Zeros(n, n) d := matrix.Zeros(n, n) for j := 0; j < n; j++ { for k := 0; k < n; k++ { a.Set(j, k, rand.NormFloat64()) b.Set(j, k, rand.NormFloat64()) c.Set(j, k, rand.NormFloat64()) d.Set(j, k, rand.NormFloat64()) } } P := matrix.Zeros(n, 4*n) for j := 0; j < n; j++ { for k := 0; k < n; k++ { P.Set(j, k, a.Get(j, k)) P.Set(j, n+k, b.Get(j, k)) P.Set(j, 2*n+k, c.Get(j, k)) P.Set(j, 3*n+k, d.Get(j, k)) } } Q := matrix.Zeros(2*n, 2*n) for j := 0; j < n; j++ { for k := 0; k < n; k++ { Q.Set(j, k, a.Get(j, k)) Q.Set(j, n+k, b.Get(j, k)) Q.Set(n+j, k, c.Get(j, k)) Q.Set(n+j, n+k, d.Get(j, k)) } } P = matrix.Product(matrix.Transpose(P), P) P = matrix.Product(P, P) P = matrix.Product(P, P) Q = matrix.Product(matrix.Transpose(Q), Q) Q = matrix.Product(Q, Q) Q = matrix.Product(Q, Q) v.Update(P.Trace()) w.Update(Q.Trace()) } return v.PopulationStandardDeviation() / float64(v.Count()) / v.Mean(), w.PopulationStandardDeviation() / float64(w.Count()) / w.Mean() }
// zerosMatrix returns a matrix filled with zeroes of a given size // Params: rows int -- number of rows to fill // Params: cols int -- number of cols to fill // Returns: *goMatrix.DenseMatrix func zerosMatrix(rows, cols int) *goMatrix.DenseMatrix { return goMatrix.Zeros(rows, cols) }
// generateReturns generates performance specifically for assets, and returns // separately by asset class as a map // Receiver: SimulationData // Params: numberOfMonths int -- number of periods to model // Returns: returnResultsByAsset func (s *SimulationData) generateReturns(numberOfMonths int) returnResultsByAsset { assetPerformanceData := s.AssetPerformanceData // map[string]Distribution assetClassIds := s.assetClassIds() // []string numberOfAssets := len(assetClassIds) choleskyApplied := s.applyCholeskyDecomposition(numberOfMonths) prices := goMatrix.Zeros(numberOfMonths, numberOfAssets) for row := 0; row < prices.Rows(); row++ { for column := 0; column < prices.Cols(); column++ { var startingValue float64 if row == 0 { startingValue = 0.0 } else { startingValue = prices.Get((row - 1), column) } assetId := assetClassIds[column] // These are sorted alphabetically assetStats := assetPerformanceData[assetId] assetMeanReturn := assetStats.Mean assetStdDev := assetStats.StdDev b := assetMeanReturn - 0.5*math.Pow(assetStdDev, 2) c := assetStdDev * choleskyApplied.Get(row, column) // Can't do the exp(x) in the same step as you need to use the previous value as a starting price! prices.Set(row, column, (startingValue + b + c)) } } for row := 0; row < prices.Rows(); row++ { for column := 0; column < prices.Cols(); column++ { basePrice := prices.Get(row, column) expPrice := math.Exp(basePrice) prices.Set(row, column, expPrice) } } /* Convert prices to relative returns. */ // Add T=0, price=1.0 initialPrices := goMatrix.Ones(1, numberOfAssets) augmentedPrices, _ := initialPrices.Stack(prices) // Create base matrix asRelativeReturns := goMatrix.Zeros(numberOfMonths, numberOfAssets) // Each row in the prices matrix is a list of asset prices in each year - NOT // the progression of a single asset. We'll need to grab columns for that. for column := 0; column < augmentedPrices.Cols(); column++ { priceValues := augmentedPrices.GetColVector(column).Array() // []float64 for periodIndex, periodPrice := range priceValues { if periodIndex == 0 { // Nothing to do on the first column continue } lastPrice := priceValues[periodIndex-1] pctReturn := (periodPrice - lastPrice) / lastPrice asRelativeReturns.Set((periodIndex - 1), column, pctReturn) } } /* */ results := asRelativeReturns.Arrays() // [][]float64 resultsByAsset := returnResultsByAsset{} // map[string][]float64 for _, assetClassId := range assetClassIds { resultsByAsset[assetClassId] = make([]float64, numberOfMonths) } for periodIndex, resultSet := range results { for assetIndex, returnResult := range resultSet { assetClassId := assetClassIds[assetIndex] resultsByAsset[assetClassId][periodIndex] = returnResult } } return resultsByAsset }
func (self *SGD) Fit(x mat.MatrixRO, y mat.MatrixRO) error { if x.Rows() != y.Rows() { return fmt.Errorf("The number of rows in x (%d) does not match the number of rows in y (%d). The matrix x should contain one input vector per row and the vector y should be a column vector containing labels for each input vector.", x.Rows(), y.Rows()) } if y.Cols() != 1 { return fmt.Errorf("y must be a column vector.") } // The number of samples in the data set n := x.Rows() // Get a dense version of the input matrix dx := x.DenseMatrix() // If there is no LinearModel yet, then we add one. if self.f == nil { self.inputDims = x.Cols() self.f = new(LinearFunction) self.f.Weights = *mat.Zeros(self.inputDims+1, 1) self.f.AFunc = self.afunc } else if self.inputDims != x.Cols() { // If there is an existing linear model, then we only train on // additional samples if they match the dimensionality of the previous // training data. return fmt.Errorf("The number of columns in matrix x does not match the dimension of previous training data. Please construct a new SGD instance.") } for i := 0; i < self.NumIterations; i++ { index := rand.Intn(n) xrow := dx.GetRowVector(index) xrowb := self.addBiasToMatrix(xrow) yhat, err := self.f.Predict(xrowb) if err != nil { return fmt.Errorf("Error while predicting with internal linear model. %v", err) } // Compute the activation function's derivative yhatPrime := 0.0 if self.afunc != nil { yNoAct, err := xrowb.Times(&self.f.Weights) if err != nil { return fmt.Errorf("Error while predicting before applying the activation function. %v", err) } yhatPrime = self.afunc.Deriv(yNoAct.Get(0, 0)) } else { yhatPrime = 1 } diff := y.Get(index, 0) - yhat for j := 0; j < self.inputDims+1; j++ { // Get the old weight value oldw := self.f.Weights.Get(j, 0) // Calculate the gradient of the squared error grad := 0.0 if j < self.inputDims { grad = (diff * yhatPrime * -xrow.Get(0, j)) } else { // Gradient for the bias grad = -diff * yhatPrime } // Calculate the gradient of the regularization penalty gpen := 0.0 if self.PenaltyType == L1_PENALTY { gpen = self.Lambda * signum(oldw) } else { gpen = self.Lambda * oldw } // Calculate the change in weight alpha := self.LearningRate / float64(self.inputDims) deltaw := alpha * (grad + gpen) neww := oldw - deltaw // Set the new weight self.f.Weights.Set(j, 0, neww) } } return nil }