func (pg *ProjectedGradient) Minimize(loss Function, stop StopCriteria, vec Parameter) (float32, error) {

	stt := vec

	// Remember to clip the point before we do any thing.
	pg.projector.ClipPoint(stt)

	nxt := stt.CloneWithoutCopy()
	cdd := stt.CloneWithoutCopy()
	Fill(nxt, 0)

	// Evaluate once
	ovalgrad := &vgpair{value: 0, gradient: stt.CloneWithoutCopy()}
	evaluate(loss, stt, ovalgrad)
	nvalgrad := &vgpair{value: 0, gradient: stt.CloneWithoutCopy()}
	tvalgrad := &vgpair{value: 0, gradient: stt.CloneWithoutCopy()}

	alpha := pg.alpha

	for k := 0; !stop.Done(stt, ovalgrad.value, ovalgrad.gradient); k += 1 {

		newPoint(stt, nxt, ovalgrad.gradient, alpha, pg.projector)
		evaluate(loss, nxt, nvalgrad)

		if pg.isGoodStep(stt, nxt, ovalgrad, nvalgrad) {
			newPoint(stt, cdd, ovalgrad.gradient, alpha/pg.beta, pg.projector)
			evaluate(loss, cdd, tvalgrad)
			for pg.isGoodStep(stt, cdd, ovalgrad, tvalgrad) {
				nxt, cdd = cdd, nxt
				nvalgrad, tvalgrad = tvalgrad, nvalgrad
				// Now increase alpha as much as we can.
				alpha /= pg.beta
				newPoint(stt, cdd, ovalgrad.gradient, alpha/pg.beta, pg.projector)
				evaluate(loss, cdd, tvalgrad)
			}
		} else {
			// Now we decrease alpha barely enough to make sufficient decrease
			// of the objective value.
			for !pg.isGoodStep(stt, nxt, ovalgrad, nvalgrad) {
				alpha *= pg.beta
				newPoint(stt, nxt, ovalgrad.gradient, alpha, pg.projector)
				evaluate(loss, nxt, nvalgrad)
			}
		}

		// Now we arrive at a point satisfies sufficient decrease condition.
		// Swap the wts and gradient for the next round.
		stt, nxt = nxt, stt
		ovalgrad, nvalgrad = nvalgrad, ovalgrad
	}

	// Originally stt == vec, but stt may be swapped to newly created param (nxt). So copy it to output param here.
	for it := vec.IndexIterator(); it.Next(); {
		i := it.Index()
		vec.Set(i, stt.Get(i))
	}

	// This is so that we can reuse the step size in next round.
	pg.alpha = alpha

	// Return the final loss func value and error.
	return ovalgrad.value, nil
}
// This implementation is based on "Projected Gradient Methods for Non-negative Matrix
// Factorization" by Chih-Jen Lin. Particularly it is based on the discription of an
// improved projected gradient method in page 10 of that paper.
This implementation is based on "Projected Gradient Methods for Non-negative Matrix
Factorization" by Chih-Jen Lin. Particularly it is based on the discription of an
improved projected gradient method in page 10 of that paper.
// This implementation is based on " Projected Gradient Methods for Non - negative Matrix // Factorization " by Chih - Jen Lin . Particularly it is based on the discription of an // improved projected gradient method in page 10 of that paper .
func (pg *ProjectedGradient) Minimize(loss Function, stop StopCriteria, vec Parameter) (float32, error) {
	stt := vec
	pg.projector.ClipPoint(stt)
	nxt := stt.CloneWithoutCopy()
	cdd := stt.CloneWithoutCopy()
	Fill(nxt, 0)
	ovalgrad := &vgpair{value: 0, gradient: stt.CloneWithoutCopy()}
	evaluate(loss, stt, ovalgrad)
	nvalgrad := &vgpair{value: 0, gradient: stt.CloneWithoutCopy()}
	tvalgrad := &vgpair{value: 0, gradient: stt.CloneWithoutCopy()}
	alpha := pg.alpha
	for k := 0; !stop.Done(stt, ovalgrad.value, ovalgrad.gradient); k += 1 {
		newPoint(stt, nxt, ovalgrad.gradient, alpha, pg.projector)
		evaluate(loss, nxt, nvalgrad)
		if pg.isGoodStep(stt, nxt, ovalgrad, nvalgrad) {
			newPoint(stt, cdd, ovalgrad.gradient, alpha/pg.beta, pg.projector)
			evaluate(loss, cdd, tvalgrad)
			for pg.isGoodStep(stt, cdd, ovalgrad, tvalgrad) {
				nxt, cdd = cdd, nxt
				nvalgrad, tvalgrad = tvalgrad, nvalgrad
				alpha /= pg.beta
				newPoint(stt, cdd, ovalgrad.gradient, alpha/pg.beta, pg.projector)
				evaluate(loss, cdd, tvalgrad)
			}
		} else {
			for !pg.isGoodStep(stt, nxt, ovalgrad, nvalgrad) {
				alpha *= pg.beta
				newPoint(stt, nxt, ovalgrad.gradient, alpha, pg.projector)
				evaluate(loss, nxt, nvalgrad)
			}
		}
		stt, nxt = nxt, stt
		ovalgrad, nvalgrad = nvalgrad, ovalgrad
	}
	for it := vec.IndexIterator(); it.Next(); {
		i := it.Index()
		vec.Set(i, stt.Get(i))
	}
	pg.alpha = alpha
	return ovalgrad.value, nil
}
func ( pg * ProjectedGradient ) Minimize ( loss Function , stop StopCriteria , vec Parameter ) ( float32 , error ) { stt := vec pg . projector . ClipPoint ( stt ) nxt := stt . CloneWithoutCopy ( ) cdd := stt . CloneWithoutCopy ( ) Fill ( nxt , 0 ) ovalgrad := & vgpair { value : 0 , gradient : stt . CloneWithoutCopy ( ) } evaluate ( loss , stt , ovalgrad ) nvalgrad := & vgpair { value : 0 , gradient : stt . CloneWithoutCopy ( ) } tvalgrad := & vgpair { value : 0 , gradient : stt . CloneWithoutCopy ( ) } alpha := pg . alpha for k := 0 ; ! stop . Done ( stt , ovalgrad . value , ovalgrad . gradient ) ; k += 1 { newPoint ( stt , nxt , ovalgrad . gradient , alpha , pg . projector ) evaluate ( loss , nxt , nvalgrad ) if pg . isGoodStep ( stt , nxt , ovalgrad , nvalgrad ) { newPoint ( stt , cdd , ovalgrad . gradient , alpha / pg . beta , pg . projector ) evaluate ( loss , cdd , tvalgrad ) for pg . isGoodStep ( stt , cdd , ovalgrad , tvalgrad ) { nxt , cdd = cdd , nxt nvalgrad , tvalgrad = tvalgrad , nvalgrad alpha /= pg . beta newPoint ( stt , cdd , ovalgrad . gradient , alpha / pg . beta , pg . projector ) evaluate ( loss , cdd , tvalgrad ) } } else { for ! pg . isGoodStep ( stt , nxt , ovalgrad , nvalgrad ) { alpha *= pg . beta newPoint ( stt , nxt , ovalgrad . gradient , alpha , pg . projector ) evaluate ( loss , nxt , nvalgrad ) } } stt , nxt = nxt , stt ovalgrad , nvalgrad = nvalgrad , ovalgrad } for it := vec . IndexIterator ( ) ; it . Next ( ) ; { i := it . Index ( ) vec . Set ( i , stt . Get ( i ) ) } pg . alpha = alpha return ovalgrad . value , nil }
This implementation is based on "Projected Gradient Methods for Non-negative Matrix
Factorization" by Chih-Jen Lin.
This implementation is based on " Projected Gradient Methods for Non - negative Matrix Factorization " by Chih - Jen Lin .
// Remember to clip the point before we do any thing. // Evaluate once // Now increase alpha as much as we can. // Now we decrease alpha barely enough to make sufficient decrease // of the objective value. // Now we arrive at a point satisfies sufficient decrease condition. // Swap the wts and gradient for the next round. // Originally stt == vec, but stt may be swapped to newly created param (nxt). So copy it to output param here. // This is so that we can reuse the step size in next round. // Return the final loss func value and error.