func subproblem(X, W, Ho *sparse.Sparse, tolerance float64, iterations int) (H, G *sparse.Sparse, i int, ok bool) { H = Ho.Copy() WtV := W.T().Dot(X) WtW := W.T().Dot(W) var alpha, beta float64 = 1, 0.1 for i := 0; i < iterations; i++ { G = WtW.Dot(H).Sub(WtV) filter := func(r, c int, v float64) bool { h := H.At(r, c) return v < 0 || h > 0 // filter called with G as receiver, so v, _ = G.At(r, c) } if projection := G.Filter(filter).Norm(matrix.Fro); projection < tolerance { break } } var ( decrease bool Hp *sparse.Sparse ) for j := 0; j < InnerLoop; j++ { Hn := H.Sub(G.Scalar(alpha)) filter := func(r, c int, v float64) bool { return v > 0 // filter called with Hn as receiver, so v, _ = Hn.At(r, c) } Hn = Hn.Filter(filter) d := Hn.Sub(H) gd := G.MulElem(d).Sum() dQd := WtW.Dot(d).MulElem(d).Sum() sufficient := 0.99*gd+0.5*dQd < 0 if j == 0 { decrease = !sufficient Hp = H.Copy() } if decrease { if sufficient { H = Hn ok = true break } else { alpha *= beta } } else { if !sufficient || Hp.Equals(Hn) { H = Hp ok = true break } else { alpha /= beta Hp = Hn.Copy() } } } return }