func sinv(x, y *matrix.FloatMatrix, dims *DimensionSet, mnl int) (err error) { /*DEBUGGED*/ err = nil // For the nonlinear and 'l' blocks: // // yk o\ xk = yk .\ xk. ind := mnl + dims.At("l")[0] blas.Tbsv(y, x, &la_.IOpt{"n", ind}, &la_.IOpt{"k", 0}, &la_.IOpt{"ldA", 1}) // For the 'q' blocks: // // [ l0 -l1' ] // yk o\ xk = 1/a^2 * [ ] * xk // [ -l1 (a*I + l1*l1')/l0 ] // // where yk = (l0, l1) and a = l0^2 - l1'*l1. for _, m := range dims.At("q") { aa := blas.Nrm2Float(y, &la_.IOpt{"n", m - 1}, &la_.IOpt{"offset", ind + 1}) ee := y.GetIndex(ind) aa = (ee + aa) * (ee - aa) cc := x.GetIndex(ind) dd := blas.DotFloat(x, y, &la_.IOpt{"n", m - 1}, &la_.IOpt{"offsetx", ind + 1}, &la_.IOpt{"offsety", ind + 1}) x.SetIndex(ind, cc*ee-dd) blas.ScalFloat(x, aa/ee, &la_.IOpt{"n", m - 1}, &la_.IOpt{"offset", ind + 1}) blas.AxpyFloat(y, x, dd/ee-cc, &la_.IOpt{"n", m - 1}, &la_.IOpt{"offsetx", ind + 1}, &la_.IOpt{"offsety", ind + 1}) blas.ScalFloat(x, 1.0/aa, &la_.IOpt{"n", m}, &la_.IOpt{"offset", ind}) ind += m } // For the 's' blocks: // // yk o\ xk = xk ./ gamma // // where gammaij = .5 * (yk_i + yk_j). ind2 := ind for _, m := range dims.At("s") { for j := 0; j < m; j++ { u := matrix.FloatVector(y.FloatArray()[ind2+j : ind2+m]) u.Add(y.GetIndex(ind2 + j)) u.Scale(0.5) blas.Tbsv(u, x, &la_.IOpt{"n", m - j}, &la_.IOpt{"k", 0}, &la_.IOpt{"lda", 1}, &la_.IOpt{"offsetx", ind + j*(m+1)}) } ind += m * m ind2 += m } return }
/* Evaluates x := H(lambda^{1/2}) * x (inverse is 'N') x := H(lambda^{-1/2}) * x (inverse is 'I'). H is the Hessian of the logarithmic barrier. */ func scale2(lmbda, x *matrix.FloatMatrix, dims *DimensionSet, mnl int, inverse bool) (err error) { err = nil // For the nonlinear and 'l' blocks, // // xk := xk ./ l (inverse is 'N') // xk := xk .* l (inverse is 'I') // // where l is lmbda[:mnl+dims['l']]. ind := mnl + dims.Sum("l") if !inverse { blas.TbsvFloat(lmbda, x, &la_.IOpt{"n", ind}, &la_.IOpt{"k", 0}, &la_.IOpt{"lda", 1}) } else { blas.TbmvFloat(lmbda, x, &la_.IOpt{"n", ind}, &la_.IOpt{"k", 0}, &la_.IOpt{"lda", 1}) } // For 'q' blocks, if inverse is 'N', // // xk := 1/a * [ l'*J*xk; // xk[1:] - (xk[0] + l'*J*xk) / (l[0] + 1) * l[1:] ]. // // If inverse is 'I', // // xk := a * [ l'*xk; // xk[1:] + (xk[0] + l'*xk) / (l[0] + 1) * l[1:] ]. // // a = sqrt(lambda_k' * J * lambda_k), l = lambda_k / a. for _, m := range dims.At("q") { var lx, a, c, x0 float64 a = jnrm2(lmbda, m, ind) //&la_.IOpt{"n", m}, &la_.IOpt{"offset", ind}) if !inverse { lx = jdot(lmbda, x, m, ind, ind) //&la_.IOpt{"n", m}, &la_.IOpt{"offsetx", ind}, //&la_.IOpt{"offsety", ind}) lx /= a } else { lx = blas.DotFloat(lmbda, x, &la_.IOpt{"n", m}, &la_.IOpt{"offsetx", ind}, &la_.IOpt{"offsety", ind}) lx /= a } x0 = x.GetIndex(ind) x.SetIndex(ind, lx) c = (lx + x0) / (lmbda.GetIndex(ind)/a + 1.0) / a if !inverse { c *= -1.0 } blas.AxpyFloat(lmbda, x, c, &la_.IOpt{"n", m - 1}, &la_.IOpt{"offsetx", ind + 1}, &la_.IOpt{"offsety", ind + 1}) if !inverse { a = 1.0 / a } blas.ScalFloat(x, a, &la_.IOpt{"offset", ind}, &la_.IOpt{"n", m}) ind += m } // For the 's' blocks, if inverse is 'N', // // xk := vec( diag(l)^{-1/2} * mat(xk) * diag(k)^{-1/2}). // // If inverse is true, // // xk := vec( diag(l)^{1/2} * mat(xk) * diag(k)^{1/2}). // // where l is kth block of lambda. // // We scale upper and lower triangular part of mat(xk) because the // inverse operation will be applied to nonsymmetric matrices. ind2 := ind sdims := dims.At("s") for k := 0; k < len(sdims); k++ { m := sdims[k] scaleF := func(v, x float64) float64 { return math.Sqrt(v) * math.Sqrt(x) } for j := 0; j < m; j++ { c := matrix.FloatVector(lmbda.FloatArray()[ind2 : ind2+m]) c.ApplyConst(c, scaleF, lmbda.GetIndex(ind2+j)) if !inverse { blas.Tbsv(c, x, &la_.IOpt{"n", m}, &la_.IOpt{"k", 0}, &la_.IOpt{"lda", 1}, &la_.IOpt{"offsetx", ind + j*m}) } else { blas.Tbmv(c, x, &la_.IOpt{"n", m}, &la_.IOpt{"k", 0}, &la_.IOpt{"lda", 1}, &la_.IOpt{"offsetx", ind + j*m}) } } ind += m * m ind2 += m } return }