コード例 #1
0
ファイル: functions.go プロジェクト: kortschak/opt
func (Q *Quadratic) Val(x mat.Vec) float64 {
	val := 0.0
	Q.temp.Apply(Q.A, x)
	val += mat.Dot(x, Q.temp)
	val += mat.Dot(x, Q.B)
	val += Q.C
	return val
}
コード例 #2
0
ファイル: functions.go プロジェクト: kortschak/opt
func (Q *Quadratic) ValGrad(x, g mat.Vec) float64 {
	At := Q.A.TrView()

	Q.temp.Apply(Q.A, x)

	g.Apply(At, x)
	g.Add(g, Q.temp)
	g.Add(g, Q.B)

	val := 0.0
	val += mat.Dot(x, Q.temp)
	val += mat.Dot(x, Q.B)
	val += Q.C
	return val
}
コード例 #3
0
ファイル: multi_test.go プロジェクト: kortschak/opt
func TestExampleModel(t *testing.T) {
	//badly conditioned Hessian leads to zig-zagging of the steepest descent
	//algorithm
	condNo := 100.0
	optSol := mat.Vec{1, 2}

	A := mat.NewFromArray([]float64{condNo, 0, 0, 1}, true, 2, 2)
	b := mat.Vec{-2 * optSol[0] * condNo, -2 * optSol[1]}
	c := -0.5 * mat.Dot(b, optSol)

	//define objective function
	fun := opt.NewQuadratic(A, b, c)

	//set inital solution estimate
	sol := NewSolution(mat.NewVec(2))

	//set termination parameters
	p := NewParams()
	p.IterMax = 5

	//Use steepest descent solver to solve the model
	result := NewSteepestDescent().Solve(fun, sol, p, NewDisplay(1))

	fmt.Println("x =", result.X)
	//should be [1,2], but because of the bad conditioning we made little
	//progress in the second dimension

	//Use a BFGS solver to refine the result:
	result = NewLBFGS().Solve(fun, result.Solution, p, NewDisplay(1))

	fmt.Println("x =", result.X)
}
コード例 #4
0
ファイル: function.go プロジェクト: kortschak/opt
func (lf *LineFuncDeriv) ValDeriv(x float64) (float64, float64) {
	lf.xTemp.Copy(lf.x)
	lf.xTemp.Axpy(x, lf.d)
	val := lf.f.ValGrad(lf.xTemp, lf.g)

	return val, mat.Dot(lf.d, lf.g)
}
コード例 #5
0
ファイル: lbfgs.go プロジェクト: kortschak/opt
func (sol LBFGS) Solve(o Grad, in *Solution, p *Params, u ...Updater) *Result {
	r := NewResult(in)
	obj := ObjGradWrapper{r: r, o: o}
	r.initGrad(obj)
	h := newHelper(r.Solution, u)

	stepSize := 1.0
	gLin := 0.0
	n := len(r.X)

	S := make([]mat.Vec, sol.Mem)
	Y := make([]mat.Vec, sol.Mem)
	for i := 0; i < sol.Mem; i++ {
		S[i] = mat.NewVec(n)
		Y[i] = mat.NewVec(n)
	}

	d := mat.NewVec(n)

	xOld := mat.NewVec(n)
	gOld := mat.NewVec(n)
	sNew := mat.NewVec(n)
	yNew := mat.NewVec(n)

	alphas := mat.NewVec(sol.Mem)
	betas := mat.NewVec(sol.Mem)
	rhos := mat.NewVec(sol.Mem)

	lineFunc := NewLineFuncDeriv(obj, r.X, d)
	lsInit := uni.NewSolution()
	lsParams := uni.NewParams()

	for ; r.Status == NotTerminated; h.update(r, p) {
		d.Copy(r.GradX)
		if r.Iter > 0 {
			yNew.Sub(r.GradX, gOld)
			sNew.Sub(r.X, xOld)

			temp := S[len(S)-1]
			copy(S[1:], S)
			S[0] = temp
			S[0].Copy(sNew)

			temp = Y[len(S)-1]
			copy(Y[1:], Y)
			Y[0] = temp
			Y[0].Copy(yNew)

			copy(rhos[1:], rhos)
			rhos[0] = 1 / mat.Dot(sNew, yNew)
			for i := 0; i < sol.Mem; i++ {
				alphas[i] = rhos[i] * mat.Dot(S[i], d)
				d.Axpy(-alphas[i], Y[i])
			}
			for i := sol.Mem - 1; i >= 0; i-- {
				betas[i] = rhos[i] * mat.Dot(Y[i], d)
				d.Axpy(alphas[i]-betas[i], S[i])
			}
		}

		d.Scal(-1)

		gLin = mat.Dot(d, r.GradX)

		lsInit.SetX(stepSize)
		lsInit.SetLB(0, r.ObjX, gLin)
		lsRes := sol.LineSearch.Solve(lineFunc, lsInit, lsParams)
		if lsRes.Status < 0 {
			fmt.Println("Linesearch:", lsRes.Status)
			d.Copy(r.GradX)
			d.Scal(-1)
			lsInit.SetLB(0, r.ObjX, -r.GradX.Nrm2Sq())
			lsRes = sol.LineSearch.Solve(lineFunc, lsInit, lsParams)
			if lsRes.Status < 0 {
				fmt.Println("Linesearch:", lsRes.Status)
				r.Status = Status(lsRes.Status)

				break
			}
		}
		stepSize, r.ObjX = lsRes.X, lsRes.ObjX

		xOld.Copy(r.X)
		gOld.Copy(r.GradX)

		r.X.Axpy(stepSize, d)
		obj.ValGrad(r.X, r.GradX)
	}
	return r
}
コード例 #6
0
ファイル: rosenbrock.go プロジェクト: kortschak/opt
func (sol *Rosenbrock) Solve(o Function, in *Solution, p *Params, u ...Updater) *Result {
	r := NewResult(in)
	obj := ObjWrapper{r: r, o: o}
	r.init(obj)
	h := newHelper(r.Solution, u)

	eps := 1.0
	n := len(r.X)

	d := make([]mat.Vec, n)
	for i := range d {
		d[i] = mat.NewVec(n)
		d[i][i] = 1
	}

	lambda := make([]float64, n)

	lf := make([]*LineFunc, n)
	for i := range lf {
		lf[i] = NewLineFunc(obj, r.X, d[i])
	}

	lsInit := uni.NewSolution()
	lsParams := uni.NewParams()
	lsParams.XTolAbs = p.XTolAbs
	lsParams.XTolRel = p.XTolRel
	lsParams.FunTolAbs = 0
	lsParams.FunTolRel = 0

	for ; r.Status == NotTerminated; h.update(r, p) {

		//Search in all directions
		for i := range d {
			lf[i].Dir = 1
			valNeg := 0.0
			valPos := lf[i].Val(eps)
			if valPos >= r.ObjX {
				lf[i].Dir = -1
				valNeg = lf[i].Val(eps)
				if valNeg >= r.ObjX {
					eps *= 0.5
					lf[i].Dir = 1
					lsInit.SetLB(-eps)
					lsInit.SetUB(eps)
					lsInit.SetX(0)
				} else {
					lsInit.SetUB()
					lsInit.SetLB()
					lsInit.SetX(eps)
				}
			} else {
				lsInit.SetUB()
				lsInit.SetLB()
				lsInit.SetX(eps)
			}
			lsRes := sol.LineSearch.Solve(lf[i], lsInit, lsParams)

			lambda[i] = lf[i].Dir * lsRes.X
			r.X.Axpy(lambda[i], d[i])
			r.ObjX = lsRes.ObjX
		}

		//Find new directions
		for i := range d {
			if math.Abs(lambda[i]) > p.XTolAbs {
				d[i].Scal(lambda[i])
				for j := i + 1; j < n; j++ {
					d[i].Axpy(lambda[j], d[j])
				}
			}
		}

		//Gram-Schmidt, TODO:use QR factorization
		for i := range d {
			d[i].Scal(1 / d[i].Nrm2())
			for j := i + 1; j < n; j++ {
				d[j].Axpy(-mat.Dot(d[i], d[j]), d[i])
			}
		}

	}
	return r
}
コード例 #7
0
ファイル: predcorr.go プロジェクト: kortschak/opt
//Predictor-Corrector Interior Point implementation
func (sol *PredCorr) Solve(prob *Problem, p *Params, u ...Updater) *Result {
	res := NewResult(prob)
	h := newHelper(u)

	A := prob.A

	m, n := A.Dims()

	At := A.TrView()

	var mu, sigma float64

	res.X.AddSc(1)
	res.S.AddSc(1)

	res.Rd = mat.NewVec(n)
	res.Rp = mat.NewVec(m)
	res.Rs = mat.NewVec(n)

	x := res.X
	s := res.S
	y := res.Y

	dx := mat.NewVec(n)
	ds := mat.NewVec(n)
	dy := mat.NewVec(m)

	dxAff := mat.NewVec(n)
	dsAff := mat.NewVec(n)
	dyAff := mat.NewVec(m)

	dxCC := mat.NewVec(n)
	dsCC := mat.NewVec(n)
	dyCC := mat.NewVec(m)

	xdivs := mat.NewVec(n)
	temp := mat.New(m, n)

	lhs := mat.New(m, m)
	rhs := mat.NewVec(m)
	soli := mat.NewVec(m)

	triU := mat.New(m, m)
	triUt := triU.TrView()

	nTemp1 := mat.NewVec(n)
	nTemp2 := mat.NewVec(n)

	alpha := 0.0

	for {
		res.Rd.Sub(prob.C, res.S)
		res.Rd.AddMul(At, res.Y, -1)
		res.Rp.Apply(A, res.X)
		res.Rp.Sub(prob.B, res.Rp)
		res.Rs.Mul(res.X, res.S)
		res.Rs.Neg(res.Rs)

		if h.update(res, p); res.Status != 0 {
			break
		}
		if checkKKT(res, p); res.Status != 0 {
			break
		}
		mu = res.Rs.Asum() / float64(n)

		//determining left hand side
		temp.ScalCols(A, xdivs.Div(x, s))
		lhs.Mul(temp, At)

		//factorization
		lhs.Chol(triU)

		//right hand side
		nTemp1.Add(res.Rd, s)
		nTemp1.Mul(nTemp1, xdivs)
		rhs.Apply(A, nTemp1)
		rhs.Add(rhs, res.Rp)

		//solving for dyAff
		soli.Trsv(triUt, rhs)
		dyAff.Trsv(triU, soli)

		//calculating other steps (dxAff, dsAff)
		nTemp1.Apply(At, dyAff)
		dxAff.Sub(nTemp1, res.Rd)
		dxAff.Sub(dxAff, s)
		dxAff.Mul(dxAff, xdivs)

		dsAff.Div(dxAff, xdivs)
		dsAff.Add(dsAff, s)
		dsAff.Neg(dsAff)

		//determining step size
		alpha = 1.0
		for i := range dxAff {
			if dxAff[i] < 0 {
				alph := -x[i] / dxAff[i]
				if alph < alpha {
					alpha = alph
				}
			}
		}
		for i := range dsAff {
			if dsAff[i] < 0 {
				alph := -s[i] / dsAff[i]
				if alph < alpha {
					alpha = alph
				}
			}
		}
		alpha *= 0.99995

		//calculating duality gap measure for affine case
		nTemp1.Copy(x)
		nTemp1.Axpy(alpha, dxAff)
		nTemp2.Copy(s)
		nTemp2.Axpy(alpha, dsAff)
		mu_aff := mat.Dot(nTemp1, nTemp2) / float64(n)

		//centering parameter
		sigma = math.Pow(mu_aff/mu, 3)

		//right hand side for predictor corrector step
		res.Rs.Mul(dxAff, dsAff)
		res.Rs.Neg(res.Rs)
		res.Rs.AddSc(sigma * mu_aff)

		nTemp1.Div(res.Rs, s)
		nTemp1.Neg(nTemp1)

		rhs.Apply(A, nTemp1)

		//solving for dyCC
		soli.Trsv(triUt, rhs)
		dyCC.Trsv(triU, soli)

		//calculating other steps (dxAff, dsAff)
		nTemp1.Apply(At, dyCC)
		dxCC.Mul(nTemp1, x)
		dxCC.Add(res.Rs, dxCC)
		dxCC.Div(dxCC, s)

		dsCC.Mul(dxCC, s)
		dsCC.Sub(res.Rs, dsCC)
		dsCC.Div(dsCC, x)

		dx.Add(dxAff, dxCC)
		dy.Add(dyAff, dyCC)
		ds.Add(dsAff, dsCC)

		alpha = 1
		for i := range dx {
			if dx[i] < 0 {
				alph := -x[i] / dx[i]
				if alph < alpha {
					alpha = alph
				}
			}
		}
		for i := range ds {
			if ds[i] < 0 {
				alph := -s[i] / ds[i]
				if alph < alpha {
					alpha = alph
				}
			}
		}
		alpha *= 0.99995

		x.Axpy(alpha, dx)
		y.Axpy(alpha, dy)
		s.Axpy(alpha, ds)
	}
	return res
}