def _Prepare(self): if self._isPrepared: return self._isPrepared = True if isinstance(self.d, dict): # FuncDesigner startPoint self.x0 = self.d MatrixProblem._Prepare(self) if self.isFDmodel: equations = self.C AsSparse = bool(self.useSparse) if type(self.useSparse) != str else self._useSparse() C, d = [], [] if len(self._fixedVars) < len(self._freeVars): Z = dict([(v, zeros_like(self._x0[v]) if v not in self._fixedVars else self._x0[v]) for v in self._x0.keys()]) else: Z = dict([(v, zeros_like(self._x0[v]) if v in self._freeVars else self._x0[v]) for v in self._x0.keys()]) #Z = self.x0#self._vector2point(zeros(self.n)) for lin_oofun in equations: if lin_oofun.getOrder(self.freeVars, self.fixedVars) > 1: raise OpenOptException('SLE constructor requires all equations to be linear') C.append(self._pointDerivative2array(lin_oofun.D(Z, **self._D_kwargs), useSparse = AsSparse)) d.append(-lin_oofun(Z)) self.d = hstack(d).flatten() self.C = Vstack(C) if hasattr(self.C, 'tocsc'): self.C_as_csc = self.C.tocsc() if isinstance(self.C,ndarray) and self.n > 100 and len(flatnonzero(self.C))/self.C.size < 0.3: s = "Probably you'd better solve this SLE as sparse" if not scipyInstalled: s += ' (requires scipy installed)' self.pWarn(s) self.x0 = zeros(self.C.shape[1])
def getPattern(oofuns): # oofuns is Python list of oofuns assert isinstance(oofuns, list), 'oofuns should be Python list, inform developers of the bug' R = [] for oof in oofuns: SIZE = asarray(oof(startPoint)).size r = [] dep = oof._getDep() if len(p._fixedVars) != 0: dep = dep & p._freeVars if len(p._freeVars) < len(p._fixedVars) else dep.difference(p._fixedVars) # NEW ind_Z = 0 vars = list(dep) vars.sort(key=lambda elem: elem._id) for oov in vars: ind_start, ind_end = oovarsIndDict[oov] if ind_start != ind_Z: r.append(SparseMatrixConstructor((SIZE, ind_start - ind_Z))) r.append(ones((SIZE, ind_end - ind_start))) ind_Z = ind_end if ind_Z != n: # assert ind_Z < n r.append(SparseMatrixConstructor((SIZE, n - ind_Z))) if any([isspmatrix(elem) for elem in r]): rr = Hstack(r) if len(r) > 1 else r[0] elif len(r)>1: rr = hstack(r) else: rr = r[0] R.append(rr) result = Vstack(R) if any([isspmatrix(_r) for _r in R]) else vstack(R) return result
def linearOOFunsToMatrices(oofuns): #, useSparse = 'auto' # oofuns should be linear C, d = [], [] Z = p._vector2point(zeros(p.n)) for elem in oofuns: if elem.isConstraint: lin_oofun = elem.oofun else: lin_oofun = elem if lin_oofun.getOrder(p.freeVars, p.fixedVars) > 1: from oologfcn import OpenOptException raise OpenOptException("this function hasn't been intended to work with nonlinear FuncDesigner oofuns") C.append(p._pointDerivative2array(lin_oofun.D(Z, **p._D_kwargs), useSparse = p.useSparse)) d.append(-lin_oofun(Z)) C, d = Vstack(C), hstack(d).flatten() return C, d
def LinConst2WholeRepr(p): """ transforms (A, x) <= b, (Aeq, x) = beq into Awhole, bwhole, dwhole constraints (see help(LP)) this func is developed for those solvers that can handle linear (in)equality constraints only via Awhole """ if p.A == None and p.Aeq == None: return # new p.Awhole = Vstack( [elem for elem in [p.Awhole, p.A, p.Aeq] if elem is not None]) #old # Awhole = Copy(p.Awhole) # maybe it's already present and not equal to None # p.Awhole = zeros([Len(p.b) + Len(p.beq) + Len(p.bwhole), p.n]) # if Awhole.size>0: p.Awhole[:Len(p.bwhole)] = Awhole # p.Awhole[Len(p.bwhole):Len(p.bwhole)+Len(p.b)] = p.A # if p.Aeq.size: p.Awhole[Len(p.bwhole)+Len(p.b):] = p.Aeq p.A, p.Aeq = None, None bwhole = Copy(p.bwhole) p.bwhole = zeros(Len(p.b) + Len(p.beq) + Len(p.bwhole)) p.bwhole[:Len(bwhole)] = bwhole p.bwhole[Len(bwhole):Len(bwhole) + Len(p.b)] = p.b p.bwhole[Len(bwhole) + Len(p.b):] = p.beq dwhole = Copy(p.dwhole) p.dwhole = zeros(Len(p.bwhole)) if dwhole.size: p.dwhole[:Len(bwhole)] = dwhole p.dwhole[Len(bwhole):Len(bwhole) + Len(p.b)] = -1 p.dwhole[Len(bwhole) + Len(p.b):] = 0 p.b = None p.beq = None
def _prepare(self): if self._baseProblemIsPrepared: return if self.useSparse == 0: self.useSparse = False elif self.useSparse == 1: self.useSparse = True if self.useSparse == 'auto' and not scipyInstalled: self.useSparse = False if self.useSparse == True and not scipyInstalled: self.err("You can't set useSparse=True without scipy installed") if self._isFDmodel(): self.isFDmodel = True self._FD = EmptyClass() self._FD.nonBoxConsWithTolShift = [] self._FD.nonBoxCons = [] from FuncDesigner import _getAllAttachedConstraints, _getDiffVarsID, ooarray, oopoint, oofun#, _Stochastic self._FDVarsID = _getDiffVarsID() probDep = set() updateDep = lambda Dep, elem: \ [updateDep(Dep, f) for f in elem] if isinstance(elem, (tuple, list, set))\ else [updateDep(Dep, f) for f in atleast_1d(elem)] if isinstance(elem, ndarray)\ else Dep.update(set([elem]) if elem.is_oovar else elem._getDep()) if isinstance(elem, oofun) else None if self.probType in ['SLE', 'NLSP', 'SNLE', 'LLSP']: equations = self.C if self.probType in ('SLE', 'LLSP') else self.f F = equations updateDep(probDep, equations) ConstraintTags = [(elem if not isinstance(elem, (set, list, tuple, ndarray)) else elem[0]).isConstraint for elem in equations] cond_all_oofuns_but_not_cons = not any(ConstraintTags) cond_cons = all(ConstraintTags) if not cond_all_oofuns_but_not_cons and not cond_cons: raise OpenOptException('for FuncDesigner SLE/SNLE constructors args must be either all-equalities or all-oofuns') if self.fTol is not None: fTol = min((self.ftol, self.fTol)) self.warn(''' both ftol and fTol are passed to the SNLE; minimal value of the pair will be used (%0.1e); also, you can modify each personal tolerance for equation, e.g. equations = [(sin(x)+cos(y)=-0.5)(tol = 0.001), ...] ''' % fTol) else: fTol = self.ftol self.fTol = self.ftol = fTol appender = lambda arg: [appender(elem) for elem in arg] if isinstance(arg, (ndarray, list, tuple, set))\ else ((arg.oofun*(fTol/arg.tol) if arg.tol != fTol and arg.tol != 0 else arg.oofun) if arg.isConstraint else arg) EQs = [] for eq in equations: rr = appender(eq) if type(rr) == list: EQs += rr else: EQs.append(rr) #EQs = [((elem.oofun*(fTol/elem.tol) if elem.tol != 0 else elem.oofun) if elem.isConstraint else elem) for elem in equations] if self.probType in ('SLE', 'LLSP'): self.C = EQs elif self.probType in ('NLSP', 'SNLE'): self.f = EQs # self.user.F = EQs else: raise OpenOptException('bug in OO kernel') else: F = [self.f] updateDep(probDep, self.f) updateDep(probDep, self.constraints) # TODO: implement it # startPointVars = set(self.x0.keys()) # D = startPointVars.difference(probDep) # if len(D): # print('values for variables %s are missing in start point' % D) # D2 = probDep.difference(startPointVars) # if len(D2): # self.x0 = dict([(key, self.x0[key]) for key in D2]) for fn in ['lb', 'ub', 'A', 'Aeq', 'b', 'beq']: if not hasattr(self, fn): continue val = getattr(self, fn) if val is not None and any(isfinite(val)): self.err('while using oovars providing lb, ub, A, Aeq for whole prob is forbidden, use for each oovar instead') if not isinstance(self.x0, dict): self.err('Unexpected start point type: ooPoint or Python dict expected, '+ str(type(self.x0)) + ' obtained') x0 = self.x0.copy() tmp = [] for key, val in x0.items(): if not isinstance(key, (list, tuple, ndarray)): tmp.append((key, val)) else: # can be only ooarray although val = atleast_1d(val) if len(key) != val.size: self.err(''' for the sake of possible bugs prevention lenght of oovars array must be equal to lenght of its start point value, assignments like x = oovars(m); startPoint[x] = 0 are forbidden, use startPoint[x] = [0]*m or np.zeros(m) instead''') for i in range(val.size): tmp.append((key[i], val[i])) Tmp = dict(tmp) if isinstance(self.fixedVars, dict): for key, val in self.fixedVars.items(): if isinstance(key, (list, tuple, ndarray)): # can be only ooarray although if len(key) != len(val): self.err(''' for the sake of possible bugs prevention lenght of oovars array must be equal to lenght of its start point value, assignments like x = oovars(m); fixedVars[x] = 0 are forbidden, use fixedVars[x] = [0]*m or np.zeros(m) instead''') for i in range(len(val)): Tmp[key[i]] = val[i] else: Tmp[key] = val self.fixedVars = set(self.fixedVars.keys()) # mb other operations will speedup it? if self.probType != 'ODE': Keys = set(Tmp.keys()).difference(probDep) for key in Keys: Tmp.pop(key) self.probDep = probDep self.x0 = Tmp self._stringVars = set() for key, val in self.x0.items(): #if key.domain is not None and key.domain is not bool and key.domain is not 'bool': if type(val) in (str, string_): self._stringVars.add(key) key.formAuxDomain() self.x0[key] = key.aux_domain[val]#searchsorted(key.aux_domain, val, 'left') elif key.fields == () and key.domain is not None and key.domain is not bool and key.domain is not 'bool' \ and key.domain is not int and key.domain is not 'int' and val not in key.domain: self.x0[key] = key.domain[0] self.x0 = oopoint(self.x0) self.x0.maxDistributionSize = self.maxDistributionSize setStartVectorAndTranslators(self) if self.probType in ['LP', 'MILP', 'SOCP'] and self.f.getOrder(self.freeVarsSet, self.fixedVarsSet, fixedVarsScheduleID = self._FDVarsID) > 1: self.err('for LP/MILP objective function has to be linear, while this one ("%s") is not' % self.f.name) if self.fixedVars is None: D_kwargs = {'fixedVars':self.fixedVarsSet} elif self.freeVars is not None and len(self.freeVars)<len(self.fixedVars): D_kwargs = {'Vars':self.freeVarsSet} else: D_kwargs = {'fixedVars':self.fixedVarsSet} D_kwargs['useSparse'] = self.useSparse D_kwargs['fixedVarsScheduleID'] = self._FDVarsID D_kwargs['exactShape'] = True self._D_kwargs = D_kwargs variableTolerancesDict = dict((v, v.tol) for v in self._freeVars) self.variableTolerances = self._point2vector(variableTolerancesDict) if len(self._fixedVars) < len(self._freeVars) and 'isdisjoint' in dir(set()): areFixed = lambda dep: dep.issubset(self.fixedVarsSet) #isFixed = lambda v: v in self._fixedVars Z = dict((v, zeros_like(val) if v not in self.fixedVarsSet else val) for v, val in self._x0.items()) else: areFixed = lambda dep: dep.isdisjoint(self.freeVarsSet) #isFixed = lambda v: v not in self._freeVars Z = dict((v, zeros_like(val) if v in self.freeVarsSet else val) for v, val in self._x0.items()) Z = oopoint(Z, maxDistributionSize = self.maxDistributionSize) self._Z = Z #p.isFixed = isFixed lb, ub = -inf*ones(self.n), inf*ones(self.n) # TODO: get rid of start c, h = None, use [] instead A, b, Aeq, beq = [], [], [], [] if type(self.constraints) not in (list, tuple, set): self.constraints = [self.constraints] oovD = self._oovarsIndDict LB = {} UB = {} """ gather attached constraints """ C = list(self.constraints) self.constraints = set(self.constraints) for v in self._x0.keys(): # if v.fields != (): # v.aux_domain = Copy(v.domain) ## # TODO: mb rework it ## ind_numeric = [j for j, elem in enumerate(v.aux_domain[0]) if type(elem) not in (str, np.str_)] ## if len(ind_numeric): ## ind_first_numeric = ind_numeric[0] ## v.aux_domain.sort(key = lambda elem: elem[ind_first_numeric]) # v.domain = np.arange(len(v.domain)) if not array_equal(v.lb, -inf): self.constraints.add(v >= v.lb) if not array_equal(v.ub, inf): self.constraints.add(v <= v.ub) if self.useAttachedConstraints: if hasattr(self, 'f'): if type(self.f) in [list, tuple, set]: C += list(self.f) else: # self.f is oofun C.append(self.f) self.constraints.update(_getAllAttachedConstraints(C)) FF = self.constraints.copy() for _F in F: if isinstance(_F, (tuple, list, set)): FF.update(_F) elif isinstance(_F, ndarray): if _F.size > 1: FF.update(_F) else: FF.add(_F.item()) else: FF.add(_F) unvectorizableFuncs = set() #unvectorizableVariables = set([var for var, val in self._x0.items() if isinstance(val, _Stochastic) or asarray(val).size > 1]) # TODO: use this unvectorizableVariables = set([]) # temporary replacement: #unvectorizableVariables = set([var for var, val in self._x0.items() if asarray(val).size > 1]) cond = False #debug # unvectorizableVariables = set(self._x0.keys()) # hasVectorizableFuncs = False # cond = True #debug end if 1 and isPyPy: hasVectorizableFuncs = False unvectorizableFuncs = FF else: hasVectorizableFuncs = False if len(unvectorizableVariables) != 0: for ff in FF: _dep = ff._getDep() if cond or len(_dep & unvectorizableVariables) != 0: unvectorizableFuncs.add(ff) else: hasVectorizableFuncs = True else: hasVectorizableFuncs = True self.unvectorizableFuncs = unvectorizableFuncs self.hasVectorizableFuncs = hasVectorizableFuncs for v in self.freeVarsSet: d = v.domain if d is bool or d is 'bool': self.constraints.update([v>0, v<1]) elif d is not None and d is not int and d is not 'int': # TODO: mb add integer domains? v.domain = array(list(d)) v.domain.sort() self.constraints.update([v >= v.domain[0], v <= v.domain[-1]]) if hasattr(v, 'aux_domain'): self.constraints.add(v <= len(v.aux_domain)-1) # for v in self._stringVars: # if isFixed(v): # ind = searchsorted(v.aux_domain, p._x0[v], 'left') # if v.aux_domain """ handling constraints """ StartPointVars = set(self._x0.keys()) self.dictOfFixedFuncs = {} from FuncDesigner import broadcast if self.probType in ['SLE', 'NLSP', 'SNLE', 'LLSP']: for eq in equations: broadcast(formDictOfFixedFuncs, eq, self.useAttachedConstraints, self.dictOfFixedFuncs, areFixed, self._x0) else: broadcast(formDictOfFixedFuncs, self.f, self.useAttachedConstraints, self.dictOfFixedFuncs, areFixed, self._x0) if oosolver(self.solver).useLinePoints: self._firstLinePointDict = {} self._secondLinePointDict = {} self._currLinePointDict = {} inplaceLinearRender = oosolver(self.solver).__name__ == 'interalg' if inplaceLinearRender and hasattr(self, 'f'): D_kwargs2 = D_kwargs.copy() D_kwargs2['useSparse'] = False if type(self.f) in [list, tuple, set]: ff = [] for f in self.f: if f.getOrder(self.freeVarsSet, self.fixedVarsSet, fixedVarsScheduleID = self._FDVarsID) < 2: D = f.D(Z, **D_kwargs2) f2 = linear_render(f, D, Z) ff.append(f2) else: ff.append(f) self.f = ff else: # self.f is oofun if self.f.getOrder(self.freeVarsSet, self.fixedVarsSet, fixedVarsScheduleID = self._FDVarsID) < 2: D = self.f.D(Z, **D_kwargs2) self.f = linear_render(self.f, D, Z) if self.isObjFunValueASingleNumber: self._linear_objective = True self._linear_objective_factor = self._pointDerivative2array(D).flatten() self._linear_objective_scalar = self.f(Z) handleConstraint_args = (StartPointVars, areFixed, oovD, A, b, Aeq, beq, Z, D_kwargs, LB, UB, inplaceLinearRender) for c in self.constraints: if isinstance(c, ooarray): for elem in c: self.handleConstraint(elem, *handleConstraint_args) elif c is True: continue elif c is False: self.err('one of elements from constraints is "False", solution is impossible') elif not hasattr(c, 'isConstraint'): self.err('The type ' + str(type(c)) + ' is inappropriate for problem constraints') else: self.handleConstraint(c, *handleConstraint_args) if len(b) != 0: self.A, self.b = Vstack(A), Hstack([asfarray(elem).flatten() for elem in b])#Vstack(b).flatten() if hasattr(self.b, 'toarray'): self.b = self.b.toarray() if len(beq) != 0: self.Aeq, self.beq = Vstack(Aeq), Hstack([ravel(elem) for elem in beq])#Vstack(beq).flatten() if hasattr(self.beq, 'toarray'): self.beq = self.beq.toarray() for vName, vVal in LB.items(): inds = oovD[vName] lb[inds[0]:inds[1]] = vVal for vName, vVal in UB.items(): inds = oovD[vName] ub[inds[0]:inds[1]] = vVal self.lb, self.ub = lb, ub else: # not FuncDesigner if self.fixedVars is not None or self.freeVars is not None: self.err('fixedVars and freeVars are valid for optimization of FuncDesigner models only') if self.x0 is None: arr = ['lb', 'ub'] if self.probType in ['LP', 'MILP', 'QP', 'SOCP', 'SDP']: arr.append('f') if self.probType in ['LLSP', 'LLAVP', 'LUNP']: arr.append('D') for fn in arr: if not hasattr(self, fn): continue tmp = getattr(self, fn) fv = asarray(tmp) if not isspmatrix(tmp) else tmp.A if any(isfinite(fv)): self.x0 = np.zeros(fv.size) break self.x0 = ravel(self.x0) if not hasattr(self, 'n'): self.n = self.x0.size if not hasattr(self, 'lb'): self.lb = -inf * ones(self.n) if not hasattr(self, 'ub'): self.ub = inf * ones(self.n) for fn in ('A', 'Aeq'): fv = getattr(self, fn) if fv is not None: #afv = asfarray(fv) if not isspmatrix(fv) else fv.toarray() # TODO: omit casting to dense matrix afv = asfarray(fv) if type(fv) in [list, tuple] else fv if len(afv.shape) > 1: if afv.shape[1] != self.n: self.err('incorrect ' + fn + ' size') else: if afv.shape != () and afv.shape[0] == self.n: afv = afv.reshape(1, self.n) setattr(self, fn, afv) else: setattr(self, fn, asfarray([]).reshape(0, self.n)) nA, nAeq = prod(self.A.shape), prod(self.Aeq.shape) SizeThreshold = 2 ** 15 if scipyInstalled: from scipy.sparse import csc_matrix if isspmatrix(self.A) or (nA > SizeThreshold and np.flatnonzero(self.A).size < 0.25*nA): self._A = csc_matrix(self.A) if isspmatrix(self.Aeq) or (nAeq > SizeThreshold and np.flatnonzero(self.Aeq).size < 0.25*nAeq): self._Aeq = csc_matrix(self.Aeq) elif nA > SizeThreshold or nAeq > SizeThreshold: self.pWarn(scipyAbsentMsg) self._baseProblemIsPrepared = True
class SLE(MatrixProblem): expectedArgs = ['C', 'd']# for FD it should be Cd and x0 probType = 'SLE' goal = 'solution' allowedGoals = ['solution'] showGoal = False FuncDesignerSign = 'C' solver = 'defaultSLEsolver' _optionalData = [] _isPrepared = False def __init__(self, *args, **kwargs): MatrixProblem.__init__(self, *args, **kwargs) _useSparse = lambda self: True if (scipyInstalled and self.n > 100) else False def objFunc(self, x): if isinstance(self.C, ndarray): return norm(dot(self.C, x) - self.d, inf) else: # TODO: omit code clone in FD ooFun.py, function _D t1 = self.C_as_csc t2 = scipy.sparse.csr_matrix(x) if t2.shape[0] != t1.shape[1]: if t2.shape[1] == t1.shape[1]: t2 = t2.T else: raise FuncDesignerException('incorrect shape in FuncDesigner function _D(), inform developers about the bug') rr = t1._mul_sparse_matrix(t2) return norm(rr.toarray().flatten() - self.d, inf) def _Prepare(self): if self._isPrepared: return self._isPrepared = True if isinstance(self.d, dict): # FuncDesigner startPoint self.x0 = self.d MatrixProblem._Prepare(self) if self.isFDmodel: equations = self.C AsSparse = bool(self.useSparse) if type(self.useSparse) != str else self._useSparse() C, d = [], [] if len(self._fixedVars) < len(self._freeVars): Z = dict([(v, zeros_like(self._x0[v]) if v not in self._fixedVars else self._x0[v]) for v in self._x0.keys()]) else: Z = dict([(v, zeros_like(self._x0[v]) if v in self._freeVars else self._x0[v]) for v in self._x0.keys()]) #Z = self.x0#self._vector2point(zeros(self.n)) for lin_oofun in equations: if lin_oofun.getOrder(self.freeVars, self.fixedVars) > 1: raise OpenOptException('SLE constructor requires all equations to be linear') C.append(self._pointDerivative2array(lin_oofun.D(Z, **self._D_kwargs), useSparse = AsSparse)) d.append(-lin_oofun(Z)) self.d = hstack(d).flatten() self.C = Vstack(C) if hasattr(self.C, 'tocsc'): self.C_as_csc = self.C.tocsc() if isinstance(self.C,ndarray) and self.n > 100 and len(flatnonzero(self.C))/self.C.size < 0.3: s = "Probably you'd better solve this SLE as sparse" if not scipyInstalled: s += ' (requires scipy installed)' self.pWarn(s) self.x0 = zeros(self.C.shape[1])
class SLE(MatrixProblem): expectedArgs = ['C', 'd']# for FD it should be Cd and x0 probType = 'SLE' goal = 'solution' allowedGoals = ['solution'] showGoal = False FuncDesignerSign = 'C' solver = 'defaultSLEsolver' _optionalData = [] _isPrepared = False def __init__(self, *args, **kwargs): MatrixProblem.__init__(self, *args, **kwargs) _useSparse = lambda self: True if (scipyInstalled and self.n > 100) else False def objFunc(self, x): if isinstance(self.C, ndarray): return norm(dot(self.C, x) - self.d, inf) else: # TODO: omit code clone in FD ooFun.py, function _D t1 = self.C_as_csc t2 = csr_matrix(x) if t2.shape[0] != t1.shape[1]: assert t2.shape[1] == t1.shape[1], 'incorrect shape in OpenOpt SLE, inform developers about the bug' t2 = t2.T rr = t1._mul_sparse_matrix(t2) return norm(rr.toarray().flatten() - self.d, inf) def _Prepare(self): if self._isPrepared: return self._isPrepared = True if isinstance(self.d, dict): # FuncDesigner startPoint self.x0 = self.d MatrixProblem._Prepare(self) if self.isFDmodel: equations = self.C AsSparse = bool(self.useSparse) if type(self.useSparse) != str else self._useSparse() C, d = [], [] if len(self._fixedVars) < len(self._freeVars): Z = dict([(v, zeros_like(self._x0[v]) if v not in self._fixedVars else self._x0[v]) for v in self._x0.keys()]) else: Z = dict([(v, zeros_like(self._x0[v]) if v in self._freeVars else self._x0[v]) for v in self._x0.keys()]) #Z = self.x0#self._vector2point(zeros(self.n)) for lin_oofun in equations: if lin_oofun.getOrder(self.freeVars, self.fixedVars) > 1: raise OpenOptException('SLE constructor requires all equations to be linear') C.append(self._pointDerivative2array(lin_oofun.D(Z, **self._D_kwargs), useSparse = AsSparse)) d.append(-lin_oofun(Z)) self.d = hstack(d).flatten() self.C = Vstack(C) if hasattr(self.C, 'tocsc'): self.C_as_csc = self.C.tocsc() if isinstance(self.C,ndarray) and self.n > 100 and len(flatnonzero(self.C))/self.C.size < 0.3: s = "Probably you'd better solve this SLE as sparse" if not scipyInstalled: s += ' (requires scipy installed)' self.pWarn(s) self.x0 = zeros(self.C.shape[1])
def wrapped_1st_derivatives(p, x, ind_, funcType, ignorePrev, useSparse): if isinstance(x, dict): if not p.isFDmodel: p.err( 'calling the function with argument of type dict is allowed for FuncDesigner models only' ) if ind_ is not None: p.err( 'the operation is turned off for argument of type dict when ind!=None' ) x = p._point2vector(x) if ind_ is not None: ind = p.getCorrectInd(ind_) else: ind = None if p.istop == USER_DEMAND_EXIT: if p.solver.useStopByException: raise killThread else: return nan derivativesType = 'd' + funcType prevKey = p.prevVal[derivativesType]['key'] if prevKey is not None and p.iter > 0 and array_equal( x, prevKey) and ind is None and not ignorePrev: #TODO: add counter of the situations assert p.prevVal[derivativesType]['val'] is not None return copy(p.prevVal[derivativesType]['val']) if ind is None and not ignorePrev: p.prevVal[derivativesType]['ind'] = copy(x) #TODO: patterns! nFuncs = getattr(p, 'n' + funcType) x = atleast_1d(x) if hasattr(p.userProvided, derivativesType) and getattr( p.userProvided, derivativesType): funcs = getattr(p.user, derivativesType) if ind is None or (nFuncs == 1 and p.functype[funcType] == 'single func'): Funcs = funcs elif ind is not None and p.functype[ funcType] == 'some funcs R^nvars -> R': Funcs = [funcs[i] for i in ind] else: Funcs = getFuncsAndExtractIndexes(p, funcs, ind, funcType) # if ind is None: derivativesNumber = nFuncs # else: derivativesNumber = len(ind) #derivatives = empty((derivativesNumber, p.n)) derivatives = [] #agregate_counter = 0 for fun in Funcs: #getattr(p.user, derivativesType): tmp = atleast_1d(fun(*(x, ) + getattr(p.args, funcType))) # TODO: replace tmp.size here for sparse matrices #assert tmp.size % p.n == mod(tmp.size, p.n) if tmp.size % p.n != 0: if funcType == 'f': p.err( 'incorrect user-supplied (sub)gradient size of objective function' ) elif funcType == 'c': p.err( 'incorrect user-supplied (sub)gradient size of non-lin inequality constraints' ) elif funcType == 'h': p.err( 'incorrect user-supplied (sub)gradient size of non-lin equality constraints' ) if tmp.ndim == 1: m = 1 else: m = tmp.shape[0] if p.functype[funcType] == 'some funcs R^nvars -> R' and m != 1: # TODO: more exact check according to stored p.arr_of_indexes_* arrays p.err( 'incorrect shape of user-supplied derivative, it should be in accordance with user-provided func size' ) derivatives.append(tmp) #derivatives[agregate_counter : agregate_counter + m] = tmp#.reshape(tmp.size/p.n,p.n) #agregate_counter += m #TODO: inline ind modification!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! derivatives = Vstack(derivatives) if any( isspmatrix(derivatives)) else vstack(derivatives) if ind is None: p.nEvals[derivativesType] += 1 else: #derivatives = derivatives[ind] p.nEvals[derivativesType] = p.nEvals[derivativesType] + float( len(ind)) / nFuncs if funcType == 'f': if p.invertObjFunc: derivatives = -derivatives if p.isObjFunValueASingleNumber: if not isinstance(derivatives, ndarray): derivatives = derivatives.toarray() derivatives = derivatives.flatten() else: #if not getattr(p.userProvided, derivativesType) or p.isFDmodel: # x, IND, userFunctionType, ignorePrev, getDerivative derivatives = p.wrapped_func(x, ind, funcType, True, True) if ind is None: p.nEvals[derivativesType] -= 1 else: p.nEvals[derivativesType] = p.nEvals[derivativesType] - float( len(ind)) / nFuncs #else: if useSparse is False or not scipyInstalled or not hasattr( p, 'solver') or not p.solver._canHandleScipySparse: # p can has no attr 'solver' if it is called from checkdf, checkdc, checkdh if not isinstance(derivatives, ndarray): derivatives = derivatives.toarray() # if min(derivatives.shape) == 1: # if isspmatrix(derivatives): derivatives = derivatives.A # derivatives = derivatives.flatten() if type(derivatives) != ndarray and isinstance( derivatives, ndarray): # dense numpy matrix derivatives = derivatives.A if ind is None and not ignorePrev: p.prevVal[derivativesType]['val'] = derivatives if funcType == 'f': if hasattr( p, 'solver' ) and not p.solver.iterfcnConnected and p.solver.funcForIterFcnConnection == 'df': if p.df_iter is True: p.iterfcn(x) elif p.nEvals[derivativesType] % p.df_iter == 0: p.iterfcn(x) # call iterfcn each {p.df_iter}-th df call if p.isObjFunValueASingleNumber and type( derivatives) == ndarray and derivatives.ndim > 1: derivatives = derivatives.flatten() return derivatives
def wrapped_func(p, x, IND, userFunctionType, ignorePrev, getDerivative): #, _linePointDescriptor = None): if isinstance(x, dict): if not p.isFDmodel: p.err( 'calling the function with argument of type dict is allowed for FuncDesigner models only' ) x = p._point2vector(x) if not getattr(p.userProvided, userFunctionType): return array([]) if p.istop == USER_DEMAND_EXIT: if p.solver.useStopByException: raise killThread else: return nan if getDerivative and not p.isFDmodel and not DerApproximatorIsInstalled: p.err( 'For the problem you should have DerApproximator installed, see http://openopt.org/DerApproximator' ) #userFunctionType should be 'f', 'c', 'h' funcs = getattr(p.user, userFunctionType) #funcs_num = getattr(p, 'n'+userFunctionType) if IND is not None: ind = p.getCorrectInd(IND) else: ind = None # this line had been added because some solvers pass tuple instead of # x being vector p.n x 1 or matrix X=[x1 x2 x3...xk], size(X)=[p.n, k] if not isspmatrix(x): x = atleast_1d(x) # if not str(x.dtype).startswith('float'): # x = asfarray(x) else: if p.debug: p.pWarn( '[oo debug] sparse matrix x in nonlinfuncs.py has been encountered' ) # if not ignorePrev: # prevKey = p.prevVal[userFunctionType]['key'] # else: # prevKey = None # # # TODO: move it into runprobsolver or baseproblem # if p.prevVal[userFunctionType]['val'] is None: # p.prevVal[userFunctionType]['val'] = zeros(getattr(p, 'n'+userFunctionType)) # # if prevKey is not None and p.iter > 0 and array_equal(x, prevKey) and ind is None and not ignorePrev: # #TODO: add counter of the situations # if not getDerivative: # r = copy(p.prevVal[userFunctionType]['val']) # #if p.debug: assert array_equal(r, p.wrapped_func(x, IND, userFunctionType, True, getDerivative)) # if ind is not None: r = r[ind] # # if userFunctionType == 'f': # if p.isObjFunValueASingleNumber: r = r.sum(0) # if p.invertObjFunc: r = -r # if p.solver.funcForIterFcnConnection=='f' and any(isnan(x)): # p.nEvals['f'] += 1 # # if p.nEvals['f']%p.f_iter == 0: # p.iterfcn(x, fk = r) # return r args = getattr(p.args, userFunctionType) # TODO: handle it in prob prepare if not hasattr(p, 'n' + userFunctionType): setNonLinFuncsNumber(p, userFunctionType) # if ind is None: # nFuncsToObtain = getattr(p, 'n'+ userFunctionType) # else: # nFuncsToObtain = len(ind) if x.shape[0] != p.n and (x.ndim < 2 or x.shape[1] != p.n): p.err('x with incorrect shape passed to non-linear function') #TODO: code cleanup (below) if getDerivative or x.ndim <= 1 or x.shape[0] == 1: nXvectors = 1 x_0 = copy(x) else: nXvectors = x.shape[0] # TODO: use certificate instead if p.isFDmodel: if getDerivative: if p.freeVars is None or (p.fixedVars is not None and len(p.freeVars) < len(p.fixedVars)): funcs2 = [(lambda x, i=i: \ p._pointDerivative2array( funcs[i].D(x, Vars = p.freeVars, useSparse=p.useSparse, fixedVarsScheduleID=p._FDVarsID, exactShape=True), useSparse=p.useSparse, func=funcs[i], point=x)) \ for i in range(len(funcs))] else: funcs2 = [(lambda x, i=i: \ p._pointDerivative2array( funcs[i].D(x, fixedVars = p.fixedVars, useSparse=p.useSparse, fixedVarsScheduleID=p._FDVarsID, exactShape=True), useSparse=p.useSparse, func=funcs[i], point=x)) \ for i in range(len(funcs))] else: if p.freeVars is None or (p.fixedVars is not None and len(p.freeVars) < len(p.fixedVars)): funcs2 = [(lambda x, i=i: \ funcs[i]._getFuncCalcEngine(x, Vars = p.freeVars, fixedVarsScheduleID=p._FDVarsID))\ for i in range(len(funcs))] else: funcs2 = [(lambda x, i=i: \ funcs[i]._getFuncCalcEngine(x, fixedVars = p.fixedVars, fixedVarsScheduleID=p._FDVarsID))\ for i in range(len(funcs))] else: funcs2 = funcs if ind is None: Funcs = funcs2 elif ind is not None and p.functype[ userFunctionType] == 'some funcs R^nvars -> R': Funcs = [funcs2[i] for i in ind] else: Funcs = getFuncsAndExtractIndexes(p, funcs2, ind, userFunctionType) # agregate_counter = 0 Args = () if p.isFDmodel else args if nXvectors == 1: if p.isFDmodel: X = p._vector2point(x) X._p = p #X._linePointDescriptor = _linePointDescriptor else: X = x if nXvectors > 1: # and hence getDerivative isn't involved #temporary, to be fixed if userFunctionType == 'f': assert p.isObjFunValueASingleNumber if p.isFDmodel: assert ind is None if isPyPy or p.hasVectorizableFuncs: # TODO: get rid of box-bound constraints from FuncDesigner.ooPoint import ooPoint as oopoint from FuncDesigner.multiarray import multiarray # TODO: new xx = [] counter = 0 #xT = x.T for i, oov in enumerate(p._freeVarsList): s = p._optVarSizes[oov] xx.append( (oov, (x[:, counter:counter + s].flatten() if s == 1 else x[:, counter:counter + s]).view(multiarray))) # xx.append((oov, multiarray(x[:, counter: counter + s].flatten() if s == 1 else x[:, counter: counter + s]))) counter += s X = oopoint(xx) X.update(p.dictOfFixedFuncs) X.maxDistributionSize = p.maxDistributionSize X._p = p if len(p.unvectorizableFuncs) != 0: XX = [p._vector2point(x[i]) for i in range(nXvectors)] for _X in XX: _X._p = p _X.update(p.dictOfFixedFuncs) r = vstack([[fun(xx) for xx in XX] if funcs[i] in p.unvectorizableFuncs else fun(X).T for i, fun in enumerate(Funcs)]).T # X = [p._vector2point(x[i]) for i in range(nXvectors)] # r = hstack([[fun(xx) for xx in X] for fun in Funcs]).reshape(1, -1) #new # if p.vectorizable: # from FuncDesigner.ooPoint import ooPoint as oopoint, multiarray # # X = dict([(oovar, x[:, i].view(multiarray)) for i, oovar in enumerate(p._freeVarsList)]) # X = oopoint(X, skipArrayCast = True) # X.N = nXvectors # X.isMultiPoint = True # X.update(p.dictOfFixedFuncs) # r = hstack([fun(X) for fun in Funcs]).reshape(1, -1) # # #old # else: # X = [p._vector2point(x[i]) for i in range(nXvectors)] # r = hstack([[fun(xx) for xx in X] for fun in Funcs]).reshape(1, -1) else: X = [(x[i], ) + Args for i in range(nXvectors)] #r = hstack([[fun(*xx) for xx in X] for fun in Funcs]) R = [] for xx in X: tmp = [fun(*xx) for fun in Funcs] r_ = hstack(tmp[0]) if len(tmp) == 1 and isinstance( tmp[0], (list, tuple)) else hstack(tmp) if len(tmp) > 1 else tmp[0] R.append(r_) r = hstack(R) #.T #print(r.shape, userFunctionType) elif not getDerivative: tmp = [fun(*(X, ) + Args) for fun in Funcs] r = hstack(tmp[0]) if len(tmp) == 1 and isinstance( tmp[0], (list, tuple)) else hstack(tmp) if len(tmp) > 1 else tmp[0] #print(x.shape, r.shape, x, r) # if not ignorePrev and ind is None: # p.prevVal[userFunctionType]['key'] = copy(x_0) # p.prevVal[userFunctionType]['val'] = r.copy() elif getDerivative and p.isFDmodel: rr = [fun(X) for fun in Funcs] r = Vstack(rr) if scipyInstalled and any( [isspmatrix(elem) for elem in rr]) else vstack(rr) else: r = [] if getDerivative: #r = zeros((nFuncsToObtain, p.n)) diffInt = p.diffInt abs_x = abs(x) finiteDiffNumbers = 1e-10 * abs_x if p.diffInt.size == 1: finiteDiffNumbers[finiteDiffNumbers < diffInt] = diffInt else: finiteDiffNumbers[finiteDiffNumbers < diffInt] = diffInt[ finiteDiffNumbers < diffInt] else: #r = zeros((nFuncsToObtain, nXvectors)) r = [] for index, fun in enumerate(Funcs): # OLD # v = ravel(fun(*((X,) + Args))) # if (ind is None or funcs_num == 1) and not ignorePrev: # #TODO: ADD COUNTER OF THE CASE # if index == 0: p.prevVal[userFunctionType]['key'] = copy(x_0) # p.prevVal[userFunctionType]['val'][agregate_counter:agregate_counter+v.size] = v.copy() # r[agregate_counter:agregate_counter+v.size,0] = v #NEW if not getDerivative: r.append(fun(*((X, ) + Args))) # v = r[-1] #r[agregate_counter:agregate_counter+v.size,0] = fun(*((X,) + Args)) # if (ind is None or funcs_num == 1) and not ignorePrev: # #TODO: ADD COUNTER OF THE CASE # if index == 0: p.prevVal[userFunctionType]['key'] = copy(x_0) # p.prevVal[userFunctionType]['val'][agregate_counter:agregate_counter+v.size] = v.copy() """ getting derivatives """ if getDerivative: def func(x): r = fun(*((x, ) + Args)) return r if type(r) not in ( list, tuple) or len(r) != 1 else r[0] d1 = get_d1(func, x, pointVal=None, diffInt=finiteDiffNumbers, stencil=p.JacobianApproximationStencil, exactShape=True) #r[agregate_counter:agregate_counter+d1.size] = d1 r.append(d1) # v = r[-1] # agregate_counter += atleast_1d(v).shape[0] r = hstack(r) if not getDerivative else vstack(r) #assert r.size != 30 #if type(r) == matrix: r = r.A if type(r) != ndarray and not isscalar(r): # multiarray r = r.view(ndarray).flatten( ) if userFunctionType == 'f' else r.view(ndarray) #elif userFunctionType == 'f' and p.isObjFunValueASingleNumber and prod(r.shape) > 1 and (type(r) == ndarray or min(r.shape) > 1): #r = r.sum(0) elif userFunctionType == 'f' and p.isObjFunValueASingleNumber and not isscalar( r): if prod(r.shape) > 1 and not getDerivative and nXvectors == 1: p.err( 'implicit summation in objective is no longer available to prevent possibly hidden bugs' ) # if r.size == 1: # r = r.item() if userFunctionType == 'f' and p.isObjFunValueASingleNumber: if getDerivative and r.ndim > 1: if min(r.shape) > 1: p.err('incorrect shape of objective func derivative') # TODO: omit cast to dense array. Somewhere bug triggers? if hasattr(r, 'toarray'): r = r.toarray() r = r.flatten() if userFunctionType != 'f' and nXvectors != 1: r = r.reshape(nXvectors, int(r.size / nXvectors)) # if type(r) == matrix: # raise 0 # r = r.A # if _dense_numpy_matrix ! if nXvectors == 1 and (not getDerivative or prod( r.shape) == 1): # DO NOT REPLACE BY r.size - r may be sparse! r = r.flatten() if type(r) == ndarray else r.toarray().flatten( ) if not isscalar(r) else atleast_1d(r) if p.invertObjFunc and userFunctionType == 'f': r = -r if not getDerivative: if ind is None: p.nEvals[userFunctionType] += nXvectors else: p.nEvals[userFunctionType] = p.nEvals[userFunctionType] + float( nXvectors * len(ind)) / getattr(p, 'n' + userFunctionType) if getDerivative: assert x.size == p.n #TODO: add python list possibility here x = x_0 # for to suppress numerical instability effects while x +/- delta_x #if userFunctionType == 'f' and p.isObjFunValueASingleNumber and r.size == 1: #r = r.item() if userFunctionType == 'f' and hasattr( p, 'solver' ) and p.solver.funcForIterFcnConnection == 'f' and hasattr( p, 'f_iter') and not getDerivative: if p.nEvals['f'] % p.f_iter == 0 or nXvectors > 1: p.iterfcn(x, r) return r
def xBounds2Matrix(p): """ transforms lb - ub bounds into (A, x) <= b, (Aeq, x) = beq conditions this func is developed for those solvers that can handle lb, ub only via c(x)<=0, h(x)=0 """ #TODO: is reshape/flatten required in newest numpy versions? # for PyPy IndLB, IndUB, IndEQ = \ isfinite(p.lb) & ~(p.lb == p.ub), \ isfinite(p.ub) & ~(p.lb == p.ub), \ p.lb == p.ub indLB, indUB, indEQ = \ where(IndLB)[0], \ where(IndUB)[0], \ where(IndEQ)[0] nLB, nUB, nEQ = Len(indLB), Len(indUB), Len(indEQ) if nLB > 0 or nUB > 0: if p.useSparse is True or (isspmatrix( p.A) or (scipyInstalled and nLB + nUB >= p.A.shape[0]) and p.useSparse is not False): R1 = coo_matrix( (-ones(nLB), (range(nLB), indLB)), shape=(nLB, p.n)) if nLB != 0 else zeros( (0, p.n)) R2 = coo_matrix( (ones(nUB), (range(nUB), indUB)), shape=(nUB, p.n)) if nUB != 0 else zeros( (0, p.n)) else: R1 = zeros((nLB, p.n)) if isPyPy: for i in range(nLB): R1[i, indLB[i]] = -1 else: R1[range(nLB), indLB] = -1 R2 = zeros((nUB, p.n)) if isPyPy: for i in range(nUB): R2[i, indUB[i]] = -1 else: R2[range(nUB), indUB] = 1 p.A = Vstack((p.A, R1, R2)) if hasattr(p, '_A'): delattr(p, '_A') if isspmatrix(p.A): if prod(p.A.shape) > 10000: p.A = p.A.tocsc() p._A = p.A else: p.A = p.A.A p.b = Hstack((p.b, -p.lb[IndLB], p.ub[IndUB])) if nEQ > 0: if p.useSparse is True or (isspmatrix(p.Aeq) or (scipyInstalled and nEQ >= p.Aeq.shape[0]) and p.useSparse is not False): R = coo_matrix(([1] * nEQ, (range(nEQ), indEQ)), shape=(nEQ, p.n)) else: R = zeros((nEQ, p.n)) #raise 0 p.Aeq = Vstack((p.Aeq, R)) if hasattr(p, '_Aeq'): delattr(p, '_Aeq') if isspmatrix(p.Aeq): if prod(p.Aeq.shape) > 10000: p.Aeq = p.Aeq.tocsc() p._Aeq = p.Aeq else: p.Aeq = p.Aeq.A p.beq = Hstack((p.beq, p.lb[IndEQ])) p.lb = -inf * ones(p.n) p.ub = inf * ones(p.n) # TODO: prevent code clone with baseProblem.py nA, nAeq = prod(p.A.shape), prod(p.Aeq.shape) SizeThreshold = 2**15 if scipyInstalled and p.useSparse is not False: from scipy.sparse import csc_matrix if nA > SizeThreshold and not isspmatrix( p.A) and flatnonzero(p.A).size < 0.25 * nA: p._A = csc_matrix(p.A) if nAeq > SizeThreshold and not isspmatrix( p.Aeq) and flatnonzero(p.Aeq).size < 0.25 * nAeq: p._Aeq = csc_matrix(p.Aeq) if (nA > SizeThreshold or nAeq > SizeThreshold ) and not scipyInstalled and p.useSparse is not False: p.pWarn(scipyAbsentMsg)
def wrapped_1st_derivatives(p, x, ind_, funcType, ignorePrev, useSparse): if isinstance(x, dict): if not p.isFDmodel: p.err('calling the function with argument of type dict is allowed for FuncDesigner models only') if ind_ is not None:p.err('the operation is turned off for argument of type dict when ind!=None') x = p._point2vector(x) if ind_ is not None: ind = p.getCorrectInd(ind_) else: ind = None if p.istop == USER_DEMAND_EXIT: if p.solver.useStopByException: raise killThread else: return nan derivativesType = 'd'+ funcType prevKey = p.prevVal[derivativesType]['key'] if prevKey is not None and p.iter > 0 and array_equal(x, prevKey) and ind is None and not ignorePrev: #TODO: add counter of the situations assert p.prevVal[derivativesType]['val'] is not None return copy(p.prevVal[derivativesType]['val']) if ind is None and not ignorePrev: p.prevVal[derivativesType]['ind'] = copy(x) #TODO: patterns! nFuncs = getattr(p, 'n'+funcType) x = atleast_1d(x) if hasattr(p.userProvided, derivativesType) and getattr(p.userProvided, derivativesType): funcs = getattr(p.user, derivativesType) if ind is None or (nFuncs == 1 and p.functype[funcType] == 'single func'): Funcs = funcs elif ind is not None and p.functype[funcType] == 'some funcs R^nvars -> R': Funcs = [funcs[i] for i in ind] else: Funcs = getFuncsAndExtractIndexes(p, funcs, ind, funcType) # if ind is None: derivativesNumber = nFuncs # else: derivativesNumber = len(ind) #derivatives = empty((derivativesNumber, p.n)) derivatives = [] #agregate_counter = 0 for fun in Funcs:#getattr(p.user, derivativesType): tmp = atleast_1d(fun(*(x,)+getattr(p.args, funcType))) # TODO: replace tmp.size here for sparse matrices #assert tmp.size % p.n == mod(tmp.size, p.n) if tmp.size % p.n != 0: if funcType=='f': p.err('incorrect user-supplied (sub)gradient size of objective function') elif funcType=='c': p.err('incorrect user-supplied (sub)gradient size of non-lin inequality constraints') elif funcType=='h': p.err('incorrect user-supplied (sub)gradient size of non-lin equality constraints') if tmp.ndim == 1: m= 1 else: m = tmp.shape[0] if p.functype[funcType] == 'some funcs R^nvars -> R' and m != 1: # TODO: more exact check according to stored p.arr_of_indexes_* arrays p.err('incorrect shape of user-supplied derivative, it should be in accordance with user-provided func size') derivatives.append(tmp) #derivatives[agregate_counter : agregate_counter + m] = tmp#.reshape(tmp.size/p.n,p.n) #agregate_counter += m #TODO: inline ind modification!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! derivatives = Vstack(derivatives) if any(isspmatrix(derivatives)) else vstack(derivatives) if ind is None: p.nEvals[derivativesType] += 1 else: #derivatives = derivatives[ind] p.nEvals[derivativesType] = p.nEvals[derivativesType] + float(len(ind)) / nFuncs if funcType=='f': if p.invertObjFunc: derivatives = -derivatives if p.isObjFunValueASingleNumber: if not isinstance(derivatives, ndarray): derivatives = derivatives.toarray() derivatives = derivatives.flatten() else: #if not getattr(p.userProvided, derivativesType) or p.isFDmodel: # x, IND, userFunctionType, ignorePrev, getDerivative derivatives = p.wrapped_func(x, ind, funcType, True, True) if ind is None: p.nEvals[derivativesType] -= 1 else: p.nEvals[derivativesType] = p.nEvals[derivativesType] - float(len(ind)) / nFuncs #else: if useSparse is False or not scipyInstalled or not hasattr(p, 'solver') or not p.solver._canHandleScipySparse: # p can has no attr 'solver' if it is called from checkdf, checkdc, checkdh if not isinstance(derivatives, ndarray): derivatives = derivatives.toarray() # if min(derivatives.shape) == 1: # if isspmatrix(derivatives): derivatives = derivatives.A # derivatives = derivatives.flatten() if type(derivatives) != ndarray and isinstance(derivatives, ndarray): # dense numpy matrix derivatives = derivatives.A if ind is None and not ignorePrev: p.prevVal[derivativesType]['val'] = derivatives if funcType=='f': if hasattr(p, 'solver') and not p.solver.iterfcnConnected and p.solver.funcForIterFcnConnection=='df': if p.df_iter is True: p.iterfcn(x) elif p.nEvals[derivativesType]%p.df_iter == 0: p.iterfcn(x) # call iterfcn each {p.df_iter}-th df call if p.isObjFunValueASingleNumber and type(derivatives) == ndarray and derivatives.ndim > 1: derivatives = derivatives.flatten() return derivatives
def wrapped_func(p, x, IND, userFunctionType, ignorePrev, getDerivative):#, _linePointDescriptor = None): if isinstance(x, dict): if not p.isFDmodel: p.err('calling the function with argument of type dict is allowed for FuncDesigner models only') x = p._point2vector(x) if not getattr(p.userProvided, userFunctionType): return array([]) if p.istop == USER_DEMAND_EXIT: if p.solver.useStopByException: raise killThread else: return nan if getDerivative and not p.isFDmodel and not DerApproximatorIsInstalled: p.err('For the problem you should have DerApproximator installed, see http://openopt.org/DerApproximator') #userFunctionType should be 'f', 'c', 'h' funcs = getattr(p.user, userFunctionType) #funcs_num = getattr(p, 'n'+userFunctionType) if IND is not None: ind = p.getCorrectInd(IND) else: ind = None # this line had been added because some solvers pass tuple instead of # x being vector p.n x 1 or matrix X=[x1 x2 x3...xk], size(X)=[p.n, k] if not isspmatrix(x): x = atleast_1d(x) # if not str(x.dtype).startswith('float'): # x = asfarray(x) else: if p.debug: p.pWarn('[oo debug] sparse matrix x in nonlinfuncs.py has been encountered') # if not ignorePrev: # prevKey = p.prevVal[userFunctionType]['key'] # else: # prevKey = None # # # TODO: move it into runprobsolver or baseproblem # if p.prevVal[userFunctionType]['val'] is None: # p.prevVal[userFunctionType]['val'] = zeros(getattr(p, 'n'+userFunctionType)) # # if prevKey is not None and p.iter > 0 and array_equal(x, prevKey) and ind is None and not ignorePrev: # #TODO: add counter of the situations # if not getDerivative: # r = copy(p.prevVal[userFunctionType]['val']) # #if p.debug: assert array_equal(r, p.wrapped_func(x, IND, userFunctionType, True, getDerivative)) # if ind is not None: r = r[ind] # # if userFunctionType == 'f': # if p.isObjFunValueASingleNumber: r = r.sum(0) # if p.invertObjFunc: r = -r # if p.solver.funcForIterFcnConnection=='f' and any(isnan(x)): # p.nEvals['f'] += 1 # # if p.nEvals['f']%p.f_iter == 0: # p.iterfcn(x, fk = r) # return r args = getattr(p.args, userFunctionType) # TODO: handle it in prob prepare if not hasattr(p, 'n'+userFunctionType): setNonLinFuncsNumber(p, userFunctionType) # if ind is None: # nFuncsToObtain = getattr(p, 'n'+ userFunctionType) # else: # nFuncsToObtain = len(ind) if x.shape[0] != p.n and (x.ndim<2 or x.shape[1] != p.n): p.err('x with incorrect shape passed to non-linear function') #TODO: code cleanup (below) if getDerivative or x.ndim <= 1 or x.shape[0] == 1: nXvectors = 1 x_0 = copy(x) else: nXvectors = x.shape[0] # TODO: use certificate instead if p.isFDmodel: if getDerivative: if p.freeVars is None or (p.fixedVars is not None and len(p.freeVars) < len(p.fixedVars)): funcs2 = [(lambda x, i=i: \ p._pointDerivative2array( funcs[i].D(x, Vars = p.freeVars, useSparse=p.useSparse, fixedVarsScheduleID=p._FDVarsID, exactShape=True), useSparse=p.useSparse, func=funcs[i], point=x)) \ for i in range(len(funcs))] else: funcs2 = [(lambda x, i=i: \ p._pointDerivative2array( funcs[i].D(x, fixedVars = p.fixedVars, useSparse=p.useSparse, fixedVarsScheduleID=p._FDVarsID, exactShape=True), useSparse=p.useSparse, func=funcs[i], point=x)) \ for i in range(len(funcs))] else: if p.freeVars is None or (p.fixedVars is not None and len(p.freeVars) < len(p.fixedVars)): funcs2 = [(lambda x, i=i: \ funcs[i]._getFuncCalcEngine(x, Vars = p.freeVars, fixedVarsScheduleID=p._FDVarsID))\ for i in range(len(funcs))] else: funcs2 = [(lambda x, i=i: \ funcs[i]._getFuncCalcEngine(x, fixedVars = p.fixedVars, fixedVarsScheduleID=p._FDVarsID))\ for i in range(len(funcs))] else: funcs2 = funcs if ind is None: Funcs = funcs2 elif ind is not None and p.functype[userFunctionType] == 'some funcs R^nvars -> R': Funcs = [funcs2[i] for i in ind] else: Funcs = getFuncsAndExtractIndexes(p, funcs2, ind, userFunctionType) # agregate_counter = 0 Args = () if p.isFDmodel else args if nXvectors == 1: if p.isFDmodel: X = p._vector2point(x) X._p = p #X._linePointDescriptor = _linePointDescriptor else: X = x if nXvectors > 1: # and hence getDerivative isn't involved #temporary, to be fixed if userFunctionType == 'f': assert p.isObjFunValueASingleNumber if p.isFDmodel: assert ind is None if isPyPy or p.hasVectorizableFuncs: # TODO: get rid of box-bound constraints from FuncDesigner.ooPoint import ooPoint as oopoint from FuncDesigner.multiarray import multiarray # TODO: new xx = [] counter = 0 #xT = x.T for i, oov in enumerate(p._freeVarsList): s = p._optVarSizes[oov] xx.append((oov, (x[:, counter: counter + s].flatten() if s == 1 else x[:, counter: counter + s]).view(multiarray))) # xx.append((oov, multiarray(x[:, counter: counter + s].flatten() if s == 1 else x[:, counter: counter + s]))) counter += s X = oopoint(xx) X.update(p.dictOfFixedFuncs) X.maxDistributionSize = p.maxDistributionSize X._p = p if len(p.unvectorizableFuncs) != 0: XX = [p._vector2point(x[i]) for i in range(nXvectors)] for _X in XX: _X._p = p _X.update(p.dictOfFixedFuncs) r = vstack([[fun(xx) for xx in XX] if funcs[i] in p.unvectorizableFuncs else fun(X).T for i, fun in enumerate(Funcs)]).T # X = [p._vector2point(x[i]) for i in range(nXvectors)] # r = hstack([[fun(xx) for xx in X] for fun in Funcs]).reshape(1, -1) #new # if p.vectorizable: # from FuncDesigner.ooPoint import ooPoint as oopoint, multiarray # # X = dict([(oovar, x[:, i].view(multiarray)) for i, oovar in enumerate(p._freeVarsList)]) # X = oopoint(X, skipArrayCast = True) # X.N = nXvectors # X.isMultiPoint = True # X.update(p.dictOfFixedFuncs) # r = hstack([fun(X) for fun in Funcs]).reshape(1, -1) # # #old # else: # X = [p._vector2point(x[i]) for i in range(nXvectors)] # r = hstack([[fun(xx) for xx in X] for fun in Funcs]).reshape(1, -1) else: X = [(x[i],) + Args for i in range(nXvectors)] #r = hstack([[fun(*xx) for xx in X] for fun in Funcs]) R = [] for xx in X: tmp = [fun(*xx) for fun in Funcs] r_ = hstack(tmp[0]) if len(tmp) == 1 and isinstance(tmp[0], (list, tuple)) else hstack(tmp) if len(tmp) > 1 else tmp[0] R.append(r_) r = hstack(R)#.T #print(r.shape, userFunctionType) elif not getDerivative: tmp = [fun(*(X, )+Args) for fun in Funcs] r = hstack(tmp[0]) if len(tmp) == 1 and isinstance(tmp[0], (list, tuple)) else hstack(tmp) if len(tmp) > 1 else tmp[0] #print(x.shape, r.shape, x, r) # if not ignorePrev and ind is None: # p.prevVal[userFunctionType]['key'] = copy(x_0) # p.prevVal[userFunctionType]['val'] = r.copy() elif getDerivative and p.isFDmodel: rr = [fun(X) for fun in Funcs] r = Vstack(rr) if scipyInstalled and any([isspmatrix(elem) for elem in rr]) else vstack(rr) else: r = [] if getDerivative: #r = zeros((nFuncsToObtain, p.n)) diffInt = p.diffInt abs_x = abs(x) finiteDiffNumbers = 1e-10 * abs_x if p.diffInt.size == 1: finiteDiffNumbers[finiteDiffNumbers < diffInt] = diffInt else: finiteDiffNumbers[finiteDiffNumbers < diffInt] = diffInt[finiteDiffNumbers < diffInt] else: #r = zeros((nFuncsToObtain, nXvectors)) r = [] for index, fun in enumerate(Funcs): # OLD # v = ravel(fun(*((X,) + Args))) # if (ind is None or funcs_num == 1) and not ignorePrev: # #TODO: ADD COUNTER OF THE CASE # if index == 0: p.prevVal[userFunctionType]['key'] = copy(x_0) # p.prevVal[userFunctionType]['val'][agregate_counter:agregate_counter+v.size] = v.copy() # r[agregate_counter:agregate_counter+v.size,0] = v #NEW if not getDerivative: r.append(fun(*((X,) + Args))) # v = r[-1] #r[agregate_counter:agregate_counter+v.size,0] = fun(*((X,) + Args)) # if (ind is None or funcs_num == 1) and not ignorePrev: # #TODO: ADD COUNTER OF THE CASE # if index == 0: p.prevVal[userFunctionType]['key'] = copy(x_0) # p.prevVal[userFunctionType]['val'][agregate_counter:agregate_counter+v.size] = v.copy() """ getting derivatives """ if getDerivative: def func(x): r = fun(*((x,) + Args)) return r if type(r) not in (list, tuple) or len(r)!=1 else r[0] d1 = get_d1(func, x, pointVal = None, diffInt = finiteDiffNumbers, stencil=p.JacobianApproximationStencil, exactShape=True) #r[agregate_counter:agregate_counter+d1.size] = d1 r.append(d1) # v = r[-1] # agregate_counter += atleast_1d(v).shape[0] r = hstack(r) if not getDerivative else vstack(r) #assert r.size != 30 #if type(r) == matrix: r = r.A if type(r) != ndarray and not isscalar(r): # multiarray r = r.view(ndarray).flatten() if userFunctionType == 'f' else r.view(ndarray) #elif userFunctionType == 'f' and p.isObjFunValueASingleNumber and prod(r.shape) > 1 and (type(r) == ndarray or min(r.shape) > 1): #r = r.sum(0) elif userFunctionType == 'f' and p.isObjFunValueASingleNumber and not isscalar(r): if prod(r.shape) > 1 and not getDerivative and nXvectors == 1: p.err('implicit summation in objective is no longer available to prevent possibly hidden bugs') # if r.size == 1: # r = r.item() if userFunctionType == 'f' and p.isObjFunValueASingleNumber: if getDerivative and r.ndim > 1: if min(r.shape) > 1: p.err('incorrect shape of objective func derivative') # TODO: omit cast to dense array. Somewhere bug triggers? if hasattr(r, 'toarray'): r=r.toarray() r = r.flatten() if userFunctionType != 'f' and nXvectors != 1: r = r.reshape(nXvectors, int(r.size/nXvectors)) # if type(r) == matrix: # raise 0 # r = r.A # if _dense_numpy_matrix ! if nXvectors == 1 and (not getDerivative or prod(r.shape) == 1): # DO NOT REPLACE BY r.size - r may be sparse! r = r.flatten() if type(r) == ndarray else r.toarray().flatten() if not isscalar(r) else atleast_1d(r) if p.invertObjFunc and userFunctionType=='f': r = -r if not getDerivative: if ind is None: p.nEvals[userFunctionType] += nXvectors else: p.nEvals[userFunctionType] = p.nEvals[userFunctionType] + float(nXvectors * len(ind)) / getattr(p, 'n'+ userFunctionType) if getDerivative: assert x.size == p.n#TODO: add python list possibility here x = x_0 # for to suppress numerical instability effects while x +/- delta_x #if userFunctionType == 'f' and p.isObjFunValueASingleNumber and r.size == 1: #r = r.item() if userFunctionType == 'f' and hasattr(p, 'solver') and p.solver.funcForIterFcnConnection=='f' and hasattr(p, 'f_iter') and not getDerivative: if p.nEvals['f']%p.f_iter == 0 or nXvectors > 1: p.iterfcn(x, r) return r