-
Notifications
You must be signed in to change notification settings - Fork 839
/
num.py
169 lines (125 loc) · 4.48 KB
/
num.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# coding: utf-8
# Copyright (c) Pymatgen Development Team.
# Distributed under the terms of the MIT License.
"""
This module provides utilities for basic math operations.
"""
import collections
import numpy as np
def abs_cap(val, max_abs_val=1):
"""
Returns the value with its absolute value capped at max_abs_val.
Particularly useful in passing values to trignometric functions where
numerical errors may result in an argument > 1 being passed in.
Args:
val (float): Input value.
max_abs_val (float): The maximum absolute value for val. Defaults to 1.
Returns:
val if abs(val) < 1 else sign of val * max_abs_val.
"""
return max(min(val, max_abs_val), -max_abs_val)
def sort_dict(d, key=None, reverse=False):
"""
Sorts a dict by value.
Args:
d: Input dictionary
key: Function which takes an tuple (key, object) and returns a value to
compare and sort by. By default, the function compares the values
of the dict i.e. key = lambda t : t[1]
reverse: Allows to reverse sort order.
Returns:
OrderedDict object whose keys are ordered according to their value.
"""
kv_items = list(d.items())
# Sort kv_items according to key.
if key is None:
kv_items.sort(key=lambda t: t[1], reverse=reverse)
else:
kv_items.sort(key=key, reverse=reverse)
# Build ordered dict.
return collections.OrderedDict(kv_items)
def minloc(seq):
"""
Return the index of the (first) minimum in seq
>>> assert minloc(range(3)) == 0
"""
return min(enumerate(seq), key=lambda s: s[1])[0]
def maxloc(seq):
"""
Return the index of the (first) maximum in seq
>>> assert maxloc([1,3,2,3]) == 1
"""
return max(enumerate(seq), key=lambda s: s[1])[0]
def min_max_indexes(seq):
"""
Uses enumerate, max, and min to return the indices of the values
in a list with the maximum and minimum value:
"""
l = sorted(enumerate(seq), key=lambda s: s[1])
return l[0][0], l[-1][0]
def strictly_increasing(values):
"""True if values are stricly increasing."""
return all(x < y for x, y in zip(values, values[1:]))
def strictly_decreasing(values):
"""True if values are stricly decreasing."""
return all(x > y for x, y in zip(values, values[1:]))
def non_increasing(values):
"""True if values are not increasing."""
return all(x >= y for x, y in zip(values, values[1:]))
def non_decreasing(values):
"""True if values are not decreasing."""
return all(x <= y for x, y in zip(values, values[1:]))
def monotonic(values, mode="<", atol=1.0e-8):
"""
Returns False if values are not monotonic (decreasing|increasing).
mode is "<" for a decreasing sequence, ">" for an increasing sequence.
Two numbers are considered equal if they differ less that atol.
.. warning:
Not very efficient for large data sets.
>>> values = [1.2, 1.3, 1.4]
>>> monotonic(values, mode="<")
False
>>> monotonic(values, mode=">")
True
"""
if len(values) == 1:
return True
if mode == ">":
for i in range(len(values) - 1):
v, vp = values[i], values[i + 1]
if abs(vp - v) > atol and vp <= v:
return False
elif mode == "<":
for i in range(len(values) - 1):
v, vp = values[i], values[i + 1]
if abs(vp - v) > atol and vp >= v:
return False
raise ValueError("Wrong mode %s" % str(mode))
def round_to_sigfigs(num, sigfigs):
"""
Rounds a number rounded to a specific number of significant
figures instead of to a specific precision.
"""
if not isinstance(sigfigs, int):
raise TypeError("Number of significant figures must be integer.")
if sigfigs < 1:
raise ValueError("Number of significant figures " "must be larger than zero.")
if num == 0:
return num
prec = int(sigfigs - np.ceil(np.log10(np.absolute(num))))
return round(num, prec)
def make_symmetric_matrix_from_upper_tri(val):
"""
Given a symmetric matrix in upper triangular matrix form as flat array indexes as:
[A_xx,A_yy,A_zz,A_xy,A_xz,A_yz]
This will generate the full matrix:
[[A_xx,A_xy,A_xz],[A_xy,A_yy,A_yz],[A_xz,A_yz,A_zz]
"""
idx = [0, 3, 4, 1, 5, 2]
val = np.array(val)[idx]
mask = ~np.tri(3, k=-1, dtype=bool)
out = np.zeros((3, 3), dtype=val.dtype)
out[mask] = val
# pylint: disable=E1137
out.T[mask] = val
return out