示例#1
0
文件: auglag.py 项目: lambe/nlpy
	def __init__(self, nlp, **kwargs):

		self.nlp = nlp

		# Temporary error message as the class does not yet support 
		# range constraints
		if nlp.nrangeC > 0:
			msg = 'Range inequality constraints are not supported.'
			raise ValueError, msg

		# Analyze NLP to add slack variables to the formulation
		# Ordering of the slacks in 'x' is assumed to be the order shown here
		self.nx = nlp.n
		self.nsLL = nlp.nlowerC
		self.nsUU = nlp.nupperC
		# self.nsLR = nlp.nrangeC
		# self.nsUR = nlp.nrangeC
		self.ns = nlp.nlowerC + nlp.nupperC + 2*nlp.nrangeC
		self.n = self.nx + self.ns
		self.m = nlp.m 

		# Copy initial data from NLP given new problem definition
		# Initialize slack variables to zero
		self.x0 = numpy.zeros(self.n,'d')
		self.x0[:self.nx] = nlp.x0

		self.pi0 = nlp.pi0.copy()

		# Create Hessian approximation by default
		self.approxHess = kwargs.get('approxHess',True)
		if self.approxHess:
			# LBFGS is currently the only option
			self.Hessapp = LBFGS(self.n)

		# Extend bound arrays to include slack variables
		self.Lvar = numpy.zeros(self.n,'d')
		self.Lvar[:self.nx] = nlp.Lvar

		self.Uvar = nlp.Infinity*numpy.ones(self.n,'d')
		self.Uvar[:self.nx] = nlp.Uvar

		# Bring in bound arrays for constraints and lists of constraint types
		self.Lcon = nlp.Lcon
		self.Ucon = nlp.Ucon
		self.lowerC = nlp.lowerC
		self.upperC = nlp.upperC
		# self.rangeC = nlp.rangeC
		self.equalC = nlp.equalC
示例#2
0
文件: ldfp.py 项目: lambe/nlpy
 def store(self, new_s, new_y):
     # Simply swap s and y.
     LBFGS.store(self, new_y, new_s)
示例#3
0
文件: auglag.py 项目: lambe/nlpy
class AugmentedLagrangian(NLPModel):
	'''
	This class is a reformulation of an NLP, used to compute the 
	augmented Lagrangian function, gradient, and approximate Hessian in a 
	method-of-multipliers optimization routine. Slack variables are introduced 
	for inequality constraints and a function that computes the gradient 
	projected on to variable bounds is included.

	Matrix-free NLP models are accomodated with the help of a Hessian 
	approximation which can be updated and restarted via calls to methods in 
	this class.
	'''

	def __init__(self, nlp, **kwargs):

		self.nlp = nlp

		# Temporary error message as the class does not yet support 
		# range constraints
		if nlp.nrangeC > 0:
			msg = 'Range inequality constraints are not supported.'
			raise ValueError, msg

		# Analyze NLP to add slack variables to the formulation
		# Ordering of the slacks in 'x' is assumed to be the order shown here
		self.nx = nlp.n
		self.nsLL = nlp.nlowerC
		self.nsUU = nlp.nupperC
		# self.nsLR = nlp.nrangeC
		# self.nsUR = nlp.nrangeC
		self.ns = nlp.nlowerC + nlp.nupperC + 2*nlp.nrangeC
		self.n = self.nx + self.ns
		self.m = nlp.m 

		# Copy initial data from NLP given new problem definition
		# Initialize slack variables to zero
		self.x0 = numpy.zeros(self.n,'d')
		self.x0[:self.nx] = nlp.x0

		self.pi0 = nlp.pi0.copy()

		# Create Hessian approximation by default
		self.approxHess = kwargs.get('approxHess',True)
		if self.approxHess:
			# LBFGS is currently the only option
			self.Hessapp = LBFGS(self.n)

		# Extend bound arrays to include slack variables
		self.Lvar = numpy.zeros(self.n,'d')
		self.Lvar[:self.nx] = nlp.Lvar

		self.Uvar = nlp.Infinity*numpy.ones(self.n,'d')
		self.Uvar[:self.nx] = nlp.Uvar

		# Bring in bound arrays for constraints and lists of constraint types
		self.Lcon = nlp.Lcon
		self.Ucon = nlp.Ucon
		self.lowerC = nlp.lowerC
		self.upperC = nlp.upperC
		# self.rangeC = nlp.rangeC
		self.equalC = nlp.equalC

	# end def 


	# Evaluate infeasibility measure (used in both objective and gradient)
	def get_infeas(self, x, **kwargs):
		nx = self.nx
		nsLL_ind = nx + self.nsLL
		nsUU_ind = nsLL_ind + self.nsUU
		# nsLR_ind = nsUU_ind + self.nsLR
		# nsUR_ind = nsLR_ind + self.nsUR

		convals = self.nlp.cons(x[:nx])
		convals[self.lowerC] -= x[nx:nsLL_ind] + self.Lcon[self.lowerC]
		convals[self.upperC] += x[nsLL_ind:nsUU_ind] - self.Ucon[self.upperC]
		convals[self.equalC] -= self.Lcon[self.equalC]
		# convals[self.rangeC] += x[nsLR_ind:nsUR_ind] - x[nsUU_ind:nsLR_ind]
		return convals
	# end def


	# Evaluate augmented Lagrangian function
	def obj(self, x, pi, rho, **kwargs):
		nx = self.nx
		nsLL_ind = nx + self.nsLL
		nsUU_ind = nsLL_ind + self.nsUU
		# nsLR_ind = nsUU_ind + self.nsLR
		# nsUR_ind = nsLR_ind + self.nsUR

		alfunc = self.nlp.obj(x[:nx])

		convals = self.get_infeas(x)

		alfunc += numpy.dot(pi,convals)
		alfunc += 0.5*rho*numpy.sum(convals**2)

		return alfunc
	# end def


	# Evaluate augmented Lagrangian gradient
	def grad(self, x, pi, rho, **kwargs):
		nlp = self.nlp 
		nx = self.nx
		nsLL_ind = nx + self.nsLL
		nsUU_ind = nsLL_ind + self.nsUU
		# nsLR_ind = nsUU_ind + self.nsLR
		# nsUR_ind = nsLR_ind + self.nsUR

		algrad = numpy.zeros(self.n,'d')
		algrad[:nx] = nlp.grad(x[:nx])

		convals = self.get_infeas(x)

		vec = pi + rho*convals
		if isinstance(nlp, MFModel):
			algrad[:nx] += nlp.jtprod(x[:nx],vec)
		else:
			algrad[:nx] += rho*numpy.dot(nlp.jac(x[:nx]).transpose(),vec)
		# end if

		algrad[nx:nsLL_ind] = -pi[nlp.lowerC] - rho*convals[nlp.lowerC]
		algrad[nsLL_ind:nsUU_ind] = pi[nlp.upperC] + rho*convals[nlp.upperC]
		# **Range constraint slacks here**

		return algrad
	# end def


	def project_gradient(self, x, g, **kwargs):
		'''
		Project the provided gradient on to the bound-constrained space and 
		return the result. This is a helper function for determining 
		optimality conditions of the original NLP.
		'''

		p = x - g 
		med = numpy.maximum(numpy.minimum(p,self.Uvar),self.Lvar)
		q = x - med 

		return q


	def hprod(self, x, pi, rho, v, **kwargs):
		'''
		Compute the Hessian-vector produce of the Hessian of the augmented 
		Lagrangian with arbitrary vector v. Both exact and approximate 
		Hessians are supported.
		'''

		nlp = self.nlp
		nx = self.nx
		w = numpy.zeros(self.n,'d')

		# Non-slack variables
		if self.approxHess:
			# Approximate Hessian
			w = self.Hessapp.matvec(v)
		else:
			# Exact Hessian
			# Note: the code in this block has yet to be properly tested
			convals = self.get_infeas(x)
			w[:nx] = nlp.hprod(x[:nx],pi,v[:nx],**kwargs)
			for i in range(self.m):
				w[:nx] += rho*convals[i]*nlp.hiprod(i,x[:nx],v[:nx])
			# end for 
			if isinstance(nlp, MFModel):
				w[:nx] += rho*nlp.jtprod(x[:nx],nlp.jprod(x[:nx],v[:nx]))
				w[:nx] += rho*nlp.jprod(x[:nx],v[:nx])
				w[nx:] += rho*nlp.jtprod(x[:nx],v[nx:])
			else:
				J = nlp.jac
				w[:nx] += rho*numpy.dot(J.transpose(),numpy.dot(J,v[:nx]))
				w[:nx] += rho*numpy.dot(J,v[:nx])
				w[nx:] += rho*numpy.dot(J.transpose(),v[nx:])
			# end if
			# Slack variables
			w[nx:] += rho*v[nx:]
		# end if 

		return w 


	def hupdate(self, new_s=None, new_y=None):
		if self.approxHess and new_s is not None and new_y is not None:
			self.Hessapp.store(new_s,new_y)
		return

	def hrestart(self):
		if self.approxHess:
			self.Hessapp.restart()
		return
示例#4
0
文件: ldfp.py 项目: lambe/nlpy
 def __init__(self, n, npairs=5, **kwargs):
     LBFGS.__init__(self, n, npairs, **kwargs)