/* Applies Nesterov-Todd scaling or its inverse. Computes x := W*x (trans is false 'N', inverse = false 'N') x := W^T*x (trans is true 'T', inverse = false 'N') x := W^{-1}*x (trans is false 'N', inverse = true 'T') x := W^{-T}*x (trans is true 'T', inverse = true 'T'). x is a dense float matrix. 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]. The 'dnl' and 'dnli' entries are optional, and only present when the function is called from the nonlinear solver. */ func scale(x *matrix.FloatMatrix, W *FloatMatrixSet, trans, inverse bool) (err error) { /*DEBUGGED*/ var wl []*matrix.FloatMatrix var w *matrix.FloatMatrix ind := 0 err = nil // Scaling for nonlinear component xk is xk := dnl .* xk; inverse // scaling is xk ./ dnl = dnli .* xk, where dnl = W['dnl'], // dnli = W['dnli']. if wl = W.At("dnl"); wl != nil { if inverse { w = W.At("dnli")[0] } else { w = W.At("dnl")[0] } for k := 0; k < x.Cols(); k++ { err = blas.TbmvFloat(w, x, &la_.IOpt{"n", w.Rows()}, &la_.IOpt{"k", 0}, &la_.IOpt{"lda", 1}, &la_.IOpt{"offsetx", k * x.Rows()}) if err != nil { return } } ind += w.Rows() } // Scaling for linear 'l' component xk is xk := d .* xk; inverse // scaling is xk ./ d = di .* xk, where d = W['d'], di = W['di']. if inverse { w = W.At("di")[0] } else { w = W.At("d")[0] } for k := 0; k < x.Cols(); k++ { err = blas.TbmvFloat(w, x, &la_.IOpt{"n", w.Rows()}, &la_.IOpt{"k", 0}, &la_.IOpt{"lda", 1}, &la_.IOpt{"offsetx", k*x.Rows() + ind}) if err != nil { return } } ind += w.Rows() // Scaling for 'q' component is // // xk := beta * (2*v*v' - J) * xk // = beta * (2*v*(xk'*v)' - J*xk) // // where beta = W['beta'][k], v = W['v'][k], J = [1, 0; 0, -I]. // //Inverse scaling is // // xk := 1/beta * (2*J*v*v'*J - J) * xk // = 1/beta * (-J) * (2*v*((-J*xk)'*v)' + xk). //wf := matrix.FloatZeros(x.Cols(), 1) w = matrix.FloatZeros(x.Cols(), 1) for k, v := range W.At("v") { m := v.Rows() if inverse { blas.ScalFloat(x, -1.0, &la_.IOpt{"offset", ind}, &la_.IOpt{"inc", x.Rows()}) } err = blas.GemvFloat(x, v, w, 1.0, 0.0, la_.OptTrans, &la_.IOpt{"m", m}, &la_.IOpt{"n", x.Cols()}, &la_.IOpt{"offsetA", ind}, &la_.IOpt{"lda", x.Rows()}) if err != nil { return } err = blas.ScalFloat(x, -1.0, &la_.IOpt{"offset", ind}, &la_.IOpt{"inc", x.Rows()}) if err != nil { return } err = blas.GerFloat(v, w, x, 2.0, &la_.IOpt{"m", m}, &la_.IOpt{"n", x.Cols()}, &la_.IOpt{"lda", x.Rows()}, &la_.IOpt{"offsetA", ind}) if err != nil { return } var a float64 if inverse { blas.ScalFloat(x, -1.0, &la_.IOpt{"offset", ind}, &la_.IOpt{"inc", x.Rows()}) // a[i,j] := 1.0/W[i,j] a = 1.0 / W.At("beta")[0].GetIndex(k) } else { a = W.At("beta")[0].GetIndex(k) } for i := 0; i < x.Cols(); i++ { blas.ScalFloat(x, a, &la_.IOpt{"n", m}, &la_.IOpt{"offset", ind + i*x.Rows()}) } ind += m } // Scaling for 's' component xk is // // xk := vec( r' * mat(xk) * r ) if trans = 'N' // xk := vec( r * mat(xk) * r' ) if trans = 'T'. // // r is kth element of W['r']. // // Inverse scaling is // // xk := vec( rti * mat(xk) * rti' ) if trans = 'N' // xk := vec( rti' * mat(xk) * rti ) if trans = 'T'. // // rti is kth element of W['rti']. maxn := 0 for _, r := range W.At("r") { if r.Rows() > maxn { maxn = r.Rows() } } a := matrix.FloatZeros(maxn, maxn) for k, v := range W.At("r") { t := trans var r *matrix.FloatMatrix if !inverse { r = v t = !trans } else { r = W.At("rti")[k] } n := r.Rows() for i := 0; i < x.Cols(); i++ { // scale diagonal of xk by 0.5 blas.ScalFloat(x, 0.5, &la_.IOpt{"offset", ind + i*x.Rows()}, &la_.IOpt{"inc", n + 1}, &la_.IOpt{"n", n}) // a = r*tril(x) (t is 'N') or a = tril(x)*r (t is 'T') blas.Copy(r, a) if !t { err = blas.TrmmFloat(x, a, 1.0, la_.OptRight, &la_.IOpt{"m", n}, &la_.IOpt{"n", n}, &la_.IOpt{"lda", n}, &la_.IOpt{"ldb", n}, &la_.IOpt{"offsetA", ind + i*x.Rows()}) if err != nil { return } // x := (r*a' + a*r') if t is 'N' err = blas.Syr2kFloat(r, a, x, 1.0, 0.0, la_.OptNoTrans, &la_.IOpt{"n", n}, &la_.IOpt{"k", n}, &la_.IOpt{"ldb", n}, &la_.IOpt{"ldc", n}, &la_.IOpt{"offsetC", ind + i*x.Rows()}) if err != nil { return } } else { err = blas.TrmmFloat(x, a, 1.0, la_.OptLeft, &la_.IOpt{"m", n}, &la_.IOpt{"n", n}, &la_.IOpt{"lda", n}, &la_.IOpt{"ldb", n}, &la_.IOpt{"offsetA", ind + i*x.Rows()}) if err != nil { return } // x := (r'*a + a'*r) if t is 'T' err = blas.Syr2kFloat(r, a, x, 1.0, 0.0, la_.OptTrans, &la_.IOpt{"n", n}, &la_.IOpt{"k", n}, &la_.IOpt{"ldb", n}, &la_.IOpt{"ldc", n}, &la_.IOpt{"offsetC", ind + i*x.Rows()}) if err != nil { return } } } ind += n * n } return }
// The product x := (y o x). If diag is 'D', the 's' part of y is // diagonal and only the diagonal is stored. func sprod(x, y *matrix.FloatMatrix, dims *DimensionSet, mnl int, opts ...la_.Option) (err error) { err = nil diag := la_.GetStringOpt("diag", "N", opts...) // For the nonlinear and 'l' blocks: // // yk o xk = yk .* xk. ind := mnl + dims.At("l")[0] err = blas.Tbmv(y, x, &la_.IOpt{"n", ind}, &la_.IOpt{"k", 0}, &la_.IOpt{"lda", 1}) if err != nil { return } //fmt.Printf("Sprod l:x=\n%v\n", x) // For 'q' blocks: // // [ l0 l1' ] // yk o xk = [ ] * xk // [ l1 l0*I ] // // where yk = (l0, l1). for _, m := range dims.At("q") { dd := blas.DotFloat(x, y, &la_.IOpt{"offsetx", ind}, &la_.IOpt{"offsety", ind}, &la_.IOpt{"n", m}) //fmt.Printf("dd=%v\n", dd) alpha := y.GetIndex(ind) //fmt.Printf("scal=%v\n", alpha) blas.ScalFloat(x, alpha, &la_.IOpt{"offset", ind + 1}, &la_.IOpt{"n", m - 1}) alpha = x.GetIndex(ind) //fmt.Printf("axpy=%v\n", alpha) blas.AxpyFloat(y, x, alpha, &la_.IOpt{"offsetx", ind + 1}, &la_.IOpt{"offsety", ind + 1}, &la_.IOpt{"n", m - 1}) x.SetIndex(ind, dd) ind += m } //fmt.Printf("Sprod q :x=\n%v\n", x) // For the 's' blocks: // // yk o sk = .5 * ( Yk * mat(xk) + mat(xk) * Yk ) // // where Yk = mat(yk) if diag is 'N' and Yk = diag(yk) if diag is 'D'. if diag[0] == 'N' { // DEBUGGED maxm := maxdim(dims.At("s")) A := matrix.FloatZeros(maxm, maxm) for _, m := range dims.At("s") { blas.Copy(x, A, &la_.IOpt{"offsetx", ind}, &la_.IOpt{"n", m * m}) for i := 0; i < m-1; i++ { // i < m-1 --> i < m symm(A, m, 0) symm(y, m, ind) } err = blas.Syr2kFloat(A, y, x, 0.5, 0.0, &la_.IOpt{"n", m}, &la_.IOpt{"k", m}, &la_.IOpt{"lda", m}, &la_.IOpt{"ldb", m}, &la_.IOpt{"ldc", m}, &la_.IOpt{"offsetb", ind}, &la_.IOpt{"offsetc", ind}) if err != nil { return } ind += m * m } //fmt.Printf("Sprod diag=N s:x=\n%v\n", x) } else { ind2 := ind for _, m := range dims.At("s") { for i := 0; i < m; i++ { // original: u = 0.5 * ( y[ind2+i:ind2+m] + y[ind2+i] ) // creates matrix of elements: [ind2+i ... ind2+m] then // element wisely adds y[ind2+i] and scales by 0.5 iset := matrix.MakeIndexSet(ind2+i, ind2+m, 1) u := matrix.FloatVector(y.GetIndexes(iset)) u.Add(y.GetIndex(ind2 + i)) u.Scale(0.5) err = blas.Tbmv(u, x, &la_.IOpt{"n", m - i}, &la_.IOpt{"k", 0}, &la_.IOpt{"lda", 1}, &la_.IOpt{"offsetx", ind + i*(m+1)}) if err != nil { return } } ind += m * m ind2 += m } //fmt.Printf("Sprod diag=T s:x=\n%v\n", x) } return }