def amsg2p(f, df, x0, epsilon, f_opt, gamma, callback = lambda x, f: False): # returns optim point and iteration number f0 = f(x0) if f0 - f_opt <= epsilon: return x0, 0 x, n = x0.copy(), x0.size df0 = df(x0) ndf = norm(df0) h, dzeta, p, B = gamma * (f0 - f_opt) / ndf, df0 / ndf, zeros(n), diag(ones(n, 'float64')) # TODO: add possibility to create B of type float128 k = 0 while True: k += 1 x -= h * dot(B, dzeta) F = f(x) r = callback(x, F) if r not in (0, False, None): break # user-demanded stop if F - f_opt <= epsilon: break DF = df(x) DF_dilated = dot(B.T, DF) nDF_dilated = norm(DF_dilated) dzeta_new, h = DF_dilated / nDF_dilated, gamma * (F-f_opt) / nDF_dilated lambda1, lambda2 = -dot(p, dzeta_new), -dot(dzeta, dzeta_new) c1, c2 = lambda1>0, lambda2>0 p = (lambda1 * p + lambda2 * dzeta)/sqrt(lambda1**2+lambda2**2) if c1 and c2 else dzeta if c2 and not c1 else zeros(n) if not c1 and not c2 else p mu = dot(p, dzeta_new) if -1 < mu < 0: S = sqrt(1-mu**2) nu = (1/S-1) * dzeta_new - (mu/S) * p B += dot(dot(B, nu.reshape(n, 1)), dzeta_new.reshape(1, n)) h /= S p = (p - mu * dzeta_new) / S else: p = zeros(n) dzeta = dzeta_new return x, k
def getPrimevalDilationMatrixWRTlinEqConstraints(self, p): n, Aeq, beq = p.n, p.Aeq, p.beq nLinEq = len(p.beq) ind_fixed = where(p.lb==p.ub)[0] arr=ones(n, dtype=self.T) arr[ind_fixed] = 0 b = diag(arr) if hasattr(Aeq, 'tocsc'):Aeq = Aeq.tocsc() for i in range(nLinEq): vec = Aeq[i] #raise 0 if hasattr(vec, 'toarray'): vec = vec.toarray().flatten() g = economyMult(b.T, vec) if not any(g): continue #ind_nnz = nonzero(g)[0] ng = norm(g) g = (g / ng).reshape(-1,1) vec1 = p.matmult(b, g)# TODO: remove economyMult, use dot? vec2 = -g.T b += p.matmult(vec1, vec2) # if len(ind_nnz) > 0.7 * g.size: # b += p.matmult(vec1, vec2) # else: # ind_nnz1 = nonzero(vec1)[0] # ind_nnz2 = nonzero(vec2)[1] # r = dot(vec1[ind_nnz1, :], vec2[:, ind_nnz2]) # if p.debug: # assert abs(norm(p.matmult(vec1, vec2).flatten()) - norm(r.flatten())) < 1e-5 # b[ix_(ind_nnz1, ind_nnz2)] += r return b
def amsg2p(f, df, x0, epsilon, f_opt, gamma, callback=lambda x, f: False): # returns optim point and iteration number f0 = f(x0) if f0 - f_opt <= epsilon: return x0, 0 x, n = x0.copy(), x0.size df0 = df(x0) ndf = norm(df0) h, dzeta, p, B = gamma * (f0 - f_opt) / ndf, df0 / ndf, zeros(n), diag( ones(n, 'float64')) # TODO: add possibility to create B of type float128 k = 0 while True: k += 1 x -= h * dot(B, dzeta) F = f(x) r = callback(x, F) if r not in (0, False, None): break # user-demanded stop if F - f_opt <= epsilon: break DF = df(x) DF_dilated = dot(B.T, DF) nDF_dilated = norm(DF_dilated) dzeta_new, h = DF_dilated / nDF_dilated, gamma * (F - f_opt) / nDF_dilated lambda1, lambda2 = -dot(p, dzeta_new), -dot(dzeta, dzeta_new) c1, c2 = lambda1 > 0, lambda2 > 0 p = (lambda1 * p + lambda2 * dzeta) / sqrt( lambda1**2 + lambda2**2) if c1 and c2 else dzeta if c2 and not c1 else zeros( n) if not c1 and not c2 else p mu = dot(p, dzeta_new) if -1 < mu < 0: S = sqrt(1 - mu**2) nu = (1 / S - 1) * dzeta_new - (mu / S) * p B += dot(dot(B, nu.reshape(n, 1)), dzeta_new.reshape(1, n)) h /= S p = (p - mu * dzeta_new) / S else: p = zeros(n) dzeta = dzeta_new return x, k
def getAltitudeDirection(p, pointTop, point2, point3): b = point2 - pointTop c = point3 - pointTop alpha = dot(c, c-b) / norm(c-b)**2 h = alpha * b + (1-alpha) * c abh = arccos(dot(h, b)/norm(h) /norm(b)) ach = arccos(dot(h, c)/norm(h) /norm(c)) abc = arccos(dot(b, c)/norm(b) /norm(c)) #ahbc = arccos(dot(h, b-c)/norm(h) /norm(b-c)) isInsideTriangle = abh+ach-abc<=1e-8 return h, isInsideTriangle
def iterfcn(*args, **kwargs): p2.primalIterFcn(*args, **kwargs) p.xk = p2.xk.copy() Fk = norm(p.f(p.xk), inf) p.rk = p.getMaxResidual(p.xk) #TODO: ADD p.rk if p.nEvals['f'] > p.maxFunEvals: p.istop = p2.istop = IS_MAX_FUN_EVALS_REACHED elif p2.istop!=0: if Fk < FTOL and p.rk < p.contol: p.istop = 15 msg_contol = '' if p.isUC else 'and contol ' p.msg = 'solution with required ftol ' + msg_contol+ 'has been reached' else: p.istop = p2.istop p.iterfcn() return p.istop
def __solver__(self, p): alp, h0, nh, q1, q2 = self.alp, self.h0, self.nh, self.q1, self.q2 if isPyPy: if p.nc != 0 or p.nh != 0: p.warn("in PyPy ralg may work incorrectly with nonlinear constraints yet") if p.nbeq != 0 or any(p.lb==p.ub): p.err('in PyPy ralg cannot handle linear equality constraints yet') if type(q1) == str: if p.probType== 'NLP' and p.isUC: q1 = 0.9 else: q1 = 1.0 T = self.T # alternatively instead of alp=self.alp etc you can use directly self.alp etc n = p.n x0 = p.x0 if p.nbeq == 0 or any(abs(p._get_AeqX_eq_Beq_residuals(x0))>p.contol): # TODO: add "or Aeqconstraints(x0) out of contol" x0[x0<p.lb] = p.lb[x0<p.lb] x0[x0>p.ub] = p.ub[x0>p.ub] ind_box_eq = where(p.lb==p.ub)[0] nEQ = ind_box_eq.size if nEQ != 0: initLenBeq = p.nbeq Aeq, beq, nbeq = copy(p.Aeq), copy(p.beq), p.nbeq p.Aeq = zeros([Len(p.beq) + nEQ, p.n]) p.beq = zeros(Len(p.beq) + nEQ) p.beq[:Len(beq)] = beq p.Aeq[:Len(beq)] = Aeq for i in range(len(ind_box_eq)): p.Aeq[initLenBeq+i, ind_box_eq[i]] = 1 p.beq[initLenBeq+i] = p.lb[ind_box_eq[i]] # = p.ub[indEQ[i]], because they are the same p.nbeq += nEQ if not self.newLinEq or p.nbeq == 0: needProjection = False B0 = eye(n, dtype=T) restoreProb = lambda *args: 0 Aeq_r, beq_r, nbeq_r = None, None, 0 else: needProjection = True B0 = self.getPrimevalDilationMatrixWRTlinEqConstraints(p) #Aeq, beq, nbeq = p.Aeq, p.beq, p.nbeq if any(abs(p._get_AeqX_eq_Beq_residuals(x0))>p.contol/16.0): #p.debugmsg('old point Aeq residual:'+str(norm(dot(Aeq, x0)-beq))) try: x0 = self.linEqProjection(x0, p.Aeq, p.beq) except LinAlgError: s = 'Failed to obtain projection of start point to linear equality constraints subspace, probably the system is infeasible' p.istop, p.msg = -25, s return #p.debugmsg('new point Aeq residual:'+str(norm(dot(Aeq, x0)-beq))) if nEQ == 0: Aeq_r, beq_r, nbeq_r = p.Aeq, p.beq, p.nbeq else: Aeq_r, beq_r, nbeq_r = Aeq, beq, nbeq p.Aeq, p.beq, p.nbeq = None, None, 0 # TODO: return prob with unmodified Aeq, beq def restoreProb(): p.Aeq, p.beq, p.nbeq = Aeq_r, beq_r, nbeq_r #if nEQ != 0: restore lb, ub b = B0.copy() if self.B is None else self.B # B_f = diag(ones(n)) # B_constr = diag(ones(n)) hs = asarray(h0, T) if self.innerState is not None: hs = self.innerState['hs'] b = self.innerState['B'] ls_arr = [] w = asarray(1.0/alp-1.0, T) """ Shor r-alg engine """ bestPoint = p.point(array(copy(x0).tolist(), T)) # tolist() for PyPy compatibility prevIter_best_ls_point = bestPoint prevIter_PointForDilation = bestPoint g = bestPoint._getDirection(self.approach) prevDirectionForDilation = g moveDirection = g if not any(g) and all(isfinite(g)): # TODO: create ENUMs p.iterfcn(bestPoint) restoreProb() p.istop = 14 if bestPoint.isFeas(False) else -14 p.msg = 'move direction has all-zero coords' return HS = [] LS = [] SwitchEncountered = False selfNeedRej = False doScale = False #directionVectorsList = [] # #pass-by-ref! not copy! # if p.isFeas(p.x0): b = B_f # else: b = B_constr # if p.debug and hasattr(p, 'x_opt'): # import scipy # exactDirection = x0-p.x_opt # asdf_0 = exactDirection * (0.2+scipy.rand(n)) # #asdf = asdf_0.copy() fTol = p.fTol if p.fTol is not None else 15*p.ftol # CHANGES if self.penalties: oldVal = p.f(p.x0) newVal = inf x = p.x0 #H, DH = p.h, p.dh if p.nh != 0: #S = 1.0 _Aeq = p.dh(x) _beq = -p.h(x) df = p.df(x) if n>=150 and not scipyInstalled: p.pWarn(scipyAbsentMsg) if n>100 and scipyInstalled: from scipy.sparse import eye as Eye # to prevent numpy.eye overwrite HH = Eye(n, n) else: HH = eye(n) qp = openopt.QP(H=HH, f=df, Aeq=_Aeq, beq=_beq) # print ('len(_beq): %d' % len(_beq)) # assert len(_beq) != 0 QPsolver = openopt.oosolver('cvxopt_qp', iprint=-1) if not QPsolver.isInstalled: #p.pWarn('to use ') S = None else: r = qp.solve(QPsolver) #S = 2.0*abs(r.duals).sum() if r.istop > 0 else 0 S = 10.0*sum(abs(r.duals)) if r.istop > 0 else None while any(p.h(x)) > p.contol: if S is not None: p2 = getattr(openopt, p.probType)(p.f, x) p.inspire(p2) p2.x0 = x p2.h = p2.dh = None p2.userProvided.h = p2.userProvided.dh = False p2.nh = 0 p2.f = lambda *args, **kwargs: p.f(*args, **kwargs) + sum(abs(S * p.h(*args, **kwargs))) p2.df = lambda *args, **kwargs: p.df(*args, **kwargs) + dot(S * sign(p.h(*args, **kwargs)), p.dh(*args, **kwargs)) #p2.iterfcn = p.iterfcn # def df2(*args, **kwargs): # r1 = p.df(*args, **kwargs) # r2 = S * dot(p.dh(*args, **kwargs).reshape(-1, 1), sign(p.h(*args, **kwargs))).flatten() # #raise 0 # return r1+r2 # #p2.df = lambda *args, **kwargs: p.df(*args, **kwargs) + S * dot(p.dh(x).reshape(-1, 1), sign(p.h(*args, **kwargs))).flatten() # p2.df = df2 # #raise 0 r2 = p2.solve(p.solver, iprint=10) if r2.stopcase >= 0: x = r2.xf p.solver.innerState = r2.extras['innerState'] oldVal, newVal = newVal, r2.ff else: if r2.istop == IS_LINE_SEARCH_FAILED: # TODO: custom S as raising penalties pass if p.isFeas(p2.xk): p.xf = p.xk = p2.xk p.istop, p.msg = p2.istop, p2.msg return else: S *= 50 #print('max residual:%0.2e'% r2.rf) else: # failed to solve QP break #print 'b:', b, '\nhs:', hs # CHANGES END """ Ralg main cycle """ for itn in range(p.maxIter+10): doDilation = True lastPointOfSameType = None # to prevent possible bugs alp_addition = 0.0 iterStartPoint = prevIter_best_ls_point x = iterStartPoint.x.copy() g_tmp = economyMult(b.T, moveDirection) if any(g_tmp): g_tmp /= p.norm(g_tmp) g1 = p.matmult(b, g_tmp) # norm_moveDirection = p.norm(g1) # if doScale: # g1 *= (norm_moveDirection_prev/norm_moveDirection) ** 0.5 # norm_moveDirection_prev = norm_moveDirection # if p.debug and hasattr(p, 'x_opt'): # cos_phi_0 = p.matmult(moveDirection, prevIter_best_ls_point.x - p.x_opt)/p.norm(moveDirection)/p.norm(prevIter_best_ls_point.x - p.x_opt) # cos_phi_1 = p.matmult(g1, prevIter_best_ls_point.x - p.x_opt)/p.norm(g1)/p.norm(prevIter_best_ls_point.x - p.x_opt) # print('beforeDilation: %f afterDilation: %f' % (cos_phi_0, cos_phi_1) ) # asdf = asdf_0.copy() # g_tmp = economyMult(b.T, asdf) # # #g_tmp = p.matmult(b.T, asdf) # # if any(g_tmp): g_tmp /= p.norm(g_tmp) # asdf = p.matmult(b, g_tmp) # cos_phi = dot(asdf, exactDirection) / p.norm(asdf) / p.norm(exactDirection) # p.debugmsg('cos_phi:%f' % cos_phi) # assert cos_phi >0 """ Forward line search """ hs_cumsum = 0 hs_start = hs for ls in range(p.maxLineSearch): hs_mult = 1.0 if ls > 20: hs_mult = 2.0 elif ls > 10: hs_mult = 1.5 elif ls > 2: hs_mult = 1.05 hs *= hs_mult x -= hs * g1 hs_cumsum += hs newPoint = p.point(x) if ls == 0 else iterStartPoint.linePoint(hs_cumsum/(hs_cumsum-hs), oldPoint) # TODO: take ls into account? if not p.isUC: if newPoint.isFeas(True) == iterStartPoint.isFeas(True): lastPointOfSameType = newPoint if self.show_nnan: p.info('ls: %d nnan: %d' % (ls, newPoint.__nnan__())) if ls == 0: oldPoint = prevIter_best_ls_point#prevIterPoint oldoldPoint = oldPoint #if not self.checkTurnByGradient: if newPoint.betterThan(oldPoint, altLinInEq=True): if newPoint.betterThan(bestPoint, altLinInEq=False): bestPoint = newPoint oldoldPoint = oldPoint oldPoint, newPoint = newPoint, None else: if not itn % 4: for fn in ['_lin_ineq', '_lin_eq']: if hasattr(newPoint, fn): delattr(newPoint, fn) break hs /= hs_mult if ls == p.maxLineSearch-1: p.istop, p.msg = IS_LINE_SEARCH_FAILED, 'maxLineSearch (' + str(p.maxLineSearch) + ') has been exceeded, the problem seems to be unbounded' restoreProb() return #iterPoint = newPoint PointForDilation = newPoint #best_ls_point = newPoint if ls == 0 else oldPoint #if p.debug and ls != 0: assert not oldPoint.betterThan(best_ls_point) """ Backward line search """ mdx = max((150, 1.5*p.n))*p.xtol if itn == 0: mdx = max((hs / 128.0, 128*p.xtol )) # TODO: set it after B rej as well ls_backward = 0 maxLS = 3 if ls == 0 else 1 # if ls <=3 or ls > 20: if self.doBackwardSearch: if self.new_bs: best_ls_point, PointForDilation, ls_backward = \ getBestPointAfterTurn(oldoldPoint, newPoint, maxLS = maxLS, maxDeltaF = 150*p.ftol, \ maxDeltaX = mdx, altLinInEq = True, new_bs = True) if PointForDilation.isFeas(True) == iterStartPoint.isFeas(True): lastPointOfSameType = PointForDilation # elif best_ls_point.isFeas(altLinInEq=True) == iterStartPoint.isFeas(altLinInEq=True): # lastPointOfSameType = best_ls_point else: best_ls_point, ls_backward = \ getBestPointAfterTurn(oldoldPoint, newPoint, maxLS = maxLS, altLinInEq = True, new_bs = False) PointForDilation = best_ls_point # TODO: extract last point from backward search, that one is better than iterPoint if best_ls_point.betterThan(bestPoint): bestPoint = best_ls_point #p.debugmsg('ls_backward:%d' % ls_backward) if ls == 0 and ls_backward == -maxLS: #pass alp_addition += 0.25 #hs *= 0.9 if ls_backward <= -1 and itn != 0: # TODO: mb use -1 or 0 instead? pass #alp_addition -= 0.25*ls_backward # ls_backward less than zero #hs *= 2 ** min((ls_backward+1, 0)) else: pass #hs *= 0.95 best_ls_point = PointForDilation # elseware lots of difficulties """ Updating hs """ step_x = p.norm(PointForDilation.x - prevIter_PointForDilation.x) step_f = abs(PointForDilation.f() - prevIter_PointForDilation.f()) HS.append(hs_start) assert ls >= 0 LS.append(ls) if itn > 3: mean_ls = (3*LS[-1] + 2*LS[-2]+LS[-3]) / 6.0 j0 = 3.3 if mean_ls > j0: hs = (mean_ls - j0 + 1)**0.5 * hs_start else: #hs = (ls/j0) ** 0.5 * hs_start hs = hs_start if ls == 0 and ls_backward == -maxLS: shift_x = step_x / p.xtol RD = log10(shift_x+1e-100) if PointForDilation.isFeas(True) or prevIter_PointForDilation.isFeas(True): RD = min((RD, asscalar(asarray(log10(step_f / p.ftol + 1e-100))))) if RD > 1.0: mp = (0.5, (ls/j0) ** 0.5, 1 - 0.2*RD) hs *= max(mp) #from numpy import argmax #print argmax(mp), mp """ Handling iterPoints """ best_ls_point = PointForDilation #if not SwitchEncountered and p.nh != 0 and PointForDilation.isFeas(altLinInEq=False) != prevIter_PointForDilation.isFeas(altLinInEq=False): #SwitchEncountered = True #selfNeedRej = True involve_lastPointOfSameType = False if lastPointOfSameType is not None and PointForDilation.isFeas(True) != prevIter_PointForDilation.isFeas(True): # TODO: add middle point for the case ls = 0 assert self.dilationType == 'plain difference' #directionForDilation = lastPointOfSameType._getDirection(self.approach) PointForDilation = lastPointOfSameType involve_lastPointOfSameType = True #directionForDilation = newPoint.__getDirection__(self.approach) # used for dilation direction obtaining # if not self.new_bs or ls != 0: # moveDirection = iterPoint.__getDirection__(self.approach) # else: # moveDirection = best_ls_point.__getDirection__(self.approach) #directionForDilation = pointForDilation.__getDirection__(self.approach) # cos_phi = -p.matmult(moveDirection, prevIterPoint.__getDirection__(self.approach)) # assert cos_phi.size == 1 # if cos_phi> 0: # g2 = moveDirection#pointForDilation.__getDirection__(self.approach) # else: # g2 = pointForDilation.__getDirection__(self.approach) if itn == 0: p.debugmsg('hs: ' + str(hs)) p.debugmsg('ls: ' + str(ls)) if self.showLS: p.info('ls: ' + str(ls)) if self.show_hs: p.info('hs: ' + str(hs)) if self.show_nnan: p.info('nnan: ' + str(best_ls_point.__nnan__())) if self.showRes: r, fname, ind = best_ls_point.mr(True) p.info(fname+str(ind)) """ Set dilation direction """ #if sum(p.dotmult(g, g2))>0: #p.debugmsg('ralg warning: slope angle less than pi/2. Mb dilation for the iter will be omitted.') #doDilation = False # CHANGES # if lastPointOfSameType is None: # if currIterPointIsFeasible and not prevIterPointIsFeasible: # alp_addition += 0.1 # elif prevIterPointIsFeasible and not currIterPointIsFeasible: # alp_addition -= 0.0 # CHANGES END # r_p, ind_p, fname_p = prevIter_best_ls_point.mr(1) # r_, ind_, fname_ = PointForDilation.mr(1) #else: #print itn,'>>>>>>>>>', currIterPointIsFeasible """ Excluding derivatives switched to/from NaN """ if self.skipPrevIterNaNsInDilation: c_prev, c_current = prevIter_PointForDilation.c(), PointForDilation.c() h_prev, h_current = prevIter_PointForDilation.h(), PointForDilation.h() """ Handling switch to NaN """ NaN_derivatives_excluded = False if self.skipPrevIterNaNsInDilation: assert self.approach == 'all active' if not prevIter_PointForDilation.isFeas(True): """ processing NaNs in nonlin inequality constraints """ ind_switch_ineq_to_nan = where(logical_and(isnan(c_current), c_prev>0))[0] if len(ind_switch_ineq_to_nan) != 0: NaN_derivatives_excluded = True tmp = prevIter_PointForDilation.dc(ind_switch_ineq_to_nan) if hasattr(tmp, 'toarray'): tmp = tmp.A if len(ind_switch_ineq_to_nan)>1: tmp *= (c_prev[ind_switch_ineq_to_nan] /sqrt((tmp**2).sum(1))).reshape(-1, 1) else: tmp *= c_prev[ind_switch_ineq_to_nan] / norm(tmp) if tmp.ndim>1: tmp = tmp.sum(0) if not isinstance(tmp, ndarray) or isinstance(tmp, matrix): tmp = tmp.A.flatten() # dense or sparse matrix #print '1: excluded:', norm(tmp), norm(prevDirectionForDilation) prevDirectionForDilation -= tmp #print '1: result=', norm(prevDirectionForDilation) """ processing NaNs in nonlin equality constraints """ ind_switch_eq_to_nan = where(logical_and(isnan(h_current), h_prev>0))[0] if len(ind_switch_eq_to_nan) != 0: NaN_derivatives_excluded = True tmp = prevIter_PointForDilation.dh(ind_switch_eq_to_nan) if tmp.ndim>1: tmp = tmp.sum(0) if not isinstance(tmp, ndarray) or isinstance(tmp, matrix): tmp = tmp.A.flatten() # dense or sparse matrix prevDirectionForDilation -= tmp ind_switch_eq_to_nan = where(logical_and(isnan(h_current), h_prev<0))[0] if len(ind_switch_eq_to_nan) != 0: NaN_derivatives_excluded = True tmp = prevIter_PointForDilation.dh(ind_switch_eq_to_nan) if tmp.ndim>1: tmp = tmp.sum(0) if not isinstance(tmp, ndarray) or isinstance(tmp, matrix): tmp = tmp.A.flatten() # dense or sparse matrix prevDirectionForDilation += tmp directionForDilation = PointForDilation._getDirection(self.approach) """ Handling switch from NaN """ if self.skipPrevIterNaNsInDilation: if not PointForDilation.isFeas(True): """ processing NaNs in nonlin inequality constraints """ ind_switch_ineq_from_nan = where(logical_and(isnan(c_prev), c_current>0))[0] if len(ind_switch_ineq_from_nan) != 0: NaN_derivatives_excluded = True tmp = PointForDilation.dc(ind_switch_ineq_from_nan) if hasattr(tmp, 'toarray'): tmp = tmp.A if len(ind_switch_ineq_from_nan)>1: tmp *= (c_current[ind_switch_ineq_from_nan] /sqrt((tmp**2).sum(1))).reshape(-1, 1) else: tmp *= c_current[ind_switch_ineq_from_nan] / norm(tmp) if tmp.ndim>1: tmp = tmp.sum(0) if not isinstance(tmp, ndarray) or isinstance(tmp, matrix): tmp = tmp.A.flatten() # dense or sparse matrix #print '2: excluded:', norm(tmp), norm(directionForDilation) directionForDilation -= tmp #print '2: result=', norm(directionForDilation) """ processing NaNs in nonlin equality constraints """ ind_switch_eq_from_nan = where(logical_and(isnan(h_prev), h_current>0))[0] if len(ind_switch_eq_from_nan) != 0: NaN_derivatives_excluded = True tmp = PointForDilation.dh(ind_switch_eq_from_nan) if tmp.ndim>1: tmp = tmp.sum(0) if not isinstance(tmp, ndarray) or isinstance(tmp, matrix): tmp = tmp.A.flatten() # dense or sparse matrix directionForDilation -= tmp ind_switch_eq_from_nan = where(logical_and(isnan(h_prev), h_current<0))[0] if len(ind_switch_eq_from_nan) != 0: NaN_derivatives_excluded = True tmp = PointForDilation.dh(ind_switch_eq_from_nan) if tmp.ndim>1: tmp = tmp.sum(0) if not isinstance(tmp, ndarray) or isinstance(tmp, matrix): tmp = tmp.A.flatten() # dense or sparse matrix directionForDilation += tmp # # CHANGES # gn = g2/norm(g2) # if len(directionVectorsList) == 0 or n < 3: pass # else: # if len(directionVectorsList) == 1 or abs(dot(directionVectorsList[-1], directionVectorsList[-2]))>0.999: # projectionComponentLenght = abs(dot(directionVectorsList[-1], gn)) # restLength = sqrt(1 - min((1, projectionComponentLenght))**2) # else: # e1 = directionVectorsList[-1] # e2 = directionVectorsList[-2] - dot(directionVectorsList[-1], directionVectorsList[-2]) * directionVectorsList[-1] # e2 /= norm(e2) # # proj1, proj2 = dot(e1, gn), dot(e2, gn) # rest = gn - proj1 * e1 - proj2 * e2 # restLength = norm(rest) # if restLength > 1+1e-5: p.pWarn('possible error in ralg solver: incorrect restLength, exceeds 1.0') # # # TODO: make it parameters of ralg # commonCoeff, alp_add_coeff = 0.5, 1.0 # # if restLength < commonCoeff * (n - 2.0) / n: # #pass # alpAddition = 0.5+(arctan((n - 2.0) / (n * restLength)) - pi / 4.0) / (pi / 2.0) * alp_add_coeff # #p.debugmsg('alpAddition:' + str(alpAddition)) # assert alpAddition > 0 # if someone incorrectly modifies commonCoeff it can be less than zero # alp_addition += alpAddition # #p.debugmsg('alp_addition:' + str(alp_addition)) # # directionVectorsList.append(gn) # if len(directionVectorsList) > 2: directionVectorsList = directionVectorsList[:-2] # # CHANGES END if self.dilationType == 'normalized' and (not fname_p in ('lb', 'ub', 'lin_eq', 'lin_ineq') \ or not fname_ in ('lb', 'ub', 'lin_eq', 'lin_ineq')) and (fname_p != fname_ or ind_p != ind_): G2, G = directionForDilation/norm(directionForDilation), prevDirectionForDilation/norm(prevDirectionForDilation) else: G2, G = directionForDilation, prevDirectionForDilation if prevIter_PointForDilation.isFeas(True) == PointForDilation.isFeas(True): g1 = G2 - G elif prevIter_PointForDilation.isFeas(True): g1 = G2.copy() else: g1 = G.copy() alp_addition += 0.05 #print p.getMaxResidual(PointForDilation.x, 1) ############################################## # the case may be occured when # 1) lastPointOfSameType is used # or # 2) some NaN from constraints have been excluded if norm(G2 - G) < 1e-12 * min((norm(G2), norm(G))) and (involve_lastPointOfSameType or NaN_derivatives_excluded): p.debugmsg("ralg: 'last point of same type gradient' is used") g1 = G2 ############################################## #g1 = -G.copy() # signum doesn't matter here # changes wrt infeas constraints # if prevIterPoint.nNaNs() != 0: # cp, hp = prevIterPoint.c(), prevIterPoint.h() # ind_infeas_cp, ind_infeas_hp = isnan(cp), isnan(hp) # # c, h = iterPoint.c(), iterPoint.h() # ind_infeas_c, ind_infeas_h = isnan(c), isnan(h) # # ind_goodChange_c = logical_and(ind_infeas_cp, logical_not(ind_infeas_c)) # ind_goodChange_h = logical_and(ind_infeas_hp, logical_not(ind_infeas_h)) # # any_c, any_h = any(ind_goodChange_c), any(ind_goodChange_h) # altDilation = zeros(n) # if any_c: # altDilation += sum(atleast_2d(iterPoint.dc(where(ind_goodChange_c)[0])), 0) # assert not any(isnan(altDilation)) # if any_h: # altDilation += sum(atleast_2d(iterPoint.dh(where(ind_goodChange_h)[0])), 0) # if any_c or any_h: # #print '!>', altDilation # #g1 = altDilation # pass # changes end """ Perform dilation """ # CHANGES # g = economyMult(b.T, g1) # gn = g/norm(g) # if len(directionVectorsList) == 0 or n < 3 or norm(g1) < 1e-20: pass # else: # if len(directionVectorsList) == 1 or abs(dot(directionVectorsList[-1], directionVectorsList[-2]))>0.999: # projectionComponentLenght = abs(dot(directionVectorsList[-1], gn)) # restLength = sqrt(1 - min((1, projectionComponentLenght))**2) # else: # e1 = directionVectorsList[-1] # e2 = directionVectorsList[-2] - dot(directionVectorsList[-1], directionVectorsList[-2]) * directionVectorsList[-1] # print dot(directionVectorsList[-1], directionVectorsList[-2]) # e2 /= norm(e2) # proj1, proj2 = dot(e1, gn), dot(e2, gn) # rest = gn - proj1 * e1 - proj2 * e2 # restLength = norm(rest) # assert restLength < 1+1e-5, 'error in ralg solver: incorrect restLength' # # # TODO: make it parameters of ralg # commonCoeff, alp_add_coeff = 0.5, 1.0 # # if restLength < commonCoeff * (n - 2.0) / n: # #pass # alpAddition = 0.5+(arctan((n - 2.0) / (n * restLength)) - pi / 4.0) / (pi / 2.0) * alp_add_coeff # #p.debugmsg('alpAddition:' + str(alpAddition)) # assert alpAddition > 0 # if someone incorrectly modifies commonCoeff it can be less than zero # alp_addition += alpAddition # #p.debugmsg('alp_addition:' + str(alp_addition)) # # directionVectorsList.append(gn) # if len(directionVectorsList) > 2: directionVectorsList = directionVectorsList[:-2] # CHANGES END if doDilation: g = economyMult(b.T, g1) ng = p.norm(g) if self.needRej(p, b, g1, g) or selfNeedRej: selfNeedRej = False if self.showRej or p.debug: p.info('debug msg: matrix B restoration in ralg solver') b = B0.copy() hs = p.norm(prevIter_best_ls_point.x - best_ls_point.x) # TODO: iterPoint = projection(iterPoint,Aeq) if res_Aeq > 0.75*contol if ng < 1e-40: hs *= 0.9 p.debugmsg('small dilation direction norm (%e), skipping' % ng) if all(isfinite(g)) and ng > 1e-50 and doDilation: g = (g / ng).reshape(-1,1) vec1 = economyMult(b, g).reshape(-1,1)# TODO: remove economyMult, use dot? #if alp_addition != 0: p.debugmsg('alp_addition:' + str(alp_addition)) w = asarray(1.0/(alp+alp_addition)-1.0, T) vec2 = w * g.T b += p.matmult(vec1, vec2) """ Call OO iterfcn """ if hasattr(p, '_df'): delattr(p, '_df') if best_ls_point.isFeas(False) and hasattr(best_ls_point, '_df'): p._df = best_ls_point.df().copy() p.iterfcn(best_ls_point) """ Check stop criteria """ cond_same_point = array_equal(best_ls_point.x, prevIter_best_ls_point.x) if cond_same_point and not p.istop: p.istop = 14 p.msg = 'X[k-1] and X[k] are same' p.stopdict[SMALL_DELTA_X] = True restoreProb() self.innerState = {'B': b, 'hs': hs} return s2 = 0 if p.istop and not p.userStop: if p.istop not in p.stopdict: p.stopdict[p.istop] = True # it's actual for converters, TODO: fix it if SMALL_DF in p.stopdict: if best_ls_point.isFeas(False): s2 = p.istop p.stopdict.pop(SMALL_DF) if SMALL_DELTA_F in p.stopdict: # TODO: implement it more properly if best_ls_point.isFeas(False) and prevIter_best_ls_point.f() != best_ls_point.f(): s2 = p.istop p.stopdict.pop(SMALL_DELTA_F) if SMALL_DELTA_X in p.stopdict: if best_ls_point.isFeas(False) or not prevIter_best_ls_point.isFeas(False) or cond_same_point: s2 = p.istop p.stopdict.pop(SMALL_DELTA_X) # if s2 and (any(isnan(best_ls_point.c())) or any(isnan(best_ls_point.h()))) \ # and not p.isNaNInConstraintsAllowed\ # and not cond_same_point: # s2 = 0 if not s2 and any(p.stopdict.values()): for key, val in p.stopdict.items(): if val == True: s2 = key break p.istop = s2 for key, val in p.stopdict.items(): if key < 0 or key in set([FVAL_IS_ENOUGH, USER_DEMAND_STOP, BUTTON_ENOUGH_HAS_BEEN_PRESSED]): p.iterfcn(bestPoint) self.innerState = {'B': b, 'hs': hs} return """ If stop required """ if p.istop: # if self.needRej(p, b, g1, g) or not feasiblePointWasEncountered: # b = B0.copy() # hs = max((p.norm(prevIter_best_ls_point.x - best_ls_point.x) , 128*p.xtol)) # p.istop = 0 # else: restoreProb() p.iterfcn(bestPoint) #p.istop, p.msg = istop, msg self.innerState = {'B': b, 'hs': hs} return """ Some final things for ralg main cycle """ # p.debugmsg('new point Aeq residual:'+str(norm(dot(Aeq, iterPoint.x)-beq))) # if needProjection and itn!=0: # #pass # x2 = self.linEqProjection(iterPoint.x, Aeq, beq) # p.debugmsg('norm(delta):' + str(norm(iterPoint.x-x2))) # iterPoint = p.point(x2) # p.debugmsg('2: new point Aeq residual:'+str(norm(dot(Aeq, iterPoint.x)-beq))) #p.hs.append(hs) #g = moveDirection.copy() #prevDirectionForDilation = directionForDilation #iterPoint = None #doScale = self.new_s and prevIter_PointForDilation.isFeas(True) != best_ls_point.isFeas(True) #print doScale prevIter_best_ls_point = best_ls_point prevIter_PointForDilation = best_ls_point prevDirectionForDilation = best_ls_point._getDirection(self.approach) moveDirection = best_ls_point._getDirection(self.approach)
def __solver__(self, p): if SMALL_DELTA_X in p.kernelIterFuncs.keys(): p.kernelIterFuncs.pop(SMALL_DELTA_X) if SMALL_DELTA_F in p.kernelIterFuncs.keys(): p.kernelIterFuncs.pop(SMALL_DELTA_F) if self.nspSolver == 'autoselect': nspSolver = 'amsg2p' if p.isUC else 'ralg' else: nspSolver = self.nspSolver # nspSolver = 'ralg' way = 3 if nspSolver == 'ralg' else 2 if way == 1: use2 = False f = lambda x: sum(abs(p.f(x))) def df(x): return dot(p.df(x), sign(p.f(x))) elif way == 2: use2 = True f = lambda x: sum(p.f(x)**2) def df(x): return 2.0*dot(p.f(x), p.df(x)) elif way == 3: use2 = False f = lambda x: max(abs(p.f(x))) def df(x): F = p.f(x) ind = argmax(abs(F)) return p.df(x, ind) * sign(F[ind]) FTOL = p.ftol**2 if use2 else p.ftol def iterfcn(*args, **kwargs): p2.primalIterFcn(*args, **kwargs) p.xk = p2.xk.copy() Fk = norm(p.f(p.xk), inf) p.rk = p.getMaxResidual(p.xk) #TODO: ADD p.rk if p.nEvals['f'] > p.maxFunEvals: p.istop = p2.istop = IS_MAX_FUN_EVALS_REACHED elif p2.istop!=0: if Fk < FTOL and p.rk < p.contol: p.istop = 15 msg_contol = '' if p.isUC else 'and contol ' p.msg = 'solution with required ftol ' + msg_contol+ 'has been reached' else: p.istop = p2.istop p.iterfcn() return p.istop p2 = NSP(f, p.x0, df=df, xtol = p.xtol/1e16, gtol = p.gtol/1e16,\ A=p.A, b=p.b, Aeq=p.Aeq, beq=p.beq, lb=p.lb, ub=p.ub, \ maxFunEvals = p.maxFunEvals, fEnough = FTOL, maxIter=p.maxIter, iprint = -1, \ maxtime = p.maxTime, maxCPUTime = p.maxCPUTime, noise = p.noise, fOpt = 0.0) if p.userProvided.c: p2.c, p2.dc = p.c, p.dc if p.userProvided.h: p2.h, p2.dh = p.h, p.dh p2.primalIterFcn, p2.iterfcn = p2.iterfcn, iterfcn if p.debug: p2.iprint = 1 if nspSolver == 'ralg': if p.isUC: p2.ftol = p.ftol / 1e16 else: p2.ftol = 0.0 else: p2.ftol = 0.0 p2.xtol = 0.0 p2.gtol = 0.0 if use2: p2.fTol = 0.5*p.ftol ** 2 else: p2.fTol = 0.5*p.ftol r2 = p2.solve(nspSolver) #xf = fsolve(p.f, p.x0, fprime=p.df, xtol = p.xtol, maxfev = p.maxFunEvals) xf = r2.xf p.xk = p.xf = xf p.fk = p.ff = asfarray(norm(p.f(xf), inf)).flatten()
def lsqr( m, n, aprod, b, damp, atol, btol, conlim, itnlim, show, wantvar = False, callback = lambda x: None): """ [ x, istop, itn, r1norm, r2norm, anorm, acond, arnorm, xnorm, var ]... = lsqr( m, n, @aprod, b, damp, atol, btol, conlim, itnlim, show ); LSQR solves Ax = b or min ||b - Ax||_2 if damp = 0, or min || [ b ] - [ A ] x || otherwise. || [ 0 ] [ damp I ] ||2 A is an m by n matrix defined by y = aprod(mode, m, n, x), where aprod refers to a function that performs the matrix-vector operations. If mode = 1, aprod must return y = Ax without altering x. If mode = 2, aprod must return y = A'x without altering x. ---------------------------------------------------------------------- LSQR uses an iterative (conjugate-gradient-like) method. For further information, see 1. C. C. Paige and M. A. Saunders (1982a). LSQR: An algorithm for sparse linear equations and sparse least squares, ACM TOMS 8(1), 43-71. 2. C. C. Paige and M. A. Saunders (1982b). Algorithm 583. LSQR: Sparse linear equations and least squares problems, ACM TOMS 8(2), 195-209. 3. M. A. Saunders (1995). Solution of sparse rectangular systems using LSQR and CRAIG, BIT 35, 588-604. Input parameters: atol, btol are stopping tolerances. If both are 1.0e-9 (say), the final residual norm should be accurate to about 9 digits. (The final x will usually have fewer correct digits, depending on cond(A) and the size of damp.) conlim is also a stopping tolerance. lsqr terminates if an estimate of cond(A) exceeds conlim. For compatible systems Ax = b, conlim could be as large as 1.0e+12 (say). For least-squares problems, conlim should be less than 1.0e+8. Maximum precision can be obtained by setting atol = btol = conlim = zero, but the number of iterations may then be excessive. itnlim is an explicit limit on iterations (for safety). show if set to 1, gives an iteration log. If set to 0, suppresses output. Output parameters: x is the final solution. istop gives the reason for termination. istop = 1 means x is an approximate solution to Ax = b. = 2 means x approximately solves the least-squares problem. r1norm = norm(r), where r = b - Ax. r2norm = sqrt( norm(r)^2 + damp^2 * norm(x)^2 ) = r1norm if damp = 0. anorm = estimate of Frobenius norm of Abar = [ A ]. [damp*I] acond = estimate of cond(Abar). arnorm = estimate of norm(A'*r - damp^2*x). xnorm = norm(x). var (if present) estimates all diagonals of (A'A)^{-1} (if damp=0) or more generally (A'A + damp^2*I)^{-1}. This is well defined if A has full column rank or damp > 0. (Not sure what var means if rank(A) < n and damp = 0.) ---------------------------------------------------------------------- """ # Initialize. msg=['The exact solution is x = 0 ', 'Ax - b is small enough, given atol, btol ', 'The least-squares solution is good enough, given atol ', 'The estimate of cond(Abar) has exceeded conlim ', 'Ax - b is small enough for this machine ', 'The least-squares solution is good enough for this machine', 'Cond(Abar) seems to be too large for this machine ', 'The iteration limit has been reached '] if wantvar: var = zeros(n,1) else: var = None # if show: # print ' ' # print 'LSQR Least-squares solution of Ax = b' # str1 = 'The matrix A has %8g rows and %8g cols' % (m, n) # str2 = 'damp = %20.14e wantvar = %-5s' % (damp, repr(wantvar)) # str3 = 'atol = %8.2e conlim = %8.2e' % (atol, conlim) # str4 = 'btol = %8.2e itnlim = %8g' % (btol, itnlim) # print str1; print str2; print str3; print str4; itn = 0; istop = 0; nstop = 0 ctol = 0.0 if conlim > 0.0: ctol = 1.0/conlim anorm = 0.; acond = 0. dampsq = damp**2; ddnorm = 0.; res2 = 0. xnorm = 0.; xxnorm = 0.; z = 0. cs2 = -1.; sn2 = 0. # Set up the first vectors u and v for the bidiagonalization. # These satisfy beta*u = b, alfa*v = A'u. u = b[:m]; x = zeros(n) alfa = 0.; beta = norm( u ) if beta > 0: u = (1.0/beta) * u; v = aprod(2, m, n, u) alfa = norm( v ); if alfa > 0: v = (1.0/alfa) * v; w = v.copy(); arnorm = alfa * beta; if arnorm == 0: # print(msg[0]) return (x, istop, itn, r1norm, r2norm, anorm, acond, arnorm, xnorm, var) rhobar = alfa; phibar = beta; bnorm = beta; rnorm = beta r1norm = rnorm r2norm = rnorm head1 = ' Itn x(1) r1norm r2norm ' head2 = ' Compatible LS Norm A Cond A' if show: # print ' ' # print head1+head2 test1 = 1.0; test2 = alfa / beta str1 = '%6g %12.5e' % (itn, x[0]) str2 = ' %10.3e %10.3e' % (r1norm, r2norm) str3 = ' %8.1e %8.1e' % (test1, test2) # print str1+str2+str3 # ------------------------------------------------------------------ # Main iteration loop. # ------------------------------------------------------------------ while itn < itnlim: itn = itn + 1 # Perform the next step of the bidiagonalization to obtain the # next beta, u, alfa, v. These satisfy the relations # beta*u = a*v - alfa*u, # alfa*v = A'*u - beta*v. u = aprod(1, m, n, v) - alfa*u beta = norm( u ); if beta > 0: u = (1.0/beta) * u anorm = normof4(anorm, alfa, beta, damp) v = aprod(2, m, n, u) - beta*v alfa = norm( v ) if alfa > 0: v = (1.0/alfa) * v # Use a plane rotation to eliminate the damping parameter. # This alters the diagonal (rhobar) of the lower-bidiagonal matrix. rhobar1 = normof2(rhobar, damp) cs1 = rhobar / rhobar1 sn1 = damp / rhobar1 psi = sn1 * phibar phibar = cs1 * phibar # Use a plane rotation to eliminate the subdiagonal element (beta) # of the lower-bidiagonal matrix, giving an upper-bidiagonal matrix. rho = normof2(rhobar1, beta) cs = rhobar1/ rho sn = beta / rho theta = sn * alfa rhobar = - cs * alfa phi = cs * phibar phibar = sn * phibar tau = sn * phi # Update x and w. t1 = phi /rho; t2 = - theta/rho; dk = (1.0/rho)*w; x = x + t1*w w = v + t2*w ddnorm = ddnorm + norm(dk)**2 if wantvar: var = var + dk*dk # Use a plane rotation on the right to eliminate the # super-diagonal element (theta) of the upper-bidiagonal matrix. # Then use the result to estimate norm(x). delta = sn2 * rho gambar = - cs2 * rho rhs = phi - delta * z zbar = rhs / gambar xnorm = sqrt(xxnorm + zbar**2) gamma = normof2(gambar, theta) cs2 = gambar / gamma sn2 = theta / gamma z = rhs / gamma xxnorm = xxnorm + z**2 # Test for convergence. # First, estimate the condition of the matrix Abar, # and the norms of rbar and Abar'rbar. acond = anorm * sqrt( ddnorm ) res1 = phibar**2 res2 = res2 + psi**2 rnorm = sqrt( res1 + res2 ) arnorm = alfa * abs( tau ) # 07 Aug 2002: # Distinguish between # r1norm = ||b - Ax|| and # r2norm = rnorm in current code # = sqrt(r1norm^2 + damp^2*||x||^2). # Estimate r1norm from # r1norm = sqrt(r2norm^2 - damp^2*||x||^2). # Although there is cancellation, it might be accurate enough. r1sq = rnorm**2 - dampsq * xxnorm r1norm = sqrt( abs(r1sq) ) if r1sq < 0: r1norm = - r1norm r2norm = rnorm # Now use these norms to estimate certain other quantities, # some of which will be small near a solution. test1 = rnorm / bnorm test2 = arnorm/( anorm * rnorm ) test3 = 1.0 / acond t1 = test1 / (1 + anorm * xnorm / bnorm) rtol = btol + atol * anorm * xnorm / bnorm # The following tests guard against extremely small values of # atol, btol or ctol. (The user may have set any or all of # the parameters atol, btol, conlim to 0.) # The effect is equivalent to the normal tests using # atol = eps, btol = eps, conlim = 1/eps. if itn >= itnlim: istop = 7 if 1 + test3 <= 1: istop = 6 if 1 + test2 <= 1: istop = 5 if 1 + t1 <= 1: istop = 4 # Allow for tolerances set by the user. if test3 <= ctol: istop = 3 if test2 <= atol: istop = 2 if test1 <= rtol: istop = 1 # See if it is time to print something. prnt = False; if n <= 40 : prnt = True if itn <= 10 : prnt = True if itn >= itnlim-10: prnt = True if itn % 10 == 0 : prnt = True if test3 <= 2*ctol : prnt = True if test2 <= 10*atol : prnt = True if test1 <= 10*rtol : prnt = True if istop != 0 : prnt = True if prnt and show: str1 = '%6g %12.5e' %( itn, x[0] ) str2 = ' %10.3e %10.3e' %(r1norm, r2norm ) str3 = ' %8.1e %8.1e' %( test1, test2 ) str4 = ' %8.1e %8.1e' %( anorm, acond ) # print str1+str2+str3+str4 if istop > 0: break callback(x) # added for OpenOpt kernel # End of iteration loop. # Print the stopping condition. # if show: # print ' ' # print 'LSQR finished' # print msg[istop] # print ' ' # str1 = 'istop =%8g r1norm =%8.1e' %(istop, r1norm ) # str2 = 'anorm =%8.1e arnorm =%8.1e' %(anorm, arnorm ) # str3 = 'itn =%8g r2norm =%8.1e' %( itn, r2norm ) # str4 = 'acond =%8.1e xnorm =%8.1e' %(acond, xnorm ) # str5 = ' bnorm =%8.1e' % bnorm # print str1 + ' ' + str2 # print str3 + ' ' + str4 # print str5 # print ' ' return ( x, istop, itn, r1norm, r2norm, anorm, acond, arnorm, xnorm, var )
def lsqr(m, n, aprod, b, damp, atol, btol, conlim, itnlim, show, wantvar=False, callback=lambda x: None): """ [ x, istop, itn, r1norm, r2norm, anorm, acond, arnorm, xnorm, var ]... = lsqr( m, n, @aprod, b, damp, atol, btol, conlim, itnlim, show ); LSQR solves Ax = b or min ||b - Ax||_2 if damp = 0, or min || [ b ] - [ A ] x || otherwise. || [ 0 ] [ damp I ] ||2 A is an m by n matrix defined by y = aprod(mode, m, n, x), where aprod refers to a function that performs the matrix-vector operations. If mode = 1, aprod must return y = Ax without altering x. If mode = 2, aprod must return y = A'x without altering x. ---------------------------------------------------------------------- LSQR uses an iterative (conjugate-gradient-like) method. For further information, see 1. C. C. Paige and M. A. Saunders (1982a). LSQR: An algorithm for sparse linear equations and sparse least squares, ACM TOMS 8(1), 43-71. 2. C. C. Paige and M. A. Saunders (1982b). Algorithm 583. LSQR: Sparse linear equations and least squares problems, ACM TOMS 8(2), 195-209. 3. M. A. Saunders (1995). Solution of sparse rectangular systems using LSQR and CRAIG, BIT 35, 588-604. Input parameters: atol, btol are stopping tolerances. If both are 1.0e-9 (say), the final residual norm should be accurate to about 9 digits. (The final x will usually have fewer correct digits, depending on cond(A) and the size of damp.) conlim is also a stopping tolerance. lsqr terminates if an estimate of cond(A) exceeds conlim. For compatible systems Ax = b, conlim could be as large as 1.0e+12 (say). For least-squares problems, conlim should be less than 1.0e+8. Maximum precision can be obtained by setting atol = btol = conlim = zero, but the number of iterations may then be excessive. itnlim is an explicit limit on iterations (for safety). show if set to 1, gives an iteration log. If set to 0, suppresses output. Output parameters: x is the final solution. istop gives the reason for termination. istop = 1 means x is an approximate solution to Ax = b. = 2 means x approximately solves the least-squares problem. r1norm = norm(r), where r = b - Ax. r2norm = sqrt( norm(r)^2 + damp^2 * norm(x)^2 ) = r1norm if damp = 0. anorm = estimate of Frobenius norm of Abar = [ A ]. [damp*I] acond = estimate of cond(Abar). arnorm = estimate of norm(A'*r - damp^2*x). xnorm = norm(x). var (if present) estimates all diagonals of (A'A)^{-1} (if damp=0) or more generally (A'A + damp^2*I)^{-1}. This is well defined if A has full column rank or damp > 0. (Not sure what var means if rank(A) < n and damp = 0.) ---------------------------------------------------------------------- """ # Initialize. msg = [ 'The exact solution is x = 0 ', 'Ax - b is small enough, given atol, btol ', 'The least-squares solution is good enough, given atol ', 'The estimate of cond(Abar) has exceeded conlim ', 'Ax - b is small enough for this machine ', 'The least-squares solution is good enough for this machine', 'Cond(Abar) seems to be too large for this machine ', 'The iteration limit has been reached ' ] if wantvar: var = zeros(n, 1) else: var = None # if show: # print ' ' # print 'LSQR Least-squares solution of Ax = b' # str1 = 'The matrix A has %8g rows and %8g cols' % (m, n) # str2 = 'damp = %20.14e wantvar = %-5s' % (damp, repr(wantvar)) # str3 = 'atol = %8.2e conlim = %8.2e' % (atol, conlim) # str4 = 'btol = %8.2e itnlim = %8g' % (btol, itnlim) # print str1; print str2; print str3; print str4; itn = 0 istop = 0 nstop = 0 ctol = 0.0 if conlim > 0.0: ctol = 1.0 / conlim anorm = 0. acond = 0. dampsq = damp**2 ddnorm = 0. res2 = 0. xnorm = 0. xxnorm = 0. z = 0. cs2 = -1. sn2 = 0. # Set up the first vectors u and v for the bidiagonalization. # These satisfy beta*u = b, alfa*v = A'u. u = b[:m] x = zeros(n) alfa = 0. beta = norm(u) if beta > 0: u = (1.0 / beta) * u v = aprod(2, m, n, u) alfa = norm(v) if alfa > 0: v = (1.0 / alfa) * v w = v.copy() arnorm = alfa * beta if arnorm == 0: # print(msg[0]) return (x, istop, itn, r1norm, r2norm, anorm, acond, arnorm, xnorm, var) rhobar = alfa phibar = beta bnorm = beta rnorm = beta r1norm = rnorm r2norm = rnorm head1 = ' Itn x(1) r1norm r2norm ' head2 = ' Compatible LS Norm A Cond A' if show: # print ' ' # print head1+head2 test1 = 1.0 test2 = alfa / beta str1 = '%6g %12.5e' % (itn, x[0]) str2 = ' %10.3e %10.3e' % (r1norm, r2norm) str3 = ' %8.1e %8.1e' % (test1, test2) # print str1+str2+str3 # ------------------------------------------------------------------ # Main iteration loop. # ------------------------------------------------------------------ while itn < itnlim: itn = itn + 1 # Perform the next step of the bidiagonalization to obtain the # next beta, u, alfa, v. These satisfy the relations # beta*u = a*v - alfa*u, # alfa*v = A'*u - beta*v. u = aprod(1, m, n, v) - alfa * u beta = norm(u) if beta > 0: u = (1.0 / beta) * u anorm = normof4(anorm, alfa, beta, damp) v = aprod(2, m, n, u) - beta * v alfa = norm(v) if alfa > 0: v = (1.0 / alfa) * v # Use a plane rotation to eliminate the damping parameter. # This alters the diagonal (rhobar) of the lower-bidiagonal matrix. rhobar1 = normof2(rhobar, damp) cs1 = rhobar / rhobar1 sn1 = damp / rhobar1 psi = sn1 * phibar phibar = cs1 * phibar # Use a plane rotation to eliminate the subdiagonal element (beta) # of the lower-bidiagonal matrix, giving an upper-bidiagonal matrix. rho = normof2(rhobar1, beta) cs = rhobar1 / rho sn = beta / rho theta = sn * alfa rhobar = -cs * alfa phi = cs * phibar phibar = sn * phibar tau = sn * phi # Update x and w. t1 = phi / rho t2 = -theta / rho dk = (1.0 / rho) * w x = x + t1 * w w = v + t2 * w ddnorm = ddnorm + norm(dk)**2 if wantvar: var = var + dk * dk # Use a plane rotation on the right to eliminate the # super-diagonal element (theta) of the upper-bidiagonal matrix. # Then use the result to estimate norm(x). delta = sn2 * rho gambar = -cs2 * rho rhs = phi - delta * z zbar = rhs / gambar xnorm = sqrt(xxnorm + zbar**2) gamma = normof2(gambar, theta) cs2 = gambar / gamma sn2 = theta / gamma z = rhs / gamma xxnorm = xxnorm + z**2 # Test for convergence. # First, estimate the condition of the matrix Abar, # and the norms of rbar and Abar'rbar. acond = anorm * sqrt(ddnorm) res1 = phibar**2 res2 = res2 + psi**2 rnorm = sqrt(res1 + res2) arnorm = alfa * abs(tau) # 07 Aug 2002: # Distinguish between # r1norm = ||b - Ax|| and # r2norm = rnorm in current code # = sqrt(r1norm^2 + damp^2*||x||^2). # Estimate r1norm from # r1norm = sqrt(r2norm^2 - damp^2*||x||^2). # Although there is cancellation, it might be accurate enough. r1sq = rnorm**2 - dampsq * xxnorm r1norm = sqrt(abs(r1sq)) if r1sq < 0: r1norm = -r1norm r2norm = rnorm # Now use these norms to estimate certain other quantities, # some of which will be small near a solution. test1 = rnorm / bnorm test2 = arnorm / (anorm * rnorm) test3 = 1.0 / acond t1 = test1 / (1 + anorm * xnorm / bnorm) rtol = btol + atol * anorm * xnorm / bnorm # The following tests guard against extremely small values of # atol, btol or ctol. (The user may have set any or all of # the parameters atol, btol, conlim to 0.) # The effect is equivalent to the normal tests using # atol = eps, btol = eps, conlim = 1/eps. if itn >= itnlim: istop = 7 if 1 + test3 <= 1: istop = 6 if 1 + test2 <= 1: istop = 5 if 1 + t1 <= 1: istop = 4 # Allow for tolerances set by the user. if test3 <= ctol: istop = 3 if test2 <= atol: istop = 2 if test1 <= rtol: istop = 1 # See if it is time to print something. prnt = False if n <= 40: prnt = True if itn <= 10: prnt = True if itn >= itnlim - 10: prnt = True if itn % 10 == 0: prnt = True if test3 <= 2 * ctol: prnt = True if test2 <= 10 * atol: prnt = True if test1 <= 10 * rtol: prnt = True if istop != 0: prnt = True if prnt and show: str1 = '%6g %12.5e' % (itn, x[0]) str2 = ' %10.3e %10.3e' % (r1norm, r2norm) str3 = ' %8.1e %8.1e' % (test1, test2) str4 = ' %8.1e %8.1e' % (anorm, acond) # print str1+str2+str3+str4 if istop > 0: break callback(x) # added for OpenOpt kernel # End of iteration loop. # Print the stopping condition. # if show: # print ' ' # print 'LSQR finished' # print msg[istop] # print ' ' # str1 = 'istop =%8g r1norm =%8.1e' %(istop, r1norm ) # str2 = 'anorm =%8.1e arnorm =%8.1e' %(anorm, arnorm ) # str3 = 'itn =%8g r2norm =%8.1e' %( itn, r2norm ) # str4 = 'acond =%8.1e xnorm =%8.1e' %(acond, xnorm ) # str5 = ' bnorm =%8.1e' % bnorm # print str1 + ' ' + str2 # print str3 + ' ' + str4 # print str5 # print ' ' return (x, istop, itn, r1norm, r2norm, anorm, acond, arnorm, xnorm, var)