def in_words_float(amount, _gender=FEMALE): """ Float in words @param amount: float numeral @type amount: C{float} or C{Decimal} @return: in-words reprsentation of float numeral @rtype: C{unicode} @raise L{pytils.err.InputParameterError}: input parameters' check failed (when amount is not C{float}) @raise ValueError: when ammount is negative """ utils.check_positive(amount) pts = [] # преобразуем целую часть pts.append(sum_string(int(amount), 2, (u"целая", u"целых", u"целых"))) # теперь то, что после запятой remainder = _get_float_remainder(amount) signs = len(str(remainder)) - 1 pts.append(sum_string(int(remainder), 2, FRACTIONS[signs])) return u" ".join(pts)
def rubles(amount, zero_for_kopeck=False): """ Get string for money @param amount: amount of money @type amount: C{int}, C{long}, C{float} or C{Decimal} @param zero_for_kopeck: If false, then zero kopecks ignored @type zero_for_kopeck: C{bool} @return: in-words representation of money's amount @rtype: C{unicode} @raise L{pytils.err.InputParameterError}: input parameters' check failed (amount neither C{int}, no C{float}) @raise ValueError: amount is negative """ check_positive(amount) pts = [] amount = round(amount, 2) pts.append(sum_string(int(amount), 1, (u"рубль", u"рубля", u"рублей"))) remainder = _get_float_remainder(amount, 2) iremainder = int(remainder) if iremainder != 0 or zero_for_kopeck: # если 3.1, то это 10 копеек, а не одна if iremainder < 10 and len(remainder) == 1: iremainder *= 10 pts.append(sum_string(iremainder, 2, (u"копейка", u"копейки", u"копеек"))) return u" ".join(pts)
def exponential_mechanism(x: ndarray, score_function: Callable[[ndarray], ndarray], sensitivity: float, privacy_budget: PrivacyBudget) -> Any: """Differentially private exponantial mechanism. Each keys sampling by probability proportional to: .. math:: \exp \left (\\frac{\epsilon \\times score}{2 \Delta f}\\right) The result guarantees :math:`(\epsilon,\delta)`-differential privacy. :param x: Sensitive input data :param score_function: a function to receive `x` and return a dictionary with items {`element`: `score`} :param sensitivity: The global L1-sensitivity :math:`\Delta f` of `x` :param privacy_budget: The privacy budget :math:`(\epsilon,0)` used for the outputs :return: The sampled element """ check_positive(privacy_budget.epsilon) check_positive(sensitivity) R, s = score_function(x) s -= np.max(s) probability = [ np.exp(privacy_budget.epsilon * score / (2 * sensitivity)) for score in s ] probability /= np.sum(probability) return choice(R, p=probability)
def sum_string(amount, gender, items=None): """ Get sum in words @param amount: amount of objects @type amount: C{int} or C{long} @param gender: gender of object (MALE, FEMALE or NEUTER) @type gender: C{int} @param items: variants of object in three forms: for one object, for two objects and for five objects @type items: 3-element C{sequence} of C{unicode} or just C{unicode} (three variants with delimeter ',') @return: in-words representation objects' amount @rtype: C{unicode} @raise L{pytils.err.InputParameterError}: input parameters' check failed @raise ValueError: items isn't 3-element C{sequence} or C{unicode} @raise ValueError: amount bigger than 10**11 @raise ValueError: amount is negative """ if isinstance(items, unicode): items = utils.split_values(items) if items is None: items = (u"", u"", u"") try: one_item, two_items, five_items = items except ValueError: raise ValueError("Items must be 3-element sequence") check_positive(amount) if amount == 0: return u"ноль %s" % five_items into = u'' tmp_val = amount # единицы into, tmp_val = _sum_string_fn(into, tmp_val, gender, items) # тысячи into, tmp_val = _sum_string_fn(into, tmp_val, FEMALE, (u"тысяча", u"тысячи", u"тысяч")) # миллионы into, tmp_val = _sum_string_fn(into, tmp_val, MALE, (u"миллион", u"миллиона", u"миллионов")) # миллиарды into, tmp_val = _sum_string_fn(into, tmp_val, MALE, (u"миллиард", u"миллиарда", u"миллиардов")) if tmp_val == 0: return into else: raise ValueError("Cannot operand with numbers bigger than 10**11")
def _get_float_remainder(fvalue, signs=9): """ Get remainder of float, i.e. 2.05 -> '05' @param fvalue: input value @type fvalue: C{int}, C{long}, C{float} or C{Decimal} @param signs: maximum number of signs @type signs: C{int} or C{long} @return: remainder @rtype: C{str} @raise L{pytils.err.InputParameterError}: input parameters' check failed (fvalue neither C{int}, no C{float}) @raise ValueError: fvalue is negative @raise ValueError: signs overflow """ check_positive(fvalue) if isinstance(fvalue, (int, long)): return "0" if isinstance(fvalue, Decimal) and fvalue.as_tuple()[2] == 0: # Decimal.as_tuple() -> (sign, digit_tuple, exponent) # если экспонента "0" -- значит дробной части нет return "0" signs = min(signs, len(FRACTIONS)) # нужно remainder в строке, потому что дробные X.0Y # будут "ломаться" до X.Y remainder = str(fvalue).split('.')[1] iremainder = int(remainder) orig_remainder = remainder factor = len(str(remainder)) - signs if factor > 0: # после запятой цифр больше чем signs, округляем iremainder = int(round(iremainder / (10.0**factor))) format = "%%0%dd" % min(len(remainder), signs) remainder = format % iremainder if len(remainder) > signs: # при округлении цифр вида 0.998 ругаться raise ValueError("Signs overflow: I can't round only fractional part \ of %s to fit %s in %d signs" % \ (str(fvalue), orig_remainder, signs)) return remainder
def _check_params(self): """Check PHATE parameters This allows us to fail early - otherwise certain unacceptable parameter choices, such as mds='mmds', would only fail after minutes of runtime. Raises ------ ValueError : unacceptable choice of parameters """ utils.check_positive(n_components=self.n_components, k=self.knn) utils.check_int(n_components=self.n_components, k=self.knn, n_jobs=self.n_jobs) utils.check_between(-1, 1, gamma=self.gamma) utils.check_if_not(None, utils.check_positive, a=self.decay) utils.check_if_not(None, utils.check_positive, utils.check_int, n_landmark=self.n_landmark, n_pca=self.n_pca) utils.check_if_not('auto', utils.check_positive, utils.check_int, t=self.t) if not callable(self.knn_dist): utils.check_in([ 'euclidean', 'precomputed', 'cosine', 'correlation', 'cityblock', 'l1', 'l2', 'manhattan', 'braycurtis', 'canberra', 'chebyshev', 'dice', 'hamming', 'jaccard', 'kulsinski', 'mahalanobis', 'matching', 'minkowski', 'rogerstanimoto', 'russellrao', 'seuclidean', 'sokalmichener', 'sokalsneath', 'sqeuclidean', 'yule', 'precomputed_affinity', 'precomputed_distance' ], knn_dist=self.knn_dist) if not callable(self.mds_dist): utils.check_in([ 'euclidean', 'cosine', 'correlation', 'braycurtis', 'canberra', 'chebyshev', 'cityblock', 'dice', 'hamming', 'jaccard', 'kulsinski', 'mahalanobis', 'matching', 'minkowski', 'rogerstanimoto', 'russellrao', 'seuclidean', 'sokalmichener', 'sokalsneath', 'sqeuclidean', 'yule' ], mds_dist=self.mds_dist) utils.check_in(['classic', 'metric', 'nonmetric'], mds=self.mds)
def in_words_int(amount, gender=MALE): """ Integer in words @param amount: numeral @type amount: C{int} or C{long} @param gender: gender (MALE, FEMALE or NEUTER) @type gender: C{int} @return: in-words reprsentation of numeral @rtype: C{unicode} @raise L{pytils.err.InputParameterError}: input parameters' check failed (when amount is not C{int}) @raise ValueError: amount is negative """ check_positive(amount) return sum_string(amount, gender)
def gaussian_mechanism(x: Union[int, float, ndarray], sensitivity: float, privacy_budget: PrivacyBudget) -> Union[float, ndarray]: """Differentially private Gaussian mechanism. Add Gaussian noise to the value: .. math:: x + Normal\left(\mu=0, \sigma=\\frac{\sqrt{2\log(1.25/\delta)}\Delta f}{\epsilon} \\right) The result guarantees :math:`(\epsilon,\delta)`-differential privacy. :param x: Sensitive input data :param sensitivity: The global L2-sensitivity :math:`\Delta f` of `x` :param privacy_budget: The privacy budget :math:`(\epsilon,\delta)` used for the outputs :return: Input data protected by noise """ check_positive(privacy_budget.epsilon) check_positive(privacy_budget.delta) check_positive(sensitivity) assert (privacy_budget.epsilon < 1) shape = None if isinstance(x, (int, float)) else x.shape noise = normal(loc=0., scale=np.sqrt(2 * np.log(1.25 / privacy_budget.delta)) * sensitivity / privacy_budget.epsilon, size=shape) return x + noise
def laplace_mechanism(x: Union[int, float, ndarray], sensitivity: float, privacy_budget: PrivacyBudget) -> Union[float, ndarray]: """Differentially private Laplace mechanism. Add Laplacian noise to the value: .. math:: x + Laplace\left(\mu=0, \sigma=\\frac{\Delta f}{\epsilon}\\right) The result guarantees :math:`(\epsilon,0)`-differential privacy. :param x: Sensitive input data :param sensitivity: The global L1-sensitivity :math:`\Delta f` of `x` :param privacy_budget: The privacy budget :math:`(\epsilon,0)` used for the outputs :return: Input data protected by noise """ check_positive(privacy_budget.epsilon) check_positive(sensitivity) shape = None if isinstance(x, (int, float)) else x.shape noise = laplace(loc=0., scale=sensitivity / privacy_budget.epsilon, size=shape) return x + noise
def in_words(amount, gender=None): """ Numeral in words @param amount: numeral @type amount: C{int}, C{long}, C{float} or C{Decimal} @param gender: gender (MALE, FEMALE or NEUTER) @type gender: C{int} @return: in-words reprsentation of numeral @rtype: C{unicode} raise L{pytils.err.InputParameterError}: input parameters' check failed (when amount not C{int} or C{float}, gender is not C{int} (and not None), gender isn't in (MALE, FEMALE, NEUTER)) raise ValueError: when amount is negative """ check_positive(amount) if isinstance(amount, Decimal) and amount.as_tuple()[2] == 0: # если целое, # т.е. Decimal.as_tuple -> (sign, digits tuple, exponent), exponent=0 # то как целое amount = int(amount) if gender is None: args = (amount,) else: args = (amount, gender) # если целое if isinstance(amount, (int, long)): return in_words_int(*args) # если дробное elif isinstance(amount, (float, Decimal)): return in_words_float(*args) # ни float, ни int, ни Decimal else: # до сюда не должно дойти raise RuntimeError()
def check_params(self): ''' check netImpute paameter and raise a valueError if needed ''' utils.check_positive(k=self.k)
def distance_of_time_in_words(from_time, accuracy=1, to_time=None): """ Represents distance of time in words @param from_time: source time (in seconds from epoch) @type from_time: C{int}, C{float} or C{datetime.datetime} @param accuracy: level of accuracy (1..3), default=1 @type accuracy: C{int} @param to_time: target time (in seconds from epoch), default=None translates to current time @type to_time: C{int}, C{float} or C{datetime.datetime} @return: distance of time in words @rtype: unicode @raise L{pytils.err.InputParameterError}: input parameters' check failed @raise ValueError: accuracy is lesser or equal zero """ current = False if to_time is None: current = True to_time = datetime.datetime.now() check_positive(accuracy, strict=True) if not isinstance(from_time, datetime.datetime): from_time = datetime.datetime.fromtimestamp(from_time) if not isinstance(to_time, datetime.datetime): to_time = datetime.datetime.fromtimestamp(to_time) dt_delta = to_time - from_time difference = dt_delta.days * 86400 + dt_delta.seconds minutes_orig = int(abs(difference) / 60.0) hours_orig = int(abs(difference) / 3600.0) days_orig = int(abs(difference) / 86400.0) in_future = from_time > to_time words = [] values = [] alternatives = [] days = days_orig hours = hours_orig - days_orig * 24 words.append(u"%d %s" % (days, numeral.choose_plural(days, DAY_VARIANTS))) values.append(days) words.append(u"%d %s" % \ (hours, numeral.choose_plural(hours, HOUR_VARIANTS))) values.append(hours) days == 0 and hours == 1 and current and alternatives.append(u"час") minutes = minutes_orig - hours_orig * 60 words.append(u"%d %s" % (minutes, numeral.choose_plural(minutes, MINUTE_VARIANTS))) values.append(minutes) days == 0 and hours == 0 and minutes == 1 and current and \ alternatives.append(u"минуту") # убираем из values и words конечные нули while values and not values[-1]: values.pop() words.pop() # убираем из values и words начальные нули while values and not values[0]: values.pop(0) words.pop(0) limit = min(accuracy, len(words)) real_words = words[:limit] real_values = values[:limit] # снова убираем конечные нули while real_values and not real_values[-1]: real_values.pop() real_words.pop() limit -= 1 real_str = u" ".join(real_words) # альтернативные варианты нужны только если в real_words одно значение # и, вдобавок, если используется текущее время alter_str = limit == 1 and current and alternatives and \ not (days and hours==1) and \ not (hours and minutes==1) and \ alternatives[0] _result_str = alter_str or real_str result_str = in_future and u"%s %s" % (PREFIX_IN, _result_str) \ or u"%s %s" % (_result_str, SUFFIX_AGO) # если же прошло менее минуты, то real_words -- пустой, и поэтому # нужно брать alternatives[0], а не result_str zero_str = minutes == 0 and not real_words and \ (in_future and u"менее чем через минуту" \ or u"менее минуты назад") # нужно использовать вчера/позавчера/завтра/послезавтра # если days 1..2 и в real_words одно значение day_alternatives = DAY_ALTERNATIVES.get(days, False) alternate_day = day_alternatives and current and limit == 1 and \ ((in_future and day_alternatives[1]) \ or day_alternatives[0]) final_str = not real_words and zero_str or alternate_day or result_str return final_str
def _sum_string_fn(into, tmp_val, gender, items=None): """ Make in-words representation of single order @param into: in-words representation of lower orders @type into: C{unicode} @param tmp_val: temporary value without lower orders @type tmp_val: C{int} or C{long} @param gender: gender (MALE, FEMALE or NEUTER) @type gender: C{int} @param items: variants of objects @type items: 3-element C{sequence} of C{unicode} @return: new into and tmp_val @rtype: C{tuple} @raise L{pytils.err.InputParameterError}: input parameters' check failed @raise ValueError: tmp_val is negative """ if items is None: items = (u"", u"", u"") one_item, two_items, five_items = items check_positive(tmp_val) if tmp_val == 0: return into, tmp_val words = [] rest = tmp_val % 1000 tmp_val = tmp_val / 1000 if rest == 0: # последние три знака нулевые if into == u"": into = u"%s " % five_items return into, tmp_val # начинаем подсчет с rest end_word = five_items # сотни words.append(HUNDREDS[rest / 100]) # десятки rest = rest % 100 rest1 = rest / 10 # особый случай -- tens=1 tens = rest1 == 1 and TENS[rest] or TENS[rest1] words.append(tens) # единицы if rest1 < 1 or rest1 > 1: amount = rest % 10 end_word = choose_plural(amount, items) words.append(ONES[amount][gender-1]) words.append(end_word) # добавляем то, что уже было words.append(into) # убираем пустые подстроки words = filter(lambda x: len(x) > 0, words) # склеиваем и отдаем return u" ".join(words).strip(), tmp_val