Skip to content

ding.utils.loader.number

ding.utils.loader.number

numeric(int_ok=True, float_ok=True, inf_ok=True)

Overview

Create a numeric loader.

Arguments: - int_ok (:obj:bool): Whether int is allowed. - float_ok (:obj:bool): Whether float is allowed. - inf_ok (:obj:bool): Whether inf is allowed.

interval(left=None, right=None, left_ok=True, right_ok=True, eps=0.0)

Overview

Create a interval loader.

Arguments: - left (:obj:Optional[NUMBER_TYPING]): The left bound. - right (:obj:Optional[NUMBER_TYPING]): The right bound. - left_ok (:obj:bool): Whether left bound is allowed. - right_ok (:obj:bool): Whether right bound is allowed. - eps (:obj:float): The epsilon.

is_negative()

Overview

Create a negative loader.

is_positive()

Overview

Create a positive loader.

non_negative()

Overview

Create a non-negative loader.

non_positive()

Overview

Create a non-positive loader.

negative()

Overview

Create a negative loader.

positive()

Overview

Create a positive loader.

plus(addend)

Overview

Create a plus loader.

Arguments: - addend (:obj:Any): The addend.

minus(subtrahend)

Overview

Create a minus loader.

Arguments: - subtrahend (:obj:Any): The subtrahend.

minus_with(minuend)

Overview

Create a minus loader.

Arguments: - minuend (:obj:Any): The minuend.

multi(multiplier)

Overview

Create a multi loader.

Arguments: - multiplier (:obj:Any): The multiplier.

divide(divisor)

Overview

Create a divide loader.

Arguments: - divisor (:obj:Any): The divisor.

divide_with(dividend)

Overview

Create a divide loader.

Arguments: - dividend (:obj:Any): The dividend.

power(index)

Overview

Create a power loader.

Arguments: - index (:obj:Any): The index.

power_with(base)

Overview

Create a power loader.

Arguments: - base (:obj:Any): The base.

msum(*items)

Overview

Create a sum loader.

Arguments: - items (:obj:tuple): The items.

mmulti(*items)

Overview

Create a multi loader.

Arguments: - items (:obj:tuple): The items.

mcmp(first, *items)

Overview

Create a multi compare loader.

Arguments: - first (:obj:Any): The first item. - items (:obj:tuple): The items.

Full Source Code

../ding/utils/loader/number.py

1import math 2import operator 3from typing import Optional, Union, Callable, Any 4 5from .base import Loader, ILoaderClass 6from .utils import keep, check_only 7 8NUMBER_TYPES = (int, float) 9NUMBER_TYPING = Union[int, float] 10 11 12def numeric(int_ok: bool = True, float_ok: bool = True, inf_ok: bool = True) -> ILoaderClass: 13 """ 14 Overview: 15 Create a numeric loader. 16 Arguments: 17 - int_ok (:obj:`bool`): Whether int is allowed. 18 - float_ok (:obj:`bool`): Whether float is allowed. 19 - inf_ok (:obj:`bool`): Whether inf is allowed. 20 """ 21 22 if not int_ok and not float_ok: 23 raise ValueError('Either int or float should be allowed.') 24 25 def _load(value) -> NUMBER_TYPING: 26 if isinstance(value, NUMBER_TYPES): 27 if math.isnan(value): 28 raise ValueError('nan is not numeric value') 29 if isinstance(value, int) and not int_ok: 30 raise TypeError('int is not allowed but {actual} found'.format(actual=repr(value))) 31 if isinstance(value, float) and not float_ok: 32 raise TypeError('float is not allowed but {actual} found'.format(actual=repr(value))) 33 if math.isinf(value) and not inf_ok: 34 raise ValueError('inf is not allowed but {actual} found'.format(actual=repr(value))) 35 36 return value 37 else: 38 raise TypeError( 39 'numeric value should be either int, float or str, but {actual} found'.format( 40 actual=repr(type(value).__name__) 41 ) 42 ) 43 44 return Loader(_load) 45 46 47def interval( 48 left: Optional[NUMBER_TYPING] = None, 49 right: Optional[NUMBER_TYPING] = None, 50 left_ok: bool = True, 51 right_ok: bool = True, 52 eps=0.0 53) -> ILoaderClass: 54 """ 55 Overview: 56 Create a interval loader. 57 Arguments: 58 - left (:obj:`Optional[NUMBER_TYPING]`): The left bound. 59 - right (:obj:`Optional[NUMBER_TYPING]`): The right bound. 60 - left_ok (:obj:`bool`): Whether left bound is allowed. 61 - right_ok (:obj:`bool`): Whether right bound is allowed. 62 - eps (:obj:`float`): The epsilon. 63 """ 64 65 if left is None: 66 left = -math.inf 67 if right is None: 68 right = +math.inf 69 if left > right: 70 raise ValueError( 71 "Left bound should no more than right bound, but {left} > {right}.".format( 72 left=repr(left), right=repr(right) 73 ) 74 ) 75 eps = math.fabs(eps) 76 77 def _value_compare_with_eps(a, b) -> int: 78 if math.fabs(a - b) <= eps: 79 return 0 80 elif a < b: 81 return -1 82 else: 83 return 1 84 85 def _load(value) -> NUMBER_TYPING: 86 _left_check = _value_compare_with_eps(value, left) 87 if _left_check < 0: 88 raise ValueError( 89 'value should be no less than {left} but {value} found'.format(left=repr(left), value=repr(value)) 90 ) 91 elif not left_ok and _left_check == 0: 92 raise ValueError( 93 'value should not be equal to left bound {left} but {value} found'.format( 94 left=repr(left), value=repr(value) 95 ) 96 ) 97 98 _right_check = _value_compare_with_eps(value, right) 99 if _right_check > 0: 100 raise ValueError( 101 'value should be no more than {right} but {value} found'.format(right=repr(right), value=repr(value)) 102 ) 103 elif not right_ok and _right_check == 0: 104 raise ValueError( 105 'value should not be equal to right bound {right} but {value} found'.format( 106 right=repr(right), value=repr(value) 107 ) 108 ) 109 110 return value 111 112 return Loader(_load) 113 114 115def is_negative() -> ILoaderClass: 116 """ 117 Overview: 118 Create a negative loader. 119 """ 120 121 return Loader((lambda x: x < 0, lambda x: ValueError('negative required but {value} found'.format(value=repr(x))))) 122 123 124def is_positive() -> ILoaderClass: 125 """ 126 Overview: 127 Create a positive loader. 128 """ 129 130 return Loader((lambda x: x > 0, lambda x: ValueError('positive required but {value} found'.format(value=repr(x))))) 131 132 133def non_negative() -> ILoaderClass: 134 """ 135 Overview: 136 Create a non-negative loader. 137 """ 138 139 return Loader( 140 (lambda x: x >= 0, lambda x: ValueError('non-negative required but {value} found'.format(value=repr(x)))) 141 ) 142 143 144def non_positive() -> ILoaderClass: 145 """ 146 Overview: 147 Create a non-positive loader. 148 """ 149 150 return Loader( 151 (lambda x: x <= 0, lambda x: ValueError('non-positive required but {value} found'.format(value=repr(x)))) 152 ) 153 154 155def negative() -> ILoaderClass: 156 """ 157 Overview: 158 Create a negative loader. 159 """ 160 161 return Loader(lambda x: -x) 162 163 164def positive() -> ILoaderClass: 165 """ 166 Overview: 167 Create a positive loader. 168 """ 169 170 return Loader(lambda x: +x) 171 172 173def _math_binary(func: Callable[[Any, Any], Any], attachment) -> ILoaderClass: 174 """ 175 Overview: 176 Create a math binary loader. 177 Arguments: 178 - func (:obj:`Callable[[Any, Any], Any]`): The function. 179 - attachment (:obj:`Any`): The attachment. 180 """ 181 182 return Loader(lambda x: func(x, Loader(attachment)(x))) 183 184 185def plus(addend) -> ILoaderClass: 186 """ 187 Overview: 188 Create a plus loader. 189 Arguments: 190 - addend (:obj:`Any`): The addend. 191 """ 192 193 return _math_binary(lambda x, y: x + y, addend) 194 195 196def minus(subtrahend) -> ILoaderClass: 197 """ 198 Overview: 199 Create a minus loader. 200 Arguments: 201 - subtrahend (:obj:`Any`): The subtrahend. 202 """ 203 204 return _math_binary(lambda x, y: x - y, subtrahend) 205 206 207def minus_with(minuend) -> ILoaderClass: 208 """ 209 Overview: 210 Create a minus loader. 211 Arguments: 212 - minuend (:obj:`Any`): The minuend. 213 """ 214 215 return _math_binary(lambda x, y: y - x, minuend) 216 217 218def multi(multiplier) -> ILoaderClass: 219 """ 220 Overview: 221 Create a multi loader. 222 Arguments: 223 - multiplier (:obj:`Any`): The multiplier. 224 """ 225 226 return _math_binary(lambda x, y: x * y, multiplier) 227 228 229def divide(divisor) -> ILoaderClass: 230 """ 231 Overview: 232 Create a divide loader. 233 Arguments: 234 - divisor (:obj:`Any`): The divisor. 235 """ 236 237 return _math_binary(lambda x, y: x / y, divisor) 238 239 240def divide_with(dividend) -> ILoaderClass: 241 """ 242 Overview: 243 Create a divide loader. 244 Arguments: 245 - dividend (:obj:`Any`): The dividend. 246 """ 247 248 return _math_binary(lambda x, y: y / x, dividend) 249 250 251def power(index) -> ILoaderClass: 252 """ 253 Overview: 254 Create a power loader. 255 Arguments: 256 - index (:obj:`Any`): The index. 257 """ 258 259 return _math_binary(lambda x, y: x ** y, index) 260 261 262def power_with(base) -> ILoaderClass: 263 """ 264 Overview: 265 Create a power loader. 266 Arguments: 267 - base (:obj:`Any`): The base. 268 """ 269 270 return _math_binary(lambda x, y: y ** x, base) 271 272 273def msum(*items) -> ILoaderClass: 274 """ 275 Overview: 276 Create a sum loader. 277 Arguments: 278 - items (:obj:`tuple`): The items. 279 """ 280 281 def _load(value): 282 return sum([item(value) for item in items]) 283 284 return Loader(_load) 285 286 287def mmulti(*items) -> ILoaderClass: 288 """ 289 Overview: 290 Create a multi loader. 291 Arguments: 292 - items (:obj:`tuple`): The items. 293 """ 294 295 def _load(value): 296 _result = 1 297 for item in items: 298 _result *= item(value) 299 return _result 300 301 return Loader(_load) 302 303 304_COMPARE_OPERATORS = { 305 '!=': operator.__ne__, 306 '==': operator.__eq__, 307 '<': operator.__lt__, 308 '<=': operator.__le__, 309 '>': operator.__gt__, 310 '>=': operator.__ge__, 311} 312 313 314def _msinglecmp(first, op, second) -> ILoaderClass: 315 """ 316 Overview: 317 Create a single compare loader. 318 Arguments: 319 - first (:obj:`Any`): The first item. 320 - op (:obj:`str`): The operator. 321 - second (:obj:`Any`): The second item. 322 """ 323 324 first = Loader(first) 325 second = Loader(second) 326 327 if op in _COMPARE_OPERATORS.keys(): 328 return Loader( 329 ( 330 lambda x: _COMPARE_OPERATORS[op](first(x), second(x)), lambda x: ValueError( 331 'comparison failed for {first} {op} {second}'.format( 332 first=repr(first(x)), 333 second=repr(second(x)), 334 op=op, 335 ) 336 ) 337 ) 338 ) 339 else: 340 raise KeyError('Invalid compare operator - {op}.'.format(op=repr(op))) 341 342 343def mcmp(first, *items) -> ILoaderClass: 344 """ 345 Overview: 346 Create a multi compare loader. 347 Arguments: 348 - first (:obj:`Any`): The first item. 349 - items (:obj:`tuple`): The items. 350 """ 351 352 if len(items) % 2 == 1: 353 raise ValueError('Count of items should be odd number but {number} found.'.format(number=len(items) + 1)) 354 355 ops, items = items[0::2], items[1::2] 356 357 _result = keep() 358 for first, op, second in zip((first, ) + items[:-1], ops, items): 359 _result &= _msinglecmp(first, op, second) 360 361 return check_only(_result)