def __getattr__(self, attr): if attr == 'size': if 'values' not in self.__dict__: raise FuncDesignerException('this distribution is unquantified yet thus it has no size yet') self.size = self.values.size return self.size elif attr == 'values': raise FuncDesignerException('this distribution is unquantified yet thus it has no array of possible values yet') elif attr == 'probabilities': raise FuncDesignerException('this distribution is unquantified yet thus it has no array of probabilities yet') elif attr == 'Mean': self.Mean = (self.values * self.probabilities).sum() return self.Mean elif attr == 'Std': self.Std = o.sqrt(self.Var, attachConstraints = False) return self.Std elif attr == 'Var': self.Var = o.abs(o.sum((self.values)**2 * self.probabilities) - self.Mean**2) return self.Var elif attr == 'cdf': self.cdf = cdf(self) return self.cdf elif attr == 'pdf': self.pdf = pdf(self) return self.pdf elif attr == 'A': return self elif attr == 'ndim': return 1 elif attr == 'shape': return (self.size, ) else: raise AttributeError('incorrect attribute "%s" of FuncDesigner stochastic class' % attr)
def P(c, interpolate='auto'): if interpolate not in (True, False, 'auto'): raise FuncDesignerException( "in P() parameter interpolate must be True, False or 'auto'") if c is True: return 1.0 elif c is False: return 0.0 if not isinstance(c, BaseFDConstraint): raise FuncDesignerException( 'arg of FuncDesigner.P() must be True, False or FuncDesigner constraint' ) if (type(c.ub) == np.ndarray and c.ub.size != 1) or (type(c.lb) == np.ndarray and c.lb.size != 1): raise FuncDesignerException( 'stochastic constraints are unimplemented for vectorized API yet') if np.isfinite(c.ub) and c.lb == -np.inf: r = oofun(lambda x: f_quantile(x, c.ub, interpolate), c.oofun, d=lambda x: d_quantile(x, c.ub, interpolate)) elif np.isfinite(c.lb) and c.ub == np.inf: r = oofun(lambda x: 1.0 - f_quantile(x, c.lb, interpolate), c.oofun, d=lambda x: -d_quantile(x, c.lb, interpolate)) else: raise FuncDesignerException( 'stochastic constraints are implemented for case xor(isfinite(lb),isfinite(ub)) only for now' ) return r
def plot(self): try: import pylab except: raise FuncDesignerException( 'to plot you should have matplotlib installed') if self.distrib.distribType != 'continuous': raise FuncDesignerException( 'you can use pdf for continuous distribution only') # Temporary, to omit same values or very close to zero division effects # TODO: rework it d2 = self.distrib.reduce(self.distrib.size - 1, inplace=False) d2.sort() vals, probs = d2.values, d2.probabilities cp = np.cumsum(probs) d_right = (cp[1:] - cp[:-1]) / (vals[1:] - vals[:-1]) d = np.hstack((d_right[0], 0.5 * (d_right[1:] + d_right[:-1]), (cp[-1] - cp[-2]) / (vals[-1] - vals[-2]))) x, y = vals, d pylab.plot(x, y) x_l, x_u = x[0] - 0.05 * (x[-1] - x[0]), x[-1] + 0.05 * (x[-1] - x[0]) pylab.xlim(x_l, x_u) My, my = np.max(y), np.min(y) d_y = My - my pylab.ylim(-0.05 * d_y, My + 0.05 * d_y) pylab.plot([x_l, x_u], [0, 0], color='g', linewidth=2) pylab.title(self._str) pylab.grid('on') pylab.show()
def var(arg, *args, **kw): if isinstance(arg, stochasticDistribution): if not len(args) == len(kw) == 0: raise FuncDesignerException( 'incorrect usage of FuncDesigner var() - it cannot handle additional arguments yet' ) r = arg.Var elif isinstance(arg, oofun): if not len(args) == len(kw) == 0: raise FuncDesignerException( 'incorrect usage of FuncDesigner var() - it cannot handle additional arguments yet' ) #r = oofun(lambda x: np.array([var(xx) for xx in x.view(np.ndarray)]).view(multiarray) if isinstance(x, multiarray)\ r = oofun(f_var, arg) else: r = np.std(var, *args, **kw) return r
def std(arg, *args, **kw): if isinstance(arg, stochasticDistribution): if not len(args) == len(kw) == 0: raise FuncDesignerException( 'incorrect usage of FuncDesigner std() - it cannot handle additional arguments yet' ) r = arg.Std elif isinstance(arg, oofun): if not len(args) == len(kw) == 0: raise FuncDesignerException( 'incorrect usage of FuncDesigner std() - it cannot handle additional arguments yet' ) #r = oofun(lambda x: np.array([std(X[i]) for i in range() in (x.reshape(-1, 1) if x.ndim < 2 else x).view(np.ndarray)]).view(multiarray) if isinstance(x, multiarray)\ r = oofun(f_std, arg) else: r = np.std(arg, *args, **kw) return r
def var(arg, *args, **kw): if isinstance(arg, stochasticDistribution): if not len(args) == len(kw) == 0: raise FuncDesignerException('incorrect usage of FuncDesigner var() - it cannot handle additional arguments yet') r = arg.Var elif isinstance(arg, oofun): if not len(args) == len(kw) == 0: raise FuncDesignerException('incorrect usage of FuncDesigner var() - it cannot handle additional arguments yet') if is_prod_scalar(arg): multiplier, tmp = arg._fixed_part, arg._unfixed_part return multiplier**2 * var(tmp) #r = oofun(lambda x: np.array([var(xx) for xx in x.view(np.ndarray)]).view(multiarray) if isinstance(x, multiarray)\ r = oofun(f_var, arg, engine = 'var', vectorized = True) else: r = np.var(var, *args, **kw) return r
def std(arg, *args, **kw): if isinstance(arg, stochasticDistribution): if not len(args) == len(kw) == 0: raise FuncDesignerException('incorrect usage of FuncDesigner std() - it cannot handle additional arguments yet') r = arg.Std elif isinstance(arg, oofun): if not len(args) == len(kw) == 0: raise FuncDesignerException('incorrect usage of FuncDesigner std() - it cannot handle additional arguments yet') #r = oofun(lambda x: np.array([std(X[i]) for i in range() in (x.reshape(-1, 1) if x.ndim < 2 else x).view(np.ndarray)]).view(multiarray) if isinstance(x, multiarray)\ if is_prod_scalar(arg): multiplier, tmp = arg._fixed_part, arg._unfixed_part return abs(multiplier) * std(tmp) r = oofun(f_std, arg, engine = 'std', vectorized = True) else: r = np.std(arg, *args, **kw) return r
def __init__(self, _values=None, _probabilities=None, distribType = 'undefined', ppf = None, N = None, quantiles=None, Str = ''): Stochastic.__init__(self) self.distribType = distribType if Str != '': self._str = Str if ppf is not None: assert quantiles is None, 'quantiles in constructor are unimplemented yet' if N is None: self.quantified = False #r.__repr__ = lambda self: self._str self._yield_quantified = lambda k: stochasticDistribution(ppf(np.arange(1.0, float(k+1)) / (k+2)), [1.0/k]*k, Str = (self._str + ' quantified into %d points' % k), distribType = self.distribType) return else: if quantiles is None: quantiles = np.arange(1, N+1) / float(N+2) else: assert len(quantiles) == N, 'lenght of quantiles must be equal to number of points to be created' values = ppf(quantiles) probabilities = np.array([1.0/N]*N) self._str = Str + ' quantified into %d points' % N else: values = _values if type(_values) == np.ndarray else np.asfarray(_values) if _probabilities is None: raise FuncDesignerException('for assignment with this set of parameters you should provide probabilities as well') probabilities = _probabilities if type(_probabilities) == np.ndarray else np.asfarray(_probabilities) if np.any(probabilities < -1e-15): raise FuncDesignerException('probabilities cannot be negative') if values.size != probabilities.size: s = ''' in stochastic distribution constructor lenght of values (got: %d) must be equal to lenght of probabilities (got: %d) ''' % (values.size, probabilities.size) raise FuncDesignerException(s) probabilitiesSum = np.sum(probabilities) Diff = np.abs(probabilitiesSum - 1) if Diff > 1e-7: p_sum_msg = 'probabilities sum differs too much: 1.0 expected, differrence = %e' % Diff raise FuncDesignerException(p_sum_msg) if Diff > 1e-10: # not inplace for more safety probabilities = probabilities / probabilitiesSum #obj = asanyarray(values).view(self) self.values = values.copy() self.probabilities = probabilities.copy()
def mean(arg, *args, **kw): if isinstance(arg, stochasticDistribution): if not len(args) == len(kw) == 0: raise FuncDesignerException( 'incorrect usage of FuncDesigner mean() - it cannot handle additional arguments yet' ) r = arg.Mean elif isinstance(arg, oofun): if not len(args) == len(kw) == 0: raise FuncDesignerException( 'incorrect usage of FuncDesigner mean() - it cannot handle additional arguments yet' ) if arg._isSum: r = o.sum([mean(elem) for elem in arg._summation_elements]) else: # def ff(x): # # TODO: same changes for std, var,other moments # #print (type(x), multiarray) # r = np.array([mean(xx) for xx in x.view(np.ndarray)]).view(multiarray) if isinstance(x, multiarray) \ # else x if not isinstance(x, stochasticDistribution) else x.Mean # #if type(x) == np.ndarray: ## print ('!', x, r.shape) # return r r = oofun(f_mean, arg) # r = oofun(lambda x: np.array([mean(xx) for xx in (x.reshape(-1, 1) if x.ndim < 2 else x).view(np.ndarray)]).view(multiarray) if isinstance(x, multiarray) \ # else x if not isinstance(x, stochasticDistribution) else x.Mean, arg) # TODO: move _D definition outside of the func def _D(*args, **kw): if not isinstance(arg, oofun): return {} res = arg._D(*args, **kw) res = dict([(key, elem.Mean if isinstance( elem, stochasticDistribution) else elem) for key, elem in res.items()]) return res r._D = _D else: r = np.mean(arg, *args, **kw) return r
def mean(arg, *args, **kw): if isinstance(arg, stochasticDistribution): if not len(args) == len(kw) == 0: raise FuncDesignerException('incorrect usage of FuncDesigner mean() - it cannot handle additional arguments yet') r = arg.Mean elif isinstance(arg, oofun): if not len(args) == len(kw) == 0: raise FuncDesignerException('incorrect usage of FuncDesigner mean() - it cannot handle additional arguments yet') if arg._isSum: r = o.sum([mean(elem) for elem in arg._summation_elements]) elif is_prod_scalar(arg): # TODO: rework it when np.prod(objects) will be fixed multiplier, tmp = arg._fixed_part, arg._unfixed_part return multiplier * mean(tmp) # elif arg._isProd: # tmp = [elem for elem in arg._prod_elements if isinstance(elem, oofun) and elem.hasStochasticVariables] else: # def ff(x): # # TODO: same changes for std, var,other moments # #print (type(x), multiarray) # r = np.array([mean(xx) for xx in x.view(np.ndarray)]).view(multiarray) if isinstance(x, multiarray) \ # else x if not isinstance(x, stochasticDistribution) else x.Mean # #if type(x) == np.ndarray: ## print ('!', x, r.shape) # return r r = oofun(f_mean, arg, engine = 'mean', engine_monotonity = 0, vectorized = True) r.getOrder = arg.getOrder # r = oofun(lambda x: np.array([mean(xx) for xx in (x.reshape(-1, 1) if x.ndim < 2 else x).view(np.ndarray)]).view(multiarray) if isinstance(x, multiarray) \ # else x if not isinstance(x, stochasticDistribution) else x.Mean, arg) # TODO: move _D definition outside of the func def _D(*args, **kw): res = arg._D(*args, **kw) res = dict((key, elem.Mean if isinstance(elem, stochasticDistribution) else elem) for key, elem in res.items()) return res r._D = _D else: r = np.mean(arg, *args, **kw) return r
def plot(self): try: import pylab except: raise FuncDesignerException('to plot you should have matplotlib installed') self.distrib.sort() x, y = self.distrib.values, np.cumsum(self.distrib.probabilities) if self.distrib.distribType == 'continuous': pylab.plot(x, y) elif self.distrib.distribType == 'discrete': X = np.hstack((x[0], np.vstack((x, x)).T.flatten(), x[-1])) Y = np.hstack((0.0, y[0], np.vstack((y, y)).T.flatten())) pylab.plot(X, Y) else: pylab.scatter(x, y, s=1) x_l, x_u = x[0]-0.05*(x[-1]-x[0]), x[-1]+0.05*(x[-1]-x[0]) pylab.xlim(x_l, x_u) pylab.ylim(-0.05, 1.05) pylab.plot([x_l, x_u], [0, 0], color='g', linewidth = 2) pylab.plot([x_l, x_u], [1, 1], color='g', linewidth = 2) pylab.title(self._str) pylab.grid('on') pylab.show()
def mergeDistributions(d1, d2, operation): #assert isinstance(d1, stochasticDistribution), 'unimplemented yet' is_d1_stoch = isinstance(d1, stochasticDistribution) is_d2_stoch = isinstance(d2, stochasticDistribution) if is_d1_stoch and type(d2) == multiarray: #return np.array([mergeDistributions(d1, elem, operation) for elem in np.atleast_1d(d2)]).view(multiarray) return np.array([mergeDistributions(d1, elem, operation) for elem in \ (d2 if d2.ndim > 1 else d2.reshape(-1, 1)).view(np.ndarray)]).view(multiarray) if is_d2_stoch and type(d1) == multiarray: #return np.array([mergeDistributions(elem, d2, operation) for elem in np.atleast_1d(d1)]).view(multiarray) return np.array([mergeDistributions(elem, d2, operation) for elem in \ (d1 if d1.ndim > 1 else d1.reshape(-1, 1)).view(np.ndarray)]).view(multiarray) if is_d1_stoch and is_d2_stoch: if not hasattr(d1, 'stochDep') or not hasattr(d1, 'stochDep'): distrib_err_fcn() cond_same_stoch = is_d2_stoch and is_d1_stoch and set( d1.stochDep.keys()) == set(d2.stochDep.keys()) if not is_d1_stoch or not is_d2_stoch or cond_same_stoch: if not is_d2_stoch: # thus d1 is stoch d2 = np.asfarray(d2) if operation == operator.truediv \ or (hasattr(operator, 'div') and operation == operator.div) and not isinstance(d2, ooarray) else np.asanyarray(d2) #assert d2.size == 1, 'unimplemented for size > 1 yet' vals2 = d2.reshape(1, -1) if d2.size > 1 else d2 vals1 = d1.values distribType = d1.distribType elif not is_d1_stoch: # thus d2 is stoch d1 = np.asfarray(d1) if operation == operator.truediv \ or (hasattr(operator, 'div') and operation == operator.div) and not isinstance(d1, ooarray) else np.asanyarray(d1) assert d1.size == 1, 'unimplemented for size > 1 yet' vals1 = d1.reshape(1, -1) if d1.size > 1 else d1 vals2 = d2.values distribType = d2.distribType else: #cond_same_stoch vals1 = d1.values vals2 = d2.values distribType = d1.distribType if d1.distribType == d2.distribType else 'undefined' Vals = operation(vals1, vals2) r = stochasticDistribution( Vals.flatten(), d1.probabilities.copy() if is_d1_stoch else d2.probabilities.copy(), distribType) if is_d1_stoch and is_d2_stoch: r.stochDep = d1.stochDep.copy() for key, val in d2.stochDep.items(): if key in r.stochDep: r.stochDep[key] += val else: r.stochDep[key] = val elif is_d1_stoch: r.stochDep = d1.stochDep.copy() else: if not is_d2_stoch: raise FuncDesignerException('bug in FuncDesigner kernel') r.stochDep = d2.stochDep.copy() #!!!!!!!!!!!! TODO: getOrder (for linear probs) else: def f(D1, D2): r = operation( D1.reshape(-1, 1), D2 if operation != operator.truediv \ or isinstance(D2, (oofun, ooarray)) \ or isinstance(D1, (oofun, ooarray)) \ else np.asfarray(D2) \ ).reshape(1, -1) return r distribType = d1.distribType if d1.distribType == d2.distribType else 'undefined' F = f(d1.values, d2.values) New = 1 if New and np.all(d1.probabilities == d1.probabilities[0]) and np.all( d2.probabilities == d2.probabilities[0]): Probabilities = np.empty(d1.probabilities.size * d2.probabilities.size) Probabilities.fill(d1.probabilities[0] * d2.probabilities[0]) else: Probabilities = (d1.probabilities.reshape(-1, 1) * d2.probabilities.reshape(1, -1)).flatten() r = stochasticDistribution(F.flatten(), Probabilities, distribType) ''' adjust stochDep ''' if len(set(d1.stochDep.keys()) & set(d2.stochDep.keys())) != 0 and len( set(d1.stochDep.keys()) | set(d2.stochDep.keys())) > 1: # print(d1.stochDep.keys()) # print(d2.stochDep.keys()) # print(set(d1.stochDep.keys()) | set(d2.stochDep.keys())) raise FuncDesignerException(''' This stochastic function has structure that makes it impossible to handle in OpenOpt Suite yet. If gradient-based solver is involved, sometimes using derivative-free one instead (e.g. scipy_cobyla, de, bobyqa) can be successful ''') stochDep = d1.stochDep.copy() for key, val in d2.stochDep.items(): if key in stochDep: stochDep[key] += val else: stochDep[key] = val r.stochDep = stochDep if is_d1_stoch: m1 = getattr(d1, 'maxDistributionSize', 0) else: m1 = 0 if is_d2_stoch: m2 = getattr(d2, 'maxDistributionSize', 0) else: m2 = 0 N = max((m1, m2)) if N == 0: s = ''' if one of function arguments is stochastic distribution without resolving into quantified value (e.g. uniform(-10,10) instead of uniform(-10,10, 100), 100 is number of point to emulate) then you should evaluate the function onto oopoint with assigned parameter maxDistributionSize''' raise FuncDesignerException(s) r = r.reduce(N) r.maxDistributionSize = N if is_d1_stoch and hasattr(d1, '_p'): r._p = d1._p elif is_d2_stoch and hasattr(d2, '_p'): r._p = d2._p # if operation == operator.mul: # r._is_product = True # r._product_elements = [self, other] return r
def engine(self): raise FuncDesignerException( 'virtual method stochFunc.engine has not been overloaded')
def __xor__(self, other): raise FuncDesignerException('For function pow() use a**b, not a^b')