Python's math module¶
The standard math module of python cannot be interfaced to work transparently with physipy. We propose an drop-in replace module in physipy.math so you get the same functions from the standard module while supporting units.
import math
from math import pi
from physipy import m, rad, Quantity, Dimension
import physipy.math as phymath
If the inputs are regular numbers (like int and float), you'll get the same results as with the standard math module - but with a speed loss due to the unit-handling overhead :
print(math.cos(5)) # call from the standard module
print(phymath.cos(5)) # call from the physipy module
0.28366218546322625
0.28366218546322625
When using the physipy.math module, dimension checks are made to the inputs of the functions where this applies. For example, the trigonomectric functions do not accept units except angles :
# trigonometric functions accept quantities that are angles
print(phymath.cos(pi*rad))
# but not any other units
try:
phymath.cos(pi*m)
except BaseException as e:
print("Trigonometrics functions only accept quantities that are angles or are unitless : ")
print(e)
-1.0
Trigonometrics functions only accept quantities that are angles or are unitless :
Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless).
Some function will return a Quantity if the input is itself a Quantity, with the same unit - like the ceil function :
print(math.ceil(5.3)) # using standard module
print(phymath.ceil(5.3)) # using physipy's math module on a float
print(phymath.ceil(5.3*m)) # using physipy's math module on a Quantity
6
6
6 m
Overall, each function has a precise way to deal with units - wheter it is to check the input or to return unitfull quantities, depending on the underlying mathematical operations of that function.
An in-depth comparison between math and physipy.math¶
import math
from math import acos, acosh, asin, asinh, atan, atan2, atanh
from math import ceil, copysign, comb, cos, cosh
from math import degrees, dist
from math import erf, erfc, exp, expm1
from math import fabs, factorial, floor, fmod, frexp, fsum
from math import gamma, gcd
from math import hypot
from math import isclose, isfinite, isinf, isnan, isqrt
from math import ldexp, lgamma, log, log10, log1p, log2
from math import modf
from math import perm, pow as math_pow, prod
from math import radians, remainder
from math import sin, sinh, sqrt
from math import tan, tanh, trunc
import physipy
# from math import nextafter, ulp, lcm
a = 5.123 * m
b = -2*m
math_params = {
"acos" :(acos , a ),
"acosh" :(acosh , a ),
"asin" :(asin , a ),
"asinh" :(asinh , a ),
"atan" :(atan , a ),
"atan2" :(atan2 , (a,b) ),
"atanh" :(atanh , a ),
"ceil" :(ceil , a ),
"coysign" :(copysign , (a, b) ),
#"comb" :(comb , 10, 3),
"cos" :(cos , a ),
"cosh" :(cosh , a ),
"degrees" :(degrees , a ),
"dist" :(dist , ([1*m, 3*m], [2*m, 5*m])),
"erf" :(erf , a ),
"erfc" :(erfc , a ),
"exp" :(exp , a ),
"expm1" :(expm1 , a ),
"fabs" :(fabs , a ),
"floor" :(floor , a ),
"fmod" :(fmod , (a, b) ),
"fsum" :(fsum , [a, a, a]),
"gamma" :(gamma , a ),
"gcd" :(gcd , (a, a) ),
"hypot" :(hypot , a ),
"isclose" :(isclose , (a, b) ),
"isfinite" :(isfinite , a ),
"isinf" :(isinf , a ),
"isnan" :(isnan , a ),
"isqrt" :(isqrt , a ),
"ldexp" :(ldexp , (a, a) ),
"lgamma" :(lgamma , a ),
"log" :(log , a ),
"log10" :(log10 , a ),
"log1p" :(log1p , a ),
"log2" :(log2 , a ),
"modf" :(modf , a ),
"perm" :(perm , a ),
"pow" :(math_pow , (a, 2) ),
"prod" :(prod , [a, a] ),
"radians" :(radians , a ),
"remainder":(remainder, (a, b) ),
"sin" :(sin , a ),
"sinh" :(sinh , a ),
"sqrt" :(sqrt , a ),
"tan" :(tan , a ),
"tanh" :(tanh , a ),
"trunc" :(trunc , a ),
}
q_rad = 0.4*rad
q = 2.123*m
q_dimless = Quantity(1, Dimension(None))
physipy_math_params = {
"acos" :(physipy.math.acos , q_dimless ),
"acosh" :(physipy.math.acosh , q_dimless ),
"asin" :(physipy.math.asin , q_dimless ),
"asinh" :(physipy.math.asinh , q_dimless ),
"atan" :(physipy.math.atan , q_dimless ),
"atan2" :(physipy.math.atan2 , (q,q) ),
"atanh" :(physipy.math.atanh , q_dimless ),
"ceil" :(physipy.math.ceil , q ),
"coysign" :(physipy.math.copysign , (q, q) ),
#"comb" :(comb , 10, 3),
"cos" :(physipy.math.cos , q ),
"cosh" :(physipy.math.cosh , q ),
"degrees" :(physipy.math.degrees , q ),
"dist" :(physipy.math.dist , ([q, q], [q, q])),
"erf" :(physipy.math.erf , q ),
"erfc" :(physipy.math.erfc , q ),
"exp" :(physipy.math.exp , q ),
"expm1" :(physipy.math.expm1 , q ),
"fabs" :(physipy.math.fabs , q ),
"floor" :(physipy.math.floor , q ),
"fmod" :(physipy.math.fmod , (q, q) ),
"fsum" :(physipy.math.fsum , [q, q, q]),
"gamma" :(physipy.math.gamma , q ),
"gcd" :(physipy.math.gcd , (q, q) ),
"hypot" :(physipy.math.hypot ,q ),
"isclose" :(physipy.math.isclose , (a, b) ),
"isfinite" :(physipy.math.isfinite ,q ),
"isinf" :(physipy.math.isinf ,q ),
"isnan" :(physipy.math.isnan ,q ),
"isqrt" :(physipy.math.isqrt ,q ),
"ldexp" :(physipy.math.ldexp , (q,q) ),
"lgamma" :(physipy.math.lgamma ,q_dimless ),
"log" :(physipy.math.log ,q_dimless ),
"log10" :(physipy.math.log10 ,q_dimless ),
"log1p" :(physipy.math.log1p ,q_dimless ),
"log2" :(physipy.math.log2 ,q_dimless ),
"modf" :(physipy.math.modf ,q ),
"perm" :(physipy.math.perm ,q ),
"pow" :(physipy.math.pow , (q, 2) ),
"prod" :(physipy.math.prod , [q,q] ),
"radians" :(physipy.math.radians ,q ),
"remainder":(physipy.math.remainder, (q, b) ),
"sin" :(physipy.math.sin ,q ),
"sinh" :(physipy.math.sinh ,q ),
"sqrt" :(physipy.math.sqrt ,q ),
"tan" :(physipy.math.tan ,q ),
"tanh" :(physipy.math.tanh ,q ),
"trunc" :(physipy.math.trunc ,q ),
}
import time
class Timer():
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, *args):
self.end = time.time()
self.secs = self.end - self.start
self.msecs = self.secs * 1000 # millisecs
def color_green_true_red_false(val):
"""
Takes a scalar and returns a string with
the css property `'color: red'` for negative
strings, black otherwise.
"""
color = 'green' if val else 'red'
return 'color: %s' % color
def compute_results_dic(param_dict):
res = {}
for name, func_and_args in param_dict.items():
func, args = func_and_args
results = {}
try:
results["Input"] = ", ".join([str(i) for i in args])
except:
results["Input"] = str(args)
if type(args) is tuple:
# For math
try:
with Timer() as timer:
v = func(*args)
# v = getattr(phymath, name)(*args)
results["Passed"] = True
results["Returned"] = str(v)
results["Time"] = timer.msecs
except Exception as e:
results["Passed"] = False
results["Returned"] = str(e)
results["Time"] = None
else:
try:
with Timer() as timer:
v = func(args)
# v = getattr(phymath, name)(args)
results["Passed"] = True
results["Returned"] = str(v)
results["Time"] = timer.msecs
except Exception as e:
results["Passed"] = False
results["Returned"] = str(e)
results["Time"] = None
res[name] = results
return res
res_math = compute_results_dic(math_params)
res_phymath = compute_results_dic(physipy_math_params)
import pandas as pd
df_math = pd.DataFrame.from_dict(res_math, orient="index")
df_math = df_math.style.applymap(color_green_true_red_false, subset=pd.IndexSlice[:, ['Passed']])
df_phymath = pd.DataFrame.from_dict(res_phymath, orient="index")
df_phymath = df_phymath.style.applymap(color_green_true_red_false, subset=pd.IndexSlice[:, ['Passed']])
C:\Users\ym\Documents\REPOS\physipy\physipy\quantity\quantity.py:753: UserWarning: The unit of the quantity is stripped for __array_struct__
warnings.warn(f"The unit of the quantity is stripped for {item}")
| Input | Passed | Returned | Time | |
|---|---|---|---|---|
| acos | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| acosh | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| asin | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| asinh | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| atan | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| atan2 | 5.123 m, -2 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| atanh | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| ceil | 5.123 m | True | 6 m | 0.000000 |
| coysign | 5.123 m, -2 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| cos | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| cosh | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| degrees | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| dist | [ |
False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| erf | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| erfc | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| exp | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| expm1 | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| fabs | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| floor | 5.123 m | True | 5 m | 0.000000 |
| fmod | 5.123 m, -2 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| fsum | 5.123 m, 5.123 m, 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| gamma | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| gcd | 5.123 m, 5.123 m | False | 'Quantity' object cannot be interpreted as an integer | nan |
| hypot | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| isclose | 5.123 m, -2 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| isfinite | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| isinf | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| isnan | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| isqrt | 5.123 m | False | 'Quantity' object cannot be interpreted as an integer | nan |
| ldexp | 5.123 m, 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| lgamma | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| log | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| log10 | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| log1p | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| log2 | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| modf | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| perm | 5.123 m | False | 'Quantity' object cannot be interpreted as an integer | nan |
| pow | 5.123 m, 2 | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| prod | 5.123 m, 5.123 m | True | 26.245129000000002 m**2 | 0.000000 |
| radians | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| remainder | 5.123 m, -2 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| sin | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| sinh | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| sqrt | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| tan | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| tanh | 5.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| trunc | 5.123 m | True | 5 m | 0.000000 |
| Input | Passed | Returned | Time | |
|---|---|---|---|---|
| acos | 1 | True | 0.0 | 0.000000 |
| acosh | 1 | True | 0.0 | 0.000000 |
| asin | 1 | True | 1.5707963267948966 | 0.000000 |
| asinh | 1 | True | 0.8813735870195429 | 0.000000 |
| atan | 1 | True | 0.7853981633974483 | 0.000000 |
| atan2 | 2.123 m, 2.123 m | True | 0.7853981633974483 | 0.000000 |
| atanh | 1 | False | math domain error | nan |
| ceil | 2.123 m | True | 3 m | 0.000000 |
| coysign | 2.123 m, 2.123 m | True | 2.123 m | 0.000000 |
| cos | 2.123 m | False | Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). | nan |
| cosh | 2.123 m | False | Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). | nan |
| degrees | 2.123 m | False | nan | |
| dist | [ |
False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| erf | 2.123 m | False | Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). | nan |
| erfc | 2.123 m | False | Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). | nan |
| exp | 2.123 m | False | Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). | nan |
| expm1 | 2.123 m | False | Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). | nan |
| fabs | 2.123 m | True | 2.123 m | 0.000000 |
| floor | 2.123 m | True | 2 m | 0.000000 |
| fmod | 2.123 m, 2.123 m | True | 0.0 m | 0.000000 |
| fsum | 2.123 m, 2.123 m, 2.123 m | False | setting an array element with a sequence. | nan |
| gamma | 2.123 m | False | Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). | nan |
| gcd | 2.123 m, 2.123 m | False | nan | |
| hypot | 2.123 m | False | Dimension error : dimension is L but should be no-dimension (length vs dimensionless). | nan |
| isclose | 5.123 m, -2 m | False | nan | |
| isfinite | 2.123 m | True | True | 0.000000 |
| isinf | 2.123 m | True | False | 0.000000 |
| isnan | 2.123 m | True | False | 0.000000 |
| isqrt | 2.123 m | False | nan | |
| ldexp | 2.123 m, 2.123 m | False | nan | |
| lgamma | 1 | True | 0.0 | 0.000000 |
| log | 1 | True | 0.0 | 0.000000 |
| log10 | 1 | True | 0.0 | 0.000000 |
| log1p | 1 | True | 0.6931471805599453 | 0.000000 |
| log2 | 1 | True | 0.0 | 0.000000 |
| modf | 2.123 m | False | nan | |
| perm | 2.123 m | False | nan | |
| pow | 2.123 m, 2 | False | nan | |
| prod | 2.123 m, 2.123 m | True | 4.507129000000001 m**2 | 0.000000 |
| radians | 2.123 m | False | nan | |
| remainder | 2.123 m, -2 m | True | 0.12300000000000022 m | 0.000000 |
| sin | 2.123 m | False | Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). | nan |
| sinh | 2.123 m | False | Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). | nan |
| sqrt | 2.123 m | True | 1.4570518178843195 m**0.5 | 0.000000 |
| tan | 2.123 m | False | Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). | nan |
| tanh | 2.123 m | False | Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). | nan |
| trunc | 2.123 m | False | type numpy.ndarray doesn't define __trunc__ method | nan |