Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/boltons/mathutils.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
comparison
equal
deleted
inserted
replaced
4:79f47841a781 | 5:9b1c78e6ba9c |
---|---|
1 """This module provides useful math functions on top of Python's | |
2 built-in :mod:`math` module. | |
3 """ | |
4 from __future__ import division | |
5 | |
6 from math import ceil as _ceil, floor as _floor | |
7 import bisect | |
8 import binascii | |
9 | |
10 | |
11 def clamp(x, lower=float('-inf'), upper=float('inf')): | |
12 """Limit a value to a given range. | |
13 | |
14 Args: | |
15 x (int or float): Number to be clamped. | |
16 lower (int or float): Minimum value for x. | |
17 upper (int or float): Maximum value for x. | |
18 | |
19 The returned value is guaranteed to be between *lower* and | |
20 *upper*. Integers, floats, and other comparable types can be | |
21 mixed. | |
22 | |
23 >>> clamp(1.0, 0, 5) | |
24 1.0 | |
25 >>> clamp(-1.0, 0, 5) | |
26 0 | |
27 >>> clamp(101.0, 0, 5) | |
28 5 | |
29 >>> clamp(123, upper=5) | |
30 5 | |
31 | |
32 Similar to `numpy's clip`_ function. | |
33 | |
34 .. _numpy's clip: http://docs.scipy.org/doc/numpy/reference/generated/numpy.clip.html | |
35 | |
36 """ | |
37 if upper < lower: | |
38 raise ValueError('expected upper bound (%r) >= lower bound (%r)' | |
39 % (upper, lower)) | |
40 return min(max(x, lower), upper) | |
41 | |
42 | |
43 def ceil(x, options=None): | |
44 """Return the ceiling of *x*. If *options* is set, return the smallest | |
45 integer or float from *options* that is greater than or equal to | |
46 *x*. | |
47 | |
48 Args: | |
49 x (int or float): Number to be tested. | |
50 options (iterable): Optional iterable of arbitrary numbers | |
51 (ints or floats). | |
52 | |
53 >>> VALID_CABLE_CSA = [1.5, 2.5, 4, 6, 10, 25, 35, 50] | |
54 >>> ceil(3.5, options=VALID_CABLE_CSA) | |
55 4 | |
56 >>> ceil(4, options=VALID_CABLE_CSA) | |
57 4 | |
58 """ | |
59 if options is None: | |
60 return _ceil(x) | |
61 options = sorted(options) | |
62 i = bisect.bisect_left(options, x) | |
63 if i == len(options): | |
64 raise ValueError("no ceil options greater than or equal to: %r" % x) | |
65 return options[i] | |
66 | |
67 | |
68 def floor(x, options=None): | |
69 """Return the floor of *x*. If *options* is set, return the largest | |
70 integer or float from *options* that is less than or equal to | |
71 *x*. | |
72 | |
73 Args: | |
74 x (int or float): Number to be tested. | |
75 options (iterable): Optional iterable of arbitrary numbers | |
76 (ints or floats). | |
77 | |
78 >>> VALID_CABLE_CSA = [1.5, 2.5, 4, 6, 10, 25, 35, 50] | |
79 >>> floor(3.5, options=VALID_CABLE_CSA) | |
80 2.5 | |
81 >>> floor(2.5, options=VALID_CABLE_CSA) | |
82 2.5 | |
83 | |
84 """ | |
85 if options is None: | |
86 return _floor(x) | |
87 options = sorted(options) | |
88 | |
89 i = bisect.bisect_right(options, x) | |
90 if not i: | |
91 raise ValueError("no floor options less than or equal to: %r" % x) | |
92 return options[i - 1] | |
93 | |
94 | |
95 try: | |
96 _int_types = (int, long) | |
97 bytes = str | |
98 except NameError: | |
99 # py3 has no long | |
100 _int_types = (int,) | |
101 unicode = str | |
102 | |
103 | |
104 class Bits(object): | |
105 ''' | |
106 An immutable bit-string or bit-array object. | |
107 Provides list-like access to bits as bools, | |
108 as well as bitwise masking and shifting operators. | |
109 Bits also make it easy to convert between many | |
110 different useful representations: | |
111 | |
112 * bytes -- good for serializing raw binary data | |
113 * int -- good for incrementing (e.g. to try all possible values) | |
114 * list of bools -- good for iterating over or treating as flags | |
115 * hex/bin string -- good for human readability | |
116 | |
117 ''' | |
118 __slots__ = ('val', 'len') | |
119 | |
120 def __init__(self, val=0, len_=None): | |
121 if type(val) not in _int_types: | |
122 if type(val) is list: | |
123 val = ''.join(['1' if e else '0' for e in val]) | |
124 if type(val) is bytes: | |
125 val = val.decode('ascii') | |
126 if type(val) is unicode: | |
127 if len_ is None: | |
128 len_ = len(val) | |
129 if val.startswith('0x'): | |
130 len_ = (len_ - 2) * 4 | |
131 if val.startswith('0x'): | |
132 val = int(val, 16) | |
133 else: | |
134 if val: | |
135 val = int(val, 2) | |
136 else: | |
137 val = 0 | |
138 if type(val) not in _int_types: | |
139 raise TypeError('initialized with bad type: {0}'.format(type(val).__name__)) | |
140 if val < 0: | |
141 raise ValueError('Bits cannot represent negative values') | |
142 if len_ is None: | |
143 len_ = len('{0:b}'.format(val)) | |
144 if val > 2 ** len_: | |
145 raise ValueError('value {0} cannot be represented with {1} bits'.format(val, len_)) | |
146 self.val = val # data is stored internally as integer | |
147 self.len = len_ | |
148 | |
149 def __getitem__(self, k): | |
150 if type(k) is slice: | |
151 return Bits(self.as_bin()[k]) | |
152 if type(k) is int: | |
153 if k >= self.len: | |
154 raise IndexError(k) | |
155 return bool((1 << (self.len - k - 1)) & self.val) | |
156 raise TypeError(type(k)) | |
157 | |
158 def __len__(self): | |
159 return self.len | |
160 | |
161 def __eq__(self, other): | |
162 if type(self) is not type(other): | |
163 return NotImplemented | |
164 return self.val == other.val and self.len == other.len | |
165 | |
166 def __or__(self, other): | |
167 if type(self) is not type(other): | |
168 return NotImplemented | |
169 return Bits(self.val | other.val, max(self.len, other.len)) | |
170 | |
171 def __and__(self, other): | |
172 if type(self) is not type(other): | |
173 return NotImplemented | |
174 return Bits(self.val & other.val, max(self.len, other.len)) | |
175 | |
176 def __lshift__(self, other): | |
177 return Bits(self.val << other, self.len + other) | |
178 | |
179 def __rshift__(self, other): | |
180 return Bits(self.val >> other, self.len - other) | |
181 | |
182 def __hash__(self): | |
183 return hash(self.val) | |
184 | |
185 def as_list(self): | |
186 return [c == '1' for c in '{0:b}'.format(self.val)] | |
187 | |
188 def as_bin(self): | |
189 return '{{0:0{0}b}}'.format(self.len).format(self.val) | |
190 | |
191 def as_hex(self): | |
192 # make template to pad out to number of bytes necessary to represent bits | |
193 tmpl = '%0{0}X'.format(2 * (self.len // 8 + ((self.len % 8) != 0))) | |
194 ret = tmpl % self.val | |
195 return ret | |
196 | |
197 def as_int(self): | |
198 return self.val | |
199 | |
200 def as_bytes(self): | |
201 return binascii.unhexlify(self.as_hex()) | |
202 | |
203 @classmethod | |
204 def from_list(cls, list_): | |
205 return cls(list_) | |
206 | |
207 @classmethod | |
208 def from_bin(cls, bin): | |
209 return cls(bin) | |
210 | |
211 @classmethod | |
212 def from_hex(cls, hex): | |
213 if isinstance(hex, bytes): | |
214 hex = hex.decode('ascii') | |
215 if not hex.startswith('0x'): | |
216 hex = '0x' + hex | |
217 return cls(hex) | |
218 | |
219 @classmethod | |
220 def from_int(cls, int_, len_=None): | |
221 return cls(int_, len_) | |
222 | |
223 @classmethod | |
224 def from_bytes(cls, bytes_): | |
225 return cls.from_hex(binascii.hexlify(bytes_)) | |
226 | |
227 def __repr__(self): | |
228 cn = self.__class__.__name__ | |
229 return "{0}('{1}')".format(cn, self.as_bin()) |