func (g *gradientIterator) updateCaches() { // This function computes and uses various pieces // of the quadratic form 1/2*c'*A*c - b'*c. columnMat := &linalg.Matrix{ Rows: g.matrix.Cols, Cols: 1, Data: g.solution, } // Compute A*c. columnProduct := g.matrix.Mul(columnMat) // Compute c'*A*c. quadValue := kahan.NewSummer64() for i, x := range g.solution { quadValue.Add(x * columnProduct.Data[i]) } // Compute b'*c linearValue := kahan.NewSummer64() for _, x := range g.solution { linearValue.Add(x) } g.quadraticCache = quadValue.Sum()*0.5 - linearValue.Sum() // Compute A*c - b. for i, x := range columnProduct.Data { columnProduct.Data[i] = x - 1 } g.gradientCache = columnProduct.Data }
// ProjectOutComp projects the active constraints // out of a vector and returns the i-th component // of the result, without modifying the original // vector. func (a *activeSet) ProjectOutComp(d linalg.Vector, comp int) float64 { if a.Constraints[comp] != 0 { return 0 } signVec := a.SignVec var signDotSign int signDotD := kahan.NewSummer64() for i, x := range a.Constraints { if x == 0 { signDotSign++ signDotD.Add(d[i] * signVec[i]) } } projAmount := signDotD.Sum() / float64(signDotSign) return d[comp] - projAmount*signVec[comp] }
func (g *gradientIterator) optimalStep(d linalg.Vector) float64 { // The optimal step size is (d'*b - c'*A*d)/(d'*A*d) // where d is the direction, A is the matrix, x is // the current approximate solution, and b is all 1's. dMat := &linalg.Matrix{ Rows: len(d), Cols: 1, Data: d, } ad := linalg.Vector(g.matrix.Mul(dMat).Data) summer := kahan.NewSummer64() for _, x := range d { summer.Add(x) } numerator := summer.Sum() - g.solution.Dot(ad) denominator := d.Dot(ad) return numerator / denominator }
// ProjectOut projects the active constraints // out of a gradient vector (in place). func (a *activeSet) ProjectOut(d linalg.Vector) { signVec := a.SignVec var signDotSign int signDotD := kahan.NewSummer64() for i, x := range a.Constraints { if x != 0 { d[i] = 0 } else { signDotSign++ signDotD.Add(d[i] * signVec[i]) } } projAmount := signDotD.Sum() / float64(signDotSign) for i, x := range a.Constraints { if x == 0 { d[i] -= projAmount * signVec[i] } } }