func nnlsSubproblem(V, W, Ho *mat64.Dense, tol float64, outer, inner int) (H, G *mat64.Dense, i int, ok bool) { H = new(mat64.Dense) H.Clone(Ho) var WtV, WtW mat64.Dense WtV.Mul(W.T(), V) WtW.Mul(W.T(), W) alpha, beta := 1., 0.1 decFilt := func(r, c int, v float64) float64 { // decFilt is applied to G, so v = G.At(r, c). if v < 0 || H.At(r, c) > 0 { return v } return 0 } G = new(mat64.Dense) for i = 0; i < outer; i++ { G.Mul(&WtW, H) G.Sub(G, &WtV) G.Apply(decFilt, G) if mat64.Norm(G, 2) < tol { break } var ( reduce bool Hp *mat64.Dense d, dQ mat64.Dense ) for j := 0; j < inner; j++ { var Hn mat64.Dense Hn.Scale(alpha, G) Hn.Sub(H, &Hn) Hn.Apply(posFilt, &Hn) d.Sub(&Hn, H) dQ.Mul(&WtW, &d) dQ.MulElem(&dQ, &d) d.MulElem(G, &d) sufficient := 0.99*mat64.Sum(&d)+0.5*mat64.Sum(&dQ) < 0 if j == 0 { reduce = !sufficient Hp = H } if reduce { if sufficient { H = &Hn ok = true break } else { alpha *= beta } } else { if !sufficient || mat64.Equal(Hp, &Hn) { H = Hp break } else { alpha /= beta Hp = &Hn } } } } return H, G, i, ok }