func (p *floorPlan) F2(x, z *matrix.FloatMatrix) (f, Df, H *matrix.FloatMatrix, err error) { f, Df, err = p.F1(x) x17 := matrix.FloatVector(x.FloatArray()[17:]) tmp := matrix.Div(p.Amin, matrix.Pow(x17, 3.0)) tmp = matrix.Mul(z, tmp).Scale(2.0) diag := matrix.FloatDiagonal(5, tmp.FloatArray()...) H = matrix.FloatZeros(22, 22) H.SetSubMatrix(17, 17, diag) return }
func (p *floorPlan) F1(x *matrix.FloatMatrix) (f, Df *matrix.FloatMatrix, err error) { err = nil mn := x.Min(-1, -2, -3, -4, -5) if mn <= 0.0 { f, Df = nil, nil return } zeros := matrix.FloatZeros(5, 12) dk1 := matrix.FloatDiagonal(5, -1.0) dk2 := matrix.FloatZeros(5, 5) x17 := matrix.FloatVector(x.FloatArray()[17:]) // -( Amin ./ (x17 .* x17) ) diag := matrix.Div(p.Amin, matrix.Mul(x17, x17)).Scale(-1.0) dk2.SetIndexesFromArray(diag.FloatArray(), matrix.MakeDiagonalSet(5)...) Df, _ = matrix.FloatMatrixStacked(matrix.StackRight, zeros, dk1, dk2) x12 := matrix.FloatVector(x.FloatArray()[12:17]) // f = -x[12:17] + div(Amin, x[17:]) == div(Amin, x[17:]) - x[12:17] f = matrix.Minus(matrix.Div(p.Amin, x17), x12) return }
// Computes analytic center of A*x <= b with A m by n of rank n. // We assume that b > 0 and the feasible set is bounded. func Acent(A, b *matrix.FloatMatrix, niters int) (*matrix.FloatMatrix, []float64) { if niters <= 0 { niters = MAXITERS } ntdecrs := make([]float64, 0, niters) if A.Rows() != b.Rows() { return nil, nil } m, n := A.Size() x := matrix.FloatZeros(n, 1) H := matrix.FloatZeros(n, n) // Helper m*n matrix Dmn := matrix.FloatZeros(m, n) for i := 0; i < niters; i++ { // Gradient is g = A^T * (1.0/(b - A*x)). d = 1.0/(b - A*x) // d is m*1 matrix, g is n*1 matrix d := matrix.Minus(b, matrix.Times(A, x)).Inv() g := matrix.Times(A.Transpose(), d) // Hessian is H = A^T * diag(1./(b-A*x))^2 * A. // in the original python code expression d[:,n*[0]] creates // a m*n matrix where each column is copy of column 0. // We do it here manually. for i := 0; i < n; i++ { Dmn.SetColumn(i, d) } // Function mul creates element wise product of matrices. Asc := matrix.Mul(Dmn, A) blas.SyrkFloat(Asc, H, 1.0, 0.0, linalg.OptTrans) // Newton step is v = H^-1 * g. v := g.Copy().Scale(-1.0) lapack.PosvFloat(H, v) // Directional derivative and Newton decrement. lam := blas.DotFloat(g, v) ntdecrs = append(ntdecrs, math.Sqrt(-lam)) if ntdecrs[len(ntdecrs)-1] < TOL { fmt.Printf("last Newton decrement < TOL(%v)\n", TOL) return x, ntdecrs } // Backtracking line search. // y = d .* A*v y := d.Mul(A.Times(v)) step := 1.0 for 1-step*y.Max() < 0 { step *= BETA } search: for { // t = -step*y t := y.Copy().Scale(-step) // t = (1 + t) [e.g. t = 1 - step*y] t.Add(1.0) // ts = sum(log(1-step*y)) ts := t.Log().Sum() if -ts < ALPHA*step*lam { break search } step *= BETA } v.Scale(step) x = x.Plus(v) } // no solution !! fmt.Printf("Iteration %d exhausted\n", niters) return x, ntdecrs }
func main() { m := 6 Vdata := [][]float64{ []float64{1.0, -1.0, -2.0, -2.0, 0.0, 1.5, 1.0}, []float64{1.0, 2.0, 1.0, -1.0, -2.0, -1.0, 1.0}} V := matrix.FloatMatrixFromTable(Vdata, matrix.RowOrder) // V[1, :m] - V[1,1:] a0 := matrix.Minus(V.GetSubMatrix(1, 0, 1, m), V.GetSubMatrix(1, 1, 1)) // V[0, :m] - V[0,1:] a1 := matrix.Minus(V.GetSubMatrix(0, 0, 1, m), V.GetSubMatrix(0, 1, 1)) A0, _ := matrix.FloatMatrixStacked(matrix.StackDown, a0.Scale(-1.0), a1) A0 = A0.Transpose() b0 := matrix.Mul(A0, V.GetSubMatrix(0, 0, 2, m).Transpose()) b0 = matrix.Times(b0, matrix.FloatWithValue(2, 1, 1.0)) A := make([]*matrix.FloatMatrix, 0) b := make([]*matrix.FloatMatrix, 0) A = append(A, A0) b = append(b, b0) // List of symbols C := make([]*matrix.FloatMatrix, 0) C = append(C, matrix.FloatZeros(2, 1)) var row *matrix.FloatMatrix = nil for k := 0; k < m; k++ { row = A0.GetRow(k, row) nrm := blas.Nrm2Float(row) row.Scale(2.0 * b0.GetIndex(k) / (nrm * nrm)) C = append(C, row.Transpose()) } // Voronoi set around C[1] A1 := matrix.FloatZeros(3, 2) A1.SetSubMatrix(0, 0, A0.GetSubMatrix(0, 0, 1).Scale(-1.0)) A1.SetSubMatrix(1, 0, matrix.Minus(C[m], C[1]).Transpose()) A1.SetSubMatrix(2, 0, matrix.Minus(C[2], C[1]).Transpose()) b1 := matrix.FloatZeros(3, 1) b1.SetIndex(0, -b0.GetIndex(0)) v := matrix.Times(A1.GetRow(1, nil), matrix.Plus(C[m], C[1])).Float() * 0.5 b1.SetIndex(1, v) v = matrix.Times(A1.GetRow(2, nil), matrix.Plus(C[2], C[1])).Float() * 0.5 b1.SetIndex(2, v) A = append(A, A1) b = append(b, b1) // Voronoi set around C[2] ... C[5] for k := 2; k < 6; k++ { A1 = matrix.FloatZeros(3, 2) A1.SetSubMatrix(0, 0, A0.GetSubMatrix(k-1, 0, 1).Scale(-1.0)) A1.SetSubMatrix(1, 0, matrix.Minus(C[k-1], C[k]).Transpose()) A1.SetSubMatrix(2, 0, matrix.Minus(C[k+1], C[k]).Transpose()) b1 = matrix.FloatZeros(3, 1) b1.SetIndex(0, -b0.GetIndex(k-1)) v := matrix.Times(A1.GetRow(1, nil), matrix.Plus(C[k-1], C[k])).Float() * 0.5 b1.SetIndex(1, v) v = matrix.Times(A1.GetRow(2, nil), matrix.Plus(C[k+1], C[k])).Float() * 0.5 b1.SetIndex(2, v) A = append(A, A1) b = append(b, b1) } // Voronoi set around C[6] A1 = matrix.FloatZeros(3, 2) A1.SetSubMatrix(0, 0, A0.GetSubMatrix(5, 0, 1).Scale(-1.0)) A1.SetSubMatrix(1, 0, matrix.Minus(C[1], C[6]).Transpose()) A1.SetSubMatrix(2, 0, matrix.Minus(C[5], C[6]).Transpose()) b1 = matrix.FloatZeros(3, 1) b1.SetIndex(0, -b0.GetIndex(5)) v = matrix.Times(A1.GetRow(1, nil), matrix.Plus(C[1], C[6])).Float() * 0.5 b1.SetIndex(1, v) v = matrix.Times(A1.GetRow(2, nil), matrix.Plus(C[5], C[6])).Float() * 0.5 b1.SetIndex(2, v) A = append(A, A1) b = append(b, b1) P := matrix.FloatIdentity(2) q := matrix.FloatZeros(2, 1) solopts := &cvx.SolverOptions{ShowProgress: false, MaxIter: 30} ovals := make([]float64, 0) for k := 1; k < 7; k++ { sol, err := cvx.Qp(P, q, A[k], b[k], nil, nil, solopts, nil) _ = err x := sol.Result.At("x")[0] ovals = append(ovals, math.Pow(blas.Nrm2Float(x), 2.0)) } optvals := matrix.FloatVector(ovals) //fmt.Printf("optvals=\n%v\n", optvals) rangeFunc := func(n int) []float64 { r := make([]float64, 0) for i := 0; i < n; i++ { r = append(r, float64(i)) } return r } nopts := 200 sigmas := matrix.FloatVector(rangeFunc(nopts)) sigmas.Scale((0.5 - 0.2) / float64(nopts)).Add(0.2) bndsVal := func(sigma float64) float64 { // 1.0 - sum(exp( -optvals/(2*sigma**2))) return 1.0 - matrix.Exp(matrix.Scale(optvals, -1.0/(2*sigma*sigma))).Sum() } bnds := matrix.FloatZeros(sigmas.NumElements(), 1) for j, v := range sigmas.FloatArray() { bnds.SetIndex(j, bndsVal(v)) } plotData("plot.png", sigmas.FloatArray(), bnds.FloatArray()) }
func main() { flag.Parse() m := len(udata) nvars := 2 * m u := matrix.FloatVector(udata[:m]) y := matrix.FloatVector(ydata[:m]) // minimize (1/2) * || yhat - y ||_2^2 // subject to yhat[j] >= yhat[i] + g[i]' * (u[j] - u[i]), j, i = 0,...,m-1 // // Variables yhat (m), g (m). P := matrix.FloatZeros(nvars, nvars) // set m first diagonal indexes to 1.0 //P.SetIndexes(1.0, matrix.DiagonalIndexes(P)[:m]...) P.Diag().SubMatrix(0, 0, 1, m).SetIndexes(1.0) q := matrix.FloatZeros(nvars, 1) q.SubMatrix(0, 0, y.NumElements(), 1).Plus(matrix.Scale(y, -1.0)) // m blocks (i = 0,...,m-1) of linear inequalities // // yhat[i] + g[i]' * (u[j] - u[i]) <= yhat[j], j = 0,...,m-1. G := matrix.FloatZeros(m*m, nvars) I := matrix.FloatDiagonal(m, 1.0) for i := 0; i < m; i++ { // coefficients of yhat[i] (column i) //G.Set(1.0, matrix.ColumnIndexes(G, i)[i*m:(i+1)*m]...) column(G, i).SetIndexes(1.0) // coefficients of gi[i] (column i, rows i*m ... (i+1)*m) //rows := matrix.Indexes(i*m, (i+1)*m) //G.SetAtColumnArray(m+i, rows, matrix.Add(u, -u.GetIndex(i)).FloatArray()) // coefficients of gi[i] (column i, rows i*m ... (i+1)*m) // from column m+i staring at row i*m select m rows and one column G.SubMatrix(i*m, m+i, m, 1).Plus(matrix.Add(u, -u.GetIndex(i))) // coeffients of yhat[i]) from rows i*m ... (i+1)*m, cols 0 ... m //G.SetSubMatrix(i*m, 0, matrix.Minus(G.GetSubMatrix(i*m, 0, m, m), I)) G.SubMatrix(i*m, 0, m, m).Minus(I) } h := matrix.FloatZeros(m*m, 1) var A, b *matrix.FloatMatrix = nil, nil var solopts cvx.SolverOptions solopts.ShowProgress = true solopts.KKTSolverName = solver sol, err := cvx.Qp(P, q, G, h, A, b, &solopts, nil) if err != nil { fmt.Printf("error: %v\n", err) return } if sol != nil && sol.Status != cvx.Optimal { fmt.Printf("status not optimal\n") return } x := sol.Result.At("x")[0] //yhat := matrix.FloatVector(x.FloatArray()[:m]) //g := matrix.FloatVector(x.FloatArray()[m:]) yhat := x.SubMatrix(0, 0, m, 1).Copy() g := x.SubMatrix(m, 0).Copy() rangeFunc := func(n int) []float64 { r := make([]float64, 0) for i := 0; i < n; i++ { r = append(r, float64(i)*2.2/float64(n)) } return r } ts := rangeFunc(1000) fitFunc := func(points []float64) []float64 { res := make([]float64, len(points)) for k, t := range points { res[k] = matrix.Plus(yhat, matrix.Mul(g, matrix.Scale(u, -1.0).Add(t))).Max() } return res } fs := fitFunc(ts) plotData("cvxfit.png", u.FloatArray(), y.FloatArray(), ts, fs) }
func mcsdp(w *matrix.FloatMatrix) (*Solution, error) { // // Returns solution x, z to // // (primal) minimize sum(x) // subject to w + diag(x) >= 0 // // (dual) maximize -tr(w*z) // subject to diag(z) = 1 // z >= 0. // n := w.Rows() G := &matrixFs{n} cngrnc := func(r, x *matrix.FloatMatrix, alpha float64) (err error) { // Congruence transformation // // x := alpha * r'*x*r. // // r and x are square matrices. // err = nil // tx = matrix(x, (n,n)) is copying and reshaping // scale diagonal of x by 1/2, (x is (n,n)) tx := x.Copy() matrix.Reshape(tx, n, n) tx.Diag().Scale(0.5) // a := tril(x)*r // (python: a = +r is really making a copy of r) a := r.Copy() err = blas.TrmmFloat(tx, a, 1.0, linalg.OptLeft) // x := alpha*(a*r' + r*a') err = blas.Syr2kFloat(r, a, tx, alpha, 0.0, linalg.OptTrans) // x[:] = tx[:] tx.CopyTo(x) return } Fkkt := func(W *sets.FloatMatrixSet) (KKTFunc, error) { // Solve // -diag(z) = bx // -diag(x) - inv(rti*rti') * z * inv(rti*rti') = bs // // On entry, x and z contain bx and bs. // On exit, they contain the solution, with z scaled // (inv(rti)'*z*inv(rti) is returned instead of z). // // We first solve // // ((rti*rti') .* (rti*rti')) * x = bx - diag(t*bs*t) // // and take z = -rti' * (diag(x) + bs) * rti. var err error = nil rti := W.At("rti")[0] // t = rti*rti' as a nonsymmetric matrix. t := matrix.FloatZeros(n, n) err = blas.GemmFloat(rti, rti, t, 1.0, 0.0, linalg.OptTransB) if err != nil { return nil, err } // Cholesky factorization of tsq = t.*t. tsq := matrix.Mul(t, t) err = lapack.Potrf(tsq) if err != nil { return nil, err } f := func(x, y, z *matrix.FloatMatrix) (err error) { // tbst := t * zs * t = t * bs * t tbst := z.Copy() matrix.Reshape(tbst, n, n) cngrnc(t, tbst, 1.0) // x := x - diag(tbst) = bx - diag(rti*rti' * bs * rti*rti') diag := tbst.Diag().Transpose() x.Minus(diag) // x := (t.*t)^{-1} * x = (t.*t)^{-1} * (bx - diag(t*bs*t)) err = lapack.Potrs(tsq, x) // z := z + diag(x) = bs + diag(x) // z, x are really column vectors here z.AddIndexes(matrix.MakeIndexSet(0, n*n, n+1), x.FloatArray()) // z := -rti' * z * rti = -rti' * (diag(x) + bs) * rti cngrnc(rti, z, -1.0) return nil } return f, nil } c := matrix.FloatWithValue(n, 1, 1.0) // initial feasible x: x = 1.0 - min(lmbda(w)) lmbda := matrix.FloatZeros(n, 1) wp := w.Copy() lapack.Syevx(wp, lmbda, nil, 0.0, nil, []int{1, 1}, linalg.OptRangeInt) x0 := matrix.FloatZeros(n, 1).Add(-lmbda.GetAt(0, 0) + 1.0) s0 := w.Copy() s0.Diag().Plus(x0.Transpose()) matrix.Reshape(s0, n*n, 1) // initial feasible z is identity z0 := matrix.FloatIdentity(n) matrix.Reshape(z0, n*n, 1) dims := sets.DSetNew("l", "q", "s") dims.Set("s", []int{n}) primalstart := sets.FloatSetNew("x", "s") dualstart := sets.FloatSetNew("z") primalstart.Set("x", x0) primalstart.Set("s", s0) dualstart.Set("z", z0) var solopts SolverOptions solopts.MaxIter = 30 solopts.ShowProgress = false h := w.Copy() matrix.Reshape(h, h.NumElements(), 1) return ConeLpCustomMatrix(c, G, h, nil, nil, dims, Fkkt, &solopts, primalstart, dualstart) }
func qcl1(A, b *matrix.FloatMatrix) (*cvx.Solution, error) { // Returns the solution u, z of // // (primal) minimize || u ||_1 // subject to || A * u - b ||_2 <= 1 // // (dual) maximize b^T z - ||z||_2 // subject to || A'*z ||_inf <= 1. // // Exploits structure, assuming A is m by n with m >= n. m, n := A.Size() Fkkt := func(W *sets.FloatMatrixSet) (f cvx.KKTFunc, err error) { minor := 0 if !checkpnt.MinorEmpty() { minor = checkpnt.MinorTop() } err = nil f = nil beta := W.At("beta")[0].GetIndex(0) v := W.At("v")[0] // As = 2 * v *(v[1:].T * A) //v_1 := matrix.FloatNew(1, v.NumElements()-1, v.FloatArray()[1:]) v_1 := v.SubMatrix(1, 0).Transpose() As := matrix.Times(v, matrix.Times(v_1, A)).Scale(2.0) //As_1 := As.GetSubMatrix(1, 0, m, n) //As_1.Scale(-1.0) //As.SetSubMatrix(1, 0, matrix.Minus(As_1, A)) As_1 := As.SubMatrix(1, 0, m, n) As_1.Scale(-1.0) As_1.Minus(A) As.Scale(1.0 / beta) S := matrix.Times(As.Transpose(), As) checkpnt.AddMatrixVar("S", S) d1 := W.At("d")[0].SubMatrix(0, 0, n, 1).Copy() d2 := W.At("d")[0].SubMatrix(n, 0).Copy() // D = 4.0 * (d1**2 + d2**2)**-1 d := matrix.Plus(matrix.Mul(d1, d1), matrix.Mul(d2, d2)).Inv().Scale(4.0) // S[::n+1] += d S.Diag().Plus(d.Transpose()) err = lapack.Potrf(S) checkpnt.Check("00-Fkkt", minor) if err != nil { return } f = func(x, y, z *matrix.FloatMatrix) (err error) { minor := 0 if !checkpnt.MinorEmpty() { minor = checkpnt.MinorTop() } else { loopf += 1 minor = loopf } checkpnt.Check("00-f", minor) // -- z := - W**-T * z // z[:n] = -div( z[:n], d1 ) z_val := z.SubMatrix(0, 0, n, 1) z_res := matrix.Div(z_val, d1).Scale(-1.0) z.SubMatrix(0, 0, n, 1).Set(z_res) // z[n:2*n] = -div( z[n:2*n], d2 ) z_val = z.SubMatrix(n, 0, n, 1) z_res = matrix.Div(z_val, d2).Scale(-1.0) z.SubMatrix(n, 0, n, 1).Set(z_res) // z[2*n:] -= 2.0*v*( v[0]*z[2*n] - blas.dot(v[1:], z[2*n+1:]) ) v0_z2n := v.GetIndex(0) * z.GetIndex(2*n) v1_z2n := blas.DotFloat(v, z, &linalg.IOpt{"offsetx", 1}, &linalg.IOpt{"offsety", 2*n + 1}) z_res = matrix.Scale(v, -2.0*(v0_z2n-v1_z2n)) z.SubMatrix(2*n, 0, z_res.NumElements(), 1).Plus(z_res) // z[2*n+1:] *= -1.0 z.SubMatrix(2*n+1, 0).Scale(-1.0) // z[2*n:] /= beta z.SubMatrix(2*n, 0).Scale(1.0 / beta) // -- x := x - G' * W**-1 * z // z_n = z[:n], z_2n = z[n:2*n], z_m = z[-(m+1):], z_n := z.SubMatrix(0, 0, n, 1) z_2n := z.SubMatrix(n, 0, n, 1) z_m := z.SubMatrix(z.NumElements()-(m+1), 0) // x[:n] -= div(z[:n], d1) - div(z[n:2*n], d2) + As.T * z[-(m+1):] z_res = matrix.Minus(matrix.Div(z_n, d1), matrix.Div(z_2n, d2)) a_res := matrix.Times(As.Transpose(), z_m) z_res.Plus(a_res).Scale(-1.0) x.SubMatrix(0, 0, n, 1).Plus(z_res) // x[n:] += div(z[:n], d1) + div(z[n:2*n], d2) z_res = matrix.Plus(matrix.Div(z_n, d1), matrix.Div(z_2n, d2)) x.SubMatrix(n, 0, z_res.NumElements(), 1).Plus(z_res) checkpnt.Check("15-f", minor) // Solve for x[:n]: // // S*x[:n] = x[:n] - (W1**2 - W2**2)(W1**2 + W2**2)^-1 * x[n:] // w1 = (d1**2 - d2**2), w2 = (d1**2 + d2**2) w1 := matrix.Minus(matrix.Mul(d1, d1), matrix.Mul(d2, d2)) w2 := matrix.Plus(matrix.Mul(d1, d1), matrix.Mul(d2, d2)) // x[:n] += -mul( div(w1, w2), x[n:]) x_n := x.SubMatrix(n, 0) x_val := matrix.Mul(matrix.Div(w1, w2), x_n).Scale(-1.0) x.SubMatrix(0, 0, n, 1).Plus(x_val) checkpnt.Check("25-f", minor) // Solve for x[n:]: // // (d1**-2 + d2**-2) * x[n:] = x[n:] + (d1**-2 - d2**-2)*x[:n] err = lapack.Potrs(S, x) if err != nil { fmt.Printf("Potrs error: %s\n", err) } checkpnt.Check("30-f", minor) // Solve for x[n:]: // // (d1**-2 + d2**-2) * x[n:] = x[n:] + (d1**-2 - d2**-2)*x[:n] // w1 = (d1**-2 - d2**-2), w2 = (d1**-2 + d2**-2) w1 = matrix.Minus(matrix.Mul(d1, d1).Inv(), matrix.Mul(d2, d2).Inv()) w2 = matrix.Plus(matrix.Mul(d1, d1).Inv(), matrix.Mul(d2, d2).Inv()) x_n = x.SubMatrix(0, 0, n, 1) // x[n:] += mul( d1**-2 - d2**-2, x[:n]) x_val = matrix.Mul(w1, x_n) x.SubMatrix(n, 0, x_val.NumElements(), 1).Plus(x_val) checkpnt.Check("35-f", minor) // x[n:] = div( x[n:], d1**-2 + d2**-2) x_n = x.SubMatrix(n, 0) x_val = matrix.Div(x_n, w2) x.SubMatrix(n, 0, x_val.NumElements(), 1).Set(x_val) checkpnt.Check("40-f", minor) // x_n = x[:n], x-2n = x[n:2*n] x_n = x.SubMatrix(0, 0, n, 1) x_2n := x.SubMatrix(n, 0, n, 1) // z := z + W^-T * G*x // z[:n] += div( x[:n] - x[n:2*n], d1) x_val = matrix.Div(matrix.Minus(x_n, x_2n), d1) z.SubMatrix(0, 0, n, 1).Plus(x_val) checkpnt.Check("44-f", minor) // z[n:2*n] += div( -x[:n] - x[n:2*n], d2) x_val = matrix.Div(matrix.Plus(x_n, x_2n).Scale(-1.0), d2) z.SubMatrix(n, 0, n, 1).Plus(x_val) checkpnt.Check("48-f", minor) // z[2*n:] += As*x[:n] x_val = matrix.Times(As, x_n) z.SubMatrix(2*n, 0, x_val.NumElements(), 1).Plus(x_val) checkpnt.Check("50-f", minor) return nil } return } // matrix(n*[0.0] + n*[1.0]) c := matrix.FloatZeros(2*n, 1) c.SubMatrix(n, 0).SetIndexes(1.0) h := matrix.FloatZeros(2*n+m+1, 1) h.SetIndexes(1.0, 2*n) // h[2*n+1:] = -b h.SubMatrix(2*n+1, 0).Plus(b).Scale(-1.0) G := &matrixFs{A} dims := sets.DSetNew("l", "q", "s") dims.Set("l", []int{2 * n}) dims.Set("q", []int{m + 1}) var solopts cvx.SolverOptions solopts.ShowProgress = true if maxIter > 0 { solopts.MaxIter = maxIter } if len(solver) > 0 { solopts.KKTSolverName = solver } return cvx.ConeLpCustomMatrix(c, G, h, nil, nil, dims, Fkkt, &solopts, nil, nil) }
/* Returns the Nesterov-Todd scaling W at points s and z, and stores the scaled variable in lmbda. W * z = W^{-T} * s = lmbda. W is a MatrixSet with entries: - W['dnl']: positive vector - W['dnli']: componentwise inverse of W['dnl'] - W['d']: positive vector - W['di']: componentwise inverse of W['d'] - W['v']: lists of 2nd order cone vectors with unit hyperbolic norms - W['beta']: list of positive numbers - W['r']: list of square matrices - W['rti']: list of square matrices. rti[k] is the inverse transpose of r[k]. */ func computeScaling(s, z, lmbda *matrix.FloatMatrix, dims *sets.DimensionSet, mnl int) (W *sets.FloatMatrixSet, err error) { /*DEBUGGED*/ err = nil W = sets.NewFloatSet("dnl", "dnli", "d", "di", "v", "beta", "r", "rti") // For the nonlinear block: // // W['dnl'] = sqrt( s[:mnl] ./ z[:mnl] ) // W['dnli'] = sqrt( z[:mnl] ./ s[:mnl] ) // lambda[:mnl] = sqrt( s[:mnl] .* z[:mnl] ) var stmp, ztmp, lmd *matrix.FloatMatrix if mnl > 0 { stmp = matrix.FloatVector(s.FloatArray()[:mnl]) ztmp = matrix.FloatVector(z.FloatArray()[:mnl]) //dnl := stmp.Div(ztmp) //dnl.Apply(dnl, math.Sqrt) dnl := matrix.Sqrt(matrix.Div(stmp, ztmp)) //dnli := dnl.Copy() //dnli.Apply(dnli, func(a float64)float64 { return 1.0/a }) dnli := matrix.Inv(dnl) W.Set("dnl", dnl) W.Set("dnli", dnli) //lmd = stmp.Mul(ztmp) //lmd.Apply(lmd, math.Sqrt) lmd = matrix.Sqrt(matrix.Mul(stmp, ztmp)) lmbda.SetIndexesFromArray(lmd.FloatArray(), matrix.MakeIndexSet(0, mnl, 1)...) } else { // set for empty matrices //W.Set("dnl", matrix.FloatZeros(0, 1)) //W.Set("dnli", matrix.FloatZeros(0, 1)) mnl = 0 } // For the 'l' block: // // W['d'] = sqrt( sk ./ zk ) // W['di'] = sqrt( zk ./ sk ) // lambdak = sqrt( sk .* zk ) // // where sk and zk are the first dims['l'] entries of s and z. // lambda_k is stored in the first dims['l'] positions of lmbda. m := dims.At("l")[0] //td := s.FloatArray() stmp = matrix.FloatVector(s.FloatArray()[mnl : mnl+m]) //zd := z.FloatArray() ztmp = matrix.FloatVector(z.FloatArray()[mnl : mnl+m]) //fmt.Printf(".Sqrt()=\n%v\n", matrix.Div(stmp, ztmp).Sqrt().ToString("%.17f")) //d := stmp.Div(ztmp) //d.Apply(d, math.Sqrt) d := matrix.Div(stmp, ztmp).Sqrt() //di := d.Copy() //di.Apply(di, func(a float64)float64 { return 1.0/a }) di := matrix.Inv(d) //fmt.Printf("d:\n%v\n", d) //fmt.Printf("di:\n%v\n", di) W.Set("d", d) W.Set("di", di) //lmd = stmp.Mul(ztmp) //lmd.Apply(lmd, math.Sqrt) lmd = matrix.Mul(stmp, ztmp).Sqrt() // lmd has indexes mnl:mnl+m and length of m lmbda.SetIndexesFromArray(lmd.FloatArray(), matrix.MakeIndexSet(mnl, mnl+m, 1)...) //fmt.Printf("after l:\n%v\n", lmbda) /* For the 'q' blocks, compute lists 'v', 'beta'. The vector v[k] has unit hyperbolic norm: (sqrt( v[k]' * J * v[k] ) = 1 with J = [1, 0; 0, -I]). beta[k] is a positive scalar. The hyperbolic Householder matrix H = 2*v[k]*v[k]' - J defined by v[k] satisfies (beta[k] * H) * zk = (beta[k] * H) \ sk = lambda_k where sk = s[indq[k]:indq[k+1]], zk = z[indq[k]:indq[k+1]]. lambda_k is stored in lmbda[indq[k]:indq[k+1]]. */ ind := mnl + dims.At("l")[0] var beta *matrix.FloatMatrix for _, k := range dims.At("q") { W.Append("v", matrix.FloatZeros(k, 1)) } beta = matrix.FloatZeros(len(dims.At("q")), 1) W.Set("beta", beta) vset := W.At("v") for k, m := range dims.At("q") { v := vset[k] // a = sqrt( sk' * J * sk ) where J = [1, 0; 0, -I] aa := jnrm2(s, m, ind) // b = sqrt( zk' * J * zk ) bb := jnrm2(z, m, ind) // beta[k] = ( a / b )**1/2 beta.SetIndex(k, math.Sqrt(aa/bb)) // c = sqrt( (sk/a)' * (zk/b) + 1 ) / sqrt(2) c0 := blas.DotFloat(s, z, &la_.IOpt{"n", m}, &la_.IOpt{"offsetx", ind}, &la_.IOpt{"offsety", ind}) cc := math.Sqrt((c0/aa/bb + 1.0) / 2.0) // vk = 1/(2*c) * ( (sk/a) + J * (zk/b) ) blas.CopyFloat(z, v, &la_.IOpt{"offsetx", ind}, &la_.IOpt{"n", m}) blas.ScalFloat(v, -1.0/bb) v.SetIndex(0, -1.0*v.GetIndex(0)) blas.AxpyFloat(s, v, 1.0/aa, &la_.IOpt{"offsetx", ind}, &la_.IOpt{"n", m}) blas.ScalFloat(v, 1.0/2.0/cc) // v[k] = 1/sqrt(2*(vk0 + 1)) * ( vk + e ), e = [1; 0] v.SetIndex(0, v.GetIndex(0)+1.0) blas.ScalFloat(v, (1.0 / math.Sqrt(2.0*v.GetIndex(0)))) /* To get the scaled variable lambda_k d = sk0/a + zk0/b + 2*c lambda_k = [ c; (c + zk0/b)/d * sk1/a + (c + sk0/a)/d * zk1/b ] lambda_k *= sqrt(a * b) */ lmbda.SetIndex(ind, cc) dd := 2*cc + s.GetIndex(ind)/aa + z.GetIndex(ind)/bb blas.CopyFloat(s, lmbda, &la_.IOpt{"offsetx", ind + 1}, &la_.IOpt{"offsety", ind + 1}, &la_.IOpt{"n", m - 1}) zz := (cc + z.GetIndex(ind)/bb) / dd / aa ss := (cc + s.GetIndex(ind)/aa) / dd / bb blas.ScalFloat(lmbda, zz, &la_.IOpt{"offset", ind + 1}, &la_.IOpt{"n", m - 1}) blas.AxpyFloat(z, lmbda, ss, &la_.IOpt{"offsetx", ind + 1}, &la_.IOpt{"offsety", ind + 1}, &la_.IOpt{"n", m - 1}) blas.ScalFloat(lmbda, math.Sqrt(aa*bb), &la_.IOpt{"offset", ind}, &la_.IOpt{"n", m}) ind += m //fmt.Printf("after q[%d]:\n%v\n", k, lmbda) } /* For the 's' blocks: compute two lists 'r' and 'rti'. r[k]' * sk^{-1} * r[k] = diag(lambda_k)^{-1} r[k]' * zk * r[k] = diag(lambda_k) where sk and zk are the entries inds[k] : inds[k+1] of s and z, reshaped into symmetric matrices. rti[k] is the inverse of r[k]', so rti[k]' * sk * rti[k] = diag(lambda_k)^{-1} rti[k]' * zk^{-1} * rti[k] = diag(lambda_k). The vectors lambda_k are stored in lmbda[ dims['l'] + sum(dims['q']) : -1 ] */ for _, k := range dims.At("s") { W.Append("r", matrix.FloatZeros(k, k)) W.Append("rti", matrix.FloatZeros(k, k)) } maxs := maxdim(dims.At("s")) work := matrix.FloatZeros(maxs*maxs, 1) Ls := matrix.FloatZeros(maxs*maxs, 1) Lz := matrix.FloatZeros(maxs*maxs, 1) ind2 := ind for k, m := range dims.At("s") { r := W.At("r")[k] rti := W.At("rti")[k] // Factor sk = Ls*Ls'; store Ls in ds[inds[k]:inds[k+1]]. blas.CopyFloat(s, Ls, &la_.IOpt{"offsetx", ind2}, &la_.IOpt{"n", m * m}) lapack.PotrfFloat(Ls, &la_.IOpt{"n", m}, &la_.IOpt{"lda", m}) // Factor zs[k] = Lz*Lz'; store Lz in dz[inds[k]:inds[k+1]]. blas.CopyFloat(z, Lz, &la_.IOpt{"offsetx", ind2}, &la_.IOpt{"n", m * m}) lapack.PotrfFloat(Lz, &la_.IOpt{"n", m}, &la_.IOpt{"lda", m}) // SVD Lz'*Ls = U*diag(lambda_k)*V'. Keep U in work. for i := 0; i < m; i++ { blas.ScalFloat(Ls, 0.0, &la_.IOpt{"offset", i * m}, &la_.IOpt{"n", i}) } blas.CopyFloat(Ls, work, &la_.IOpt{"n", m * m}) blas.TrmmFloat(Lz, work, 1.0, la_.OptTransA, &la_.IOpt{"lda", m}, &la_.IOpt{"ldb", m}, &la_.IOpt{"n", m}, &la_.IOpt{"m", m}) lapack.GesvdFloat(work, lmbda, nil, nil, la_.OptJobuO, &la_.IOpt{"lda", m}, &la_.IOpt{"offsetS", ind}, &la_.IOpt{"n", m}, &la_.IOpt{"m", m}) // r = Lz^{-T} * U blas.CopyFloat(work, r, &la_.IOpt{"n", m * m}) blas.TrsmFloat(Lz, r, 1.0, la_.OptTransA, &la_.IOpt{"lda", m}, &la_.IOpt{"n", m}, &la_.IOpt{"m", m}) // rti = Lz * U blas.CopyFloat(work, rti, &la_.IOpt{"n", m * m}) blas.TrmmFloat(Lz, rti, 1.0, &la_.IOpt{"lda", m}, &la_.IOpt{"n", m}, &la_.IOpt{"m", m}) // r := r * diag(sqrt(lambda_k)) // rti := rti * diag(1 ./ sqrt(lambda_k)) for i := 0; i < m; i++ { a := math.Sqrt(lmbda.GetIndex(ind + i)) blas.ScalFloat(r, a, &la_.IOpt{"offset", m * i}, &la_.IOpt{"n", m}) blas.ScalFloat(rti, 1.0/a, &la_.IOpt{"offset", m * i}, &la_.IOpt{"n", m}) } ind += m ind2 += m * m } return }