//Just a wrapper for the mat64.Dense.TCopy method func (F *Matrix) TCopy(A mat64.Matrix) { //NOTE: This function has been removed from gonum, hence I should remove it from here too. ******************* //Somehow the mat64.TCopy method seems to misbehave if I give it a mat64.Matrix. //Although I can't see a bug in the mat64.Dense.TCopy function, it seems that if I //call it with an A which is not a mat64.Dense, it doesn't work. That is why this wrapper //has not been deleted. This seems to be a bug in gochem somehow, not in gonum. if A, ok := A.(*Matrix); ok { F.Dense.Copy(A.Dense.T()) } else { F.Dense.Copy(A.T()) } }
// CovarianceMatrix calculates a covariance matrix (also known as a // variance-covariance matrix) from a matrix of data, using a two-pass // algorithm. // // The weights must have length equal to the number of rows in // input data matrix x. If cov is nil, then a new matrix with appropriate size will // be constructed. If cov is not nil, it should have the same number of columns as the // input data matrix x, and it will be used as the destination for the covariance // data. Weights must not be negative. func CovarianceMatrix(cov *mat64.SymDense, x mat64.Matrix, weights []float64) *mat64.SymDense { // This is the matrix version of the two-pass algorithm. It doesn't use the // additional floating point error correction that the Covariance function uses // to reduce the impact of rounding during centering. r, c := x.Dims() if cov == nil { cov = mat64.NewSymDense(c, nil) } else if n := cov.Symmetric(); n != c { panic(matrix.ErrShape) } var xt mat64.Dense xt.Clone(x.T()) // Subtract the mean of each of the columns. for i := 0; i < c; i++ { v := xt.RawRowView(i) // This will panic with ErrShape if len(weights) != len(v), so // we don't have to check the size later. mean := Mean(v, weights) floats.AddConst(-mean, v) } if weights == nil { // Calculate the normalization factor // scaled by the sample size. cov.SymOuterK(1/(float64(r)-1), &xt) return cov } // Multiply by the sqrt of the weights, so that multiplication is symmetric. sqrtwts := make([]float64, r) for i, w := range weights { if w < 0 { panic("stat: negative covariance matrix weights") } sqrtwts[i] = math.Sqrt(w) } // Weight the rows. for i := 0; i < c; i++ { v := xt.RawRowView(i) floats.Mul(v, sqrtwts) } // Calculate the normalization factor // scaled by the weighted sample size. cov.SymOuterK(1/(floats.Sum(weights)-1), &xt) return cov }
func testSimplex(t *testing.T, initialBasic []int, c []float64, a mat64.Matrix, b []float64, convergenceTol float64) error { primalOpt, primalX, _, errPrimal := simplex(initialBasic, c, a, b, convergenceTol) if errPrimal == nil { // No error solving the simplex, check that the solution is feasible. var bCheck mat64.Vector bCheck.MulVec(a, mat64.NewVector(len(primalX), primalX)) if !mat64.EqualApprox(&bCheck, mat64.NewVector(len(b), b), 1e-10) { t.Errorf("No error in primal but solution infeasible") } } primalInfeasible := errPrimal == ErrInfeasible primalUnbounded := errPrimal == ErrUnbounded primalBounded := errPrimal == nil primalASingular := errPrimal == ErrSingular primalZeroRow := errPrimal == ErrZeroRow primalZeroCol := errPrimal == ErrZeroColumn primalBad := !primalInfeasible && !primalUnbounded && !primalBounded && !primalASingular && !primalZeroRow && !primalZeroCol // It's an error if it's not one of the known returned errors. If it's // singular the problem is undefined and so the result cannot be compared // to the dual. if errPrimal == ErrSingular || primalBad { if primalBad { t.Errorf("non-known error returned: %s", errPrimal) } return errPrimal } // Compare the result to the answer found from solving the dual LP. // Construct and solve the dual LP. // Standard Form: // minimize c^T * x // subject to A * x = b, x >= 0 // The dual of this problem is // maximize -b^T * nu // subject to A^T * nu + c >= 0 // Which is // minimize b^T * nu // subject to -A^T * nu <= c negAT := &mat64.Dense{} negAT.Clone(a.T()) negAT.Scale(-1, negAT) cNew, aNew, bNew := Convert(b, negAT, c, nil, nil) dualOpt, dualX, _, errDual := simplex(nil, cNew, aNew, bNew, convergenceTol) if errDual == nil { // Check that the dual is feasible var bCheck mat64.Vector bCheck.MulVec(aNew, mat64.NewVector(len(dualX), dualX)) if !mat64.EqualApprox(&bCheck, mat64.NewVector(len(bNew), bNew), 1e-10) { t.Errorf("No error in dual but solution infeasible") } } // Check about the zero status. if errPrimal == ErrZeroRow || errPrimal == ErrZeroColumn { return errPrimal } // If the primal problem is feasible, then the primal and the dual should // be the same answer. We have flopped the sign in the dual (minimizing // b^T *nu instead of maximizing -b^T*nu), so flip it back. if errPrimal == nil { if errDual != nil { fmt.Println("errDual", errDual) panic("here") t.Errorf("Primal feasible but dual errored: %s", errDual) } dualOpt *= -1 if !floats.EqualWithinAbsOrRel(dualOpt, primalOpt, convergenceTol, convergenceTol) { t.Errorf("Primal and dual value mismatch. Primal %v, dual %v.", primalOpt, dualOpt) } } // If the primal problem is unbounded, then the dual should be infeasible. if errPrimal == ErrUnbounded && errDual != ErrInfeasible { t.Errorf("Primal unbounded but dual not infeasible. ErrDual = %s", errDual) } // If the dual is unbounded, then the primal should be infeasible. if errDual == ErrUnbounded && errPrimal != ErrInfeasible { t.Errorf("Dual unbounded but primal not infeasible. ErrDual = %s", errPrimal) } // If the primal is infeasible, then the dual should be either infeasible // or unbounded. if errPrimal == ErrInfeasible { if errDual != ErrUnbounded && errDual != ErrInfeasible && errDual != ErrZeroColumn { t.Errorf("Primal infeasible but dual not infeasible or unbounded: %s", errDual) } } return errPrimal }
// CovarianceMatrix calculates a covariance matrix (also known as a // variance-covariance matrix) from a matrix of data, using a two-pass // algorithm. The matrix returned will be symmetric and square. // // The weights wts should have the length equal to the number of rows in // input data matrix x. If c is nil, then a new matrix with appropriate size will // be constructed. If c is not nil, it should be a square matrix with the same // number of columns as the input data matrix x, and it will be used as the receiver // for the covariance data. Weights cannot be negative. func CovarianceMatrix(cov *mat64.Dense, x mat64.Matrix, wts []float64) *mat64.Dense { // This is the matrix version of the two-pass algorithm. It doesn't use the // additional floating point error correction that the Covariance function uses // to reduce the impact of rounding during centering. // TODO(jonlawlor): indicate that the resulting matrix is symmetric, and change // the returned type from a *mat.Dense to a *mat.Symmetric. r, c := x.Dims() if cov == nil { cov = mat64.NewDense(c, c, nil) } else if covr, covc := cov.Dims(); covr != covc || covc != c { panic(mat64.ErrShape) } var xt mat64.Dense xt.Clone(x.T()) // Subtract the mean of each of the columns. for i := 0; i < c; i++ { v := xt.RawRowView(i) // This will panic with ErrShape if len(wts) != len(v), so // we don't have to check the size later. mean := Mean(v, wts) floats.AddConst(-mean, v) } var n float64 if wts == nil { n = float64(r) cov.Mul(&xt, (&xt).T()) // Scale by the sample size. cov.Scale(1/(n-1), cov) return cov } // Multiply by the sqrt of the weights, so that multiplication is symmetric. sqrtwts := make([]float64, r) for i, w := range wts { if w < 0 { panic("stat: negative covariance matrix weights") } sqrtwts[i] = math.Sqrt(w) } // Weight the rows. for i := 0; i < c; i++ { v := xt.RawRowView(i) floats.Mul(v, sqrtwts) } // Calculate the normalization factor. n = floats.Sum(wts) cov.Mul(&xt, (&xt).T()) // Scale by the sample size. cov.Scale(1/(n-1), cov) return cov }