m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
6.0 KiB

6 months ago
  1. """
  2. Various richly-typed exceptions, that also help us deal with string formatting
  3. in python where it's easier.
  4. By putting the formatting in `__str__`, we also avoid paying the cost for
  5. users who silence the exceptions.
  6. """
  7. from numpy.core.overrides import set_module
  8. def _unpack_tuple(tup):
  9. if len(tup) == 1:
  10. return tup[0]
  11. else:
  12. return tup
  13. def _display_as_base(cls):
  14. """
  15. A decorator that makes an exception class look like its base.
  16. We use this to hide subclasses that are implementation details - the user
  17. should catch the base type, which is what the traceback will show them.
  18. Classes decorated with this decorator are subject to removal without a
  19. deprecation warning.
  20. """
  21. assert issubclass(cls, Exception)
  22. cls.__name__ = cls.__base__.__name__
  23. return cls
  24. class UFuncTypeError(TypeError):
  25. """ Base class for all ufunc exceptions """
  26. def __init__(self, ufunc):
  27. self.ufunc = ufunc
  28. @_display_as_base
  29. class _UFuncBinaryResolutionError(UFuncTypeError):
  30. """ Thrown when a binary resolution fails """
  31. def __init__(self, ufunc, dtypes):
  32. super().__init__(ufunc)
  33. self.dtypes = tuple(dtypes)
  34. assert len(self.dtypes) == 2
  35. def __str__(self):
  36. return (
  37. "ufunc {!r} cannot use operands with types {!r} and {!r}"
  38. ).format(
  39. self.ufunc.__name__, *self.dtypes
  40. )
  41. @_display_as_base
  42. class _UFuncNoLoopError(UFuncTypeError):
  43. """ Thrown when a ufunc loop cannot be found """
  44. def __init__(self, ufunc, dtypes):
  45. super().__init__(ufunc)
  46. self.dtypes = tuple(dtypes)
  47. def __str__(self):
  48. return (
  49. "ufunc {!r} did not contain a loop with signature matching types "
  50. "{!r} -> {!r}"
  51. ).format(
  52. self.ufunc.__name__,
  53. _unpack_tuple(self.dtypes[:self.ufunc.nin]),
  54. _unpack_tuple(self.dtypes[self.ufunc.nin:])
  55. )
  56. @_display_as_base
  57. class _UFuncCastingError(UFuncTypeError):
  58. def __init__(self, ufunc, casting, from_, to):
  59. super().__init__(ufunc)
  60. self.casting = casting
  61. self.from_ = from_
  62. self.to = to
  63. @_display_as_base
  64. class _UFuncInputCastingError(_UFuncCastingError):
  65. """ Thrown when a ufunc input cannot be casted """
  66. def __init__(self, ufunc, casting, from_, to, i):
  67. super().__init__(ufunc, casting, from_, to)
  68. self.in_i = i
  69. def __str__(self):
  70. # only show the number if more than one input exists
  71. i_str = "{} ".format(self.in_i) if self.ufunc.nin != 1 else ""
  72. return (
  73. "Cannot cast ufunc {!r} input {}from {!r} to {!r} with casting "
  74. "rule {!r}"
  75. ).format(
  76. self.ufunc.__name__, i_str, self.from_, self.to, self.casting
  77. )
  78. @_display_as_base
  79. class _UFuncOutputCastingError(_UFuncCastingError):
  80. """ Thrown when a ufunc output cannot be casted """
  81. def __init__(self, ufunc, casting, from_, to, i):
  82. super().__init__(ufunc, casting, from_, to)
  83. self.out_i = i
  84. def __str__(self):
  85. # only show the number if more than one output exists
  86. i_str = "{} ".format(self.out_i) if self.ufunc.nout != 1 else ""
  87. return (
  88. "Cannot cast ufunc {!r} output {}from {!r} to {!r} with casting "
  89. "rule {!r}"
  90. ).format(
  91. self.ufunc.__name__, i_str, self.from_, self.to, self.casting
  92. )
  93. # Exception used in shares_memory()
  94. @set_module('numpy')
  95. class TooHardError(RuntimeError):
  96. pass
  97. @set_module('numpy')
  98. class AxisError(ValueError, IndexError):
  99. """ Axis supplied was invalid. """
  100. def __init__(self, axis, ndim=None, msg_prefix=None):
  101. # single-argument form just delegates to base class
  102. if ndim is None and msg_prefix is None:
  103. msg = axis
  104. # do the string formatting here, to save work in the C code
  105. else:
  106. msg = ("axis {} is out of bounds for array of dimension {}"
  107. .format(axis, ndim))
  108. if msg_prefix is not None:
  109. msg = "{}: {}".format(msg_prefix, msg)
  110. super().__init__(msg)
  111. @_display_as_base
  112. class _ArrayMemoryError(MemoryError):
  113. """ Thrown when an array cannot be allocated"""
  114. def __init__(self, shape, dtype):
  115. self.shape = shape
  116. self.dtype = dtype
  117. @property
  118. def _total_size(self):
  119. num_bytes = self.dtype.itemsize
  120. for dim in self.shape:
  121. num_bytes *= dim
  122. return num_bytes
  123. @staticmethod
  124. def _size_to_string(num_bytes):
  125. """ Convert a number of bytes into a binary size string """
  126. # https://en.wikipedia.org/wiki/Binary_prefix
  127. LOG2_STEP = 10
  128. STEP = 1024
  129. units = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']
  130. unit_i = max(num_bytes.bit_length() - 1, 1) // LOG2_STEP
  131. unit_val = 1 << (unit_i * LOG2_STEP)
  132. n_units = num_bytes / unit_val
  133. del unit_val
  134. # ensure we pick a unit that is correct after rounding
  135. if round(n_units) == STEP:
  136. unit_i += 1
  137. n_units /= STEP
  138. # deal with sizes so large that we don't have units for them
  139. if unit_i >= len(units):
  140. new_unit_i = len(units) - 1
  141. n_units *= 1 << ((unit_i - new_unit_i) * LOG2_STEP)
  142. unit_i = new_unit_i
  143. unit_name = units[unit_i]
  144. # format with a sensible number of digits
  145. if unit_i == 0:
  146. # no decimal point on bytes
  147. return '{:.0f} {}'.format(n_units, unit_name)
  148. elif round(n_units) < 1000:
  149. # 3 significant figures, if none are dropped to the left of the .
  150. return '{:#.3g} {}'.format(n_units, unit_name)
  151. else:
  152. # just give all the digits otherwise
  153. return '{:#.0f} {}'.format(n_units, unit_name)
  154. def __str__(self):
  155. size_str = self._size_to_string(self._total_size)
  156. return (
  157. "Unable to allocate {} for an array with shape {} and data type {}"
  158. .format(size_str, self.shape, self.dtype)
  159. )