// Copyright ©2020 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mat_test import ( "fmt" "log" "gonum.org/v1/gonum/mat" ) func ExampleSVD_SolveTo() { // The system described by A is rank deficient. a := mat.NewDense(5, 3, []float64{ -1.7854591879711257, -0.42687285925779594, -0.12730256811265162, -0.5728984211439724, -0.10093393134001777, -0.1181901192353067, 1.2484316018707418, 0.5646683943038734, -0.48229492403243485, 0.10174927665169475, -0.5805410929482445, 1.3054473231942054, -1.134174808195733, -0.4732430202414438, 0.3528489486370508, }) // Perform an SVD retaining all singular vectors. var svd mat.SVD ok := svd.Factorize(a, mat.SVDFull) if !ok { log.Fatal("failed to factorize A") } // Determine the rank of the A matrix with a near zero condition threshold. const rcond = 1e-15 rank := svd.Rank(rcond) if rank == 0 { log.Fatal("zero rank system") } b := mat.NewDense(5, 2, []float64{ -2.318, -4.35, -0.715, 1.451, 1.836, -0.119, -0.357, 3.094, -1.636, 0.021, }) // Find a least-squares solution using the determined parts of the system. var x mat.Dense svd.SolveTo(&x, b, rank) fmt.Printf("singular values = %v\nrank = %d\nx = %.15f", format(svd.Values(nil), 4, rcond), rank, mat.Formatted(&x, mat.Prefix(" "))) // Output: // singular values = [2.685 1.526 <1e-15] // rank = 2 // x = ⎡ 1.212064313552347 1.507467451093930⎤ // ⎢ 0.415400738264774 -0.624498607705372⎥ // ⎣-0.183184442255280 2.221334193689124⎦ } func ExampleSVD_SolveVecTo() { // The system described by A is rank deficient. a := mat.NewDense(5, 3, []float64{ -1.7854591879711257, -0.42687285925779594, -0.12730256811265162, -0.5728984211439724, -0.10093393134001777, -0.1181901192353067, 1.2484316018707418, 0.5646683943038734, -0.48229492403243485, 0.10174927665169475, -0.5805410929482445, 1.3054473231942054, -1.134174808195733, -0.4732430202414438, 0.3528489486370508, }) // Perform an SVD retaining all singular vectors. var svd mat.SVD ok := svd.Factorize(a, mat.SVDFull) if !ok { log.Fatal("failed to factorize A") } // Determine the rank of the A matrix with a near zero condition threshold. const rcond = 1e-15 rank := svd.Rank(rcond) if rank == 0 { log.Fatal("zero rank system") } b := mat.NewVecDense(5, []float64{-2.318, -0.715, 1.836, -0.357, -1.636}) // Find a least-squares solution using the determined parts of the system. var x mat.VecDense svd.SolveVecTo(&x, b, rank) fmt.Printf("singular values = %v\nrank = %d\nx = %.15f", format(svd.Values(nil), 4, rcond), rank, mat.Formatted(&x, mat.Prefix(" "))) // Output: // singular values = [2.685 1.526 <1e-15] // rank = 2 // x = ⎡ 1.212064313552347⎤ // ⎢ 0.415400738264774⎥ // ⎣-0.183184442255280⎦ } func format(vals []float64, prec int, eps float64) []string { s := make([]string, len(vals)) for i, v := range vals { if v < eps { s[i] = fmt.Sprintf("<%.*g", prec, eps) continue } s[i] = fmt.Sprintf("%.*g", prec, v) } return s }