def approx_cost_df(self,xopt): ''' A discrete approximation to the cost fn and its derivative Mainly useful for testing as it can be done faster If DerApproximator is not available, the 'full' cost function is returned, which doesn't allow a test. Check log file or try: from DerApproximator import get_d1 if you are concerned about that. ''' try: from DerApproximator import get_d1 except: self.confs.logger.error(\ "Cannot import DerApproximator for derivative approx'") J = self.cost(xopt) J_prime = self.cost_df(xopt) self.J_prime_approx = J_prime.flatten() return self.J_prime_approx self.J_prime_approx = get_d1(self.cost,xopt) return self.J_prime_approx
def approx_cost_df(self, xopt): ''' A discrete approximation to the cost fn and its derivative Mainly useful for testing as it can be done faster If DerApproximator is not available, the 'full' cost function is returned, which doesn't allow a test. Check log file or try: from DerApproximator import get_d1 if you are concerned about that. ''' try: from DerApproximator import get_d1 except: self.confs.logger.error(\ "Cannot import DerApproximator for derivative approx'") J = self.cost(xopt) J_prime = self.cost_df(xopt) self.J_prime_approx = J_prime.flatten() return self.J_prime_approx self.J_prime_approx = get_d1(self.cost, xopt) return self.J_prime_approx
def check(f, f_grad, x0, name, verbose=False): """ Checks whether gradients of function ``f`` at point x0 is same as the gradients provided by ``f_grad``. ``error`` is the difference between numerical and provided gradients. '%error' = abs(error) / numerical gradient. Parameters ---------- f : callable input function to check gradients against f_grad : callable input function which provides gradients x0 : ndarray the point at which gradients should be calculated name : list a vector with the size of the number of parameters, which provides name for each parameter. This name will be used when generating output table verbose : boolean whether to print output for each parameter separately Returns ------- avg : float average of the percentage error over all the parameters, i.e., mean(%error) """ g = f_grad(x0) if len(g) != len(x0): raise Exception('dimensions mismatch') table = Texttable() table.set_cols_align(["l", "r", "c", "c", "c"]) table.set_cols_valign(["t", "m", "b" , "r", "c"]) rows = [] rows += [["Name ", "analytical ", "numerical ", "error ", "% error "]] if verbose: print 'dimensions:', len(x0) aver_error = 0 for i in range(len(x0)): def f_i(x): return f((concatenate((x0[:i], x, x0[(i+1):])))) t = get_d1(f_i, [x0[i]]) p_errro=None if t != 0: p_errro = abs(t-g[i]) / abs(t) rows += [[name[i], g[i], t, abs(t-g[i]), p_errro]] if abs(g[i]) <1e-4 and abs(t) < 1e-4: pass else: aver_error += abs(t-g[i]) / abs(t) if verbose: print 'element:', i table.add_rows(rows) if verbose: print(table.draw()) return aver_error / len(x0)
from numpy import * from DerApproximator import get_d1 func = lambda x: (x**4).sum() x = arange(1.0, 6.0) r1 = get_d1(func, x, stencil=1, diffInt=1e-4) print( r1 ) # [ 4.00060004 32.00240008 108.00540012 256.00960016 500.0150002 ] r2 = get_d1(func, x, stencil=2, diffInt=1e-4) print( r2 ) # [ 4.00000004 32.00000008 108.00000012 256.00000016 500.0000002 ] r3 = get_d1(func, x, stencil=3, diffInt=1e-4) print(r3) # [ 4. 32. 108. 256. 500.]
def A_n_analytical(Z_f): Z_shaped = Z_f.reshape((M, Dim)) An = mdot(kernel.K(X[np.newaxis, n,:], Z_shaped), inv(kernel.K(Z_shaped, Z_shaped))) # return kernel.gradients_X_(mdot(inv(kernel.K(Z_shaped, Z_shaped)), O), Z_shaped, X[np.newaxis, n,:])- \ return kernel.gradients_X(mdot(An.T, mdot(inv(kernel.K(Z_shaped, Z_shaped)), O).T ), Z_shaped) def A_n_analytical_vec(Z_f): Z_shaped = Z_f.reshape((M, Dim)) A = mdot(kernel.K(X, Z_shaped), inv(kernel.K(Z_shaped, Z_shaped))) An = mdot(kernel.K(X[np.newaxis, n,:], Z_shaped), inv(kernel.K(Z_shaped, Z_shaped))) # return (kernel.get_gradients_X_AK(mdot(inv(kernel.K(Z_shaped, Z_shaped)), O).repeat(N, 1), Z_shaped, X)) - \ return kernel.get_gradients_X_SKD(A, mdot(inv(kernel.K(Z_shaped, Z_shaped)), O).repeat(N, 1), Z_shaped)[1,:,:] print get_d1(A_n, Z.flatten()).reshape((M, Dim)) print print A_n_analytical(Z.flatten()) print A_n_analytical_vec(Z.flatten()) O1 = np.random.normal(0, 1, M) \ .reshape((M, 1)) O2 = np.random.normal(0, 1, M) \ .reshape((M, 1)) OO = np.random.normal(0, 1, M * M) \ .reshape((M, M))
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 getDerivativeSelf(Self, x, fixedVarsScheduleID, Vars, fixedVars): Input = Self._getInput(x, fixedVarsScheduleID=fixedVarsScheduleID, Vars=Vars, fixedVars=fixedVars) expectedTotalInputLength = sum([Len(elem) for elem in Input]) # if hasattr(Self, 'size') and isscalar(Self.size): nOutput = Self.size # else: nOutput = Self(x).size hasUserSuppliedDerivative = Self.d is not None if hasUserSuppliedDerivative: derivativeSelf = [] if type(Self.d) == tuple: if len(Self.d) != len(Self.input): raise FuncDesignerException( 'oofun error: num(derivatives) not equal to neither 1 nor num(inputs)' ) for i, deriv in enumerate(Self.d): inp = Self.input[i] if not isinstance(inp, OOFun) or inp.discrete: #if deriv is not None: #raise FuncDesignerException('For an oofun with some input oofuns declared as discrete you have to set oofun.d[i] = None') continue #!!!!!!!!! TODO: handle fixed cases properly!!!!!!!!!!!! #if hasattr(inp, 'fixed') and inp.fixed: continue if inp.is_oovar and ( (Vars is not None and inp not in Vars) or (fixedVars is not None and inp in fixedVars)): continue if deriv is None: if not DerApproximatorIsInstalled: raise FuncDesignerException( 'To perform gradients check you should have DerApproximator installed, see http://openopt.org/DerApproximator' ) derivativeSelf.append(get_d1(Self.fun, Input, diffInt=Self.diffInt, stencil = Self.stencil, \ args=Self.args, varForDifferentiation = i, pointVal = Self._getFuncCalcEngine(x), exactShape = True)) else: # !!!!!!!!!!!!!! TODO: add check for user-supplied derivative shape tmp = deriv(*Input) if not isscalar(tmp) and type(tmp) in ( ndarray, tuple, list ) and type( tmp ) != DiagonalType: # i.e. not a scipy.sparse matrix tmp = atleast_2d(tmp) ######################################## _tmp = Input[i] Tmp = 1 if isscalar(_tmp) or prod( _tmp.shape) == 1 else len(Input[i]) if tmp.shape[1] != Tmp: # TODO: add debug msg # print('incorrect shape in FD AD _getDerivativeSelf') # print tmp.shape[0], nOutput, tmp if tmp.shape[0] != Tmp: raise FuncDesignerException( 'error in getDerivativeSelf()') tmp = tmp.T ######################################## derivativeSelf.append(tmp) else: tmp = Self.d(*Input) if not isscalar(tmp) and type(tmp) in ( ndarray, tuple, list): # i.e. not a scipy.sparse matrix tmp = atleast_2d(tmp) if tmp.shape[1] != expectedTotalInputLength: # TODO: add debug msg if tmp.shape[0] != expectedTotalInputLength: raise FuncDesignerException( 'error in getDerivativeSelf()') tmp = tmp.T ac = 0 if isinstance(tmp, ndarray) and hasattr( tmp, 'toarray') and not isinstance(tmp, multiarray): tmp = tmp.A # is dense matrix #if not isinstance(tmp, ndarray) and not isscalar(tmp) and type(tmp) != DiagonalType: if len(Input) == 1: # if type(tmp) == DiagonalType: # # TODO: mb rework it # if Input[0].size > 150 and tmp.size > 150: # tmp = tmp.resolve(True).tocsc() # else: tmp = tmp.resolve(False) derivativeSelf = [tmp] else: for i, inp in enumerate(Input): t = Self.input[i] if t.discrete or (t.is_oovar and ( (Vars is not None and t not in Vars) or (fixedVars is not None and t in fixedVars))): ac += inp.size continue if isinstance(tmp, ndarray): TMP = tmp[:, ac:ac + Len(inp)] elif isscalar(tmp): TMP = tmp elif type(tmp) == DiagonalType: if tmp.size == inp.size and ac == 0: TMP = tmp else: # print debug warning here # TODO: mb rework it if inp.size > 150 and tmp.size > 150: tmp = tmp.resolve(True).tocsc() else: tmp = tmp.resolve(False) TMP = tmp[:, ac:ac + inp.size] else: # scipy.sparse matrix TMP = tmp.tocsc()[:, ac:ac + inp.size] ac += Len(inp) derivativeSelf.append(TMP) # TODO: is it required? # if not hasattr(Self, 'outputTotalLength'): Self(x) # # if derivativeSelf.shape != (Self.outputTotalLength, Self.inputTotalLength): # s = 'incorrect shape for user-supplied derivative of oofun '+Self.name+': ' # s += '(%d, %d) expected, (%d, %d) obtained' % (Self.outputTotalLength, Self.inputTotalLength, derivativeSelf.shape[0], derivativeSelf.shape[1]) # raise FuncDesignerException(s) else: if Vars is not None or (fixedVars is not None and len(fixedVars) != 0): raise FuncDesignerException( "sorry, custom oofun derivatives don't work with Vars/fixedVars arguments yet" ) if not DerApproximatorIsInstalled: raise FuncDesignerException( 'To perform this operation you should have DerApproximator installed, see http://openopt.org/DerApproximator' ) derivativeSelf = get_d1(Self.fun, Input, diffInt=Self.diffInt, stencil=Self.stencil, args=Self.args, pointVal=Self._getFuncCalcEngine(x), exactShape=True) if type(derivativeSelf) == tuple: derivativeSelf = list(derivativeSelf) elif type(derivativeSelf) != list: derivativeSelf = [derivativeSelf] #assert all([elem.ndim > 1 for elem in derivativeSelf]) # assert len(derivativeSelf[0])!=16 #assert (type(derivativeSelf[0]) in (int, float)) or derivativeSelf[0][0]>480.00006752 or derivativeSelf[0][0]<480.00006750 return derivativeSelf
mdot(inv(kernel.K(Z_shaped, Z_shaped)), O).T), Z_shaped) def A_n_analytical_vec(Z_f): Z_shaped = Z_f.reshape((M, Dim)) A = mdot(kernel.K(X, Z_shaped), inv(kernel.K(Z_shaped, Z_shaped))) An = mdot(kernel.K(X[np.newaxis, n, :], Z_shaped), inv(kernel.K(Z_shaped, Z_shaped))) # return (kernel.get_gradients_X_AK(mdot(inv(kernel.K(Z_shaped, Z_shaped)), O).repeat(N, 1), Z_shaped, X)) - \ return kernel.get_gradients_X_SKD( A, mdot(inv(kernel.K(Z_shaped, Z_shaped)), O).repeat(N, 1), Z_shaped)[1, :, :] print get_d1(A_n, Z.flatten()).reshape((M, Dim)) print print A_n_analytical(Z.flatten()) print A_n_analytical_vec(Z.flatten()) O1 = np.random.normal(0, 1, M) \ .reshape((M, 1)) O2 = np.random.normal(0, 1, M) \ .reshape((M, 1)) OO = np.random.normal(0, 1, M * M) \ .reshape((M, M))
from numpy import * from DerApproximator import get_d1 func = lambda x: (x**4).sum() x = arange(1.0, 6.0) r1 = get_d1(func, x, stencil = 1, diffInt = 1e-4) print(r1) # [ 4.00060004 32.00240008 108.00540012 256.00960016 500.0150002 ] r2 = get_d1(func, x, stencil = 2, diffInt = 1e-4) print(r2) # [ 4.00000004 32.00000008 108.00000012 256.00000016 500.0000002 ] r3 = get_d1(func, x, stencil = 3, diffInt = 1e-4) print(r3) # [ 4. 32. 108. 256. 500.]
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