Source code for crystalpy.util.CalculationStrategy

"""
Numeric strategy for calculation. The exp, sin and cos functions are calculated using numpy,
numpy with truncation of the arguments, or arbitrary precision using mpmath.
"""

import numpy

[docs]class CalculationStrategy(object): """Abstract strategy for calculation. Can be plain python or arbitrary precision like mpmath."""
[docs] def createVariable(self, initial_value): """Factory method for calculation variable. Parameters ---------- initial_value : Initial value of the variable. Raises ------ Exception Must override this method. """ raise Exception("Must override this method.")
[docs] def exponentiate(self, power): """Exponentiates to the power. Parameters ---------- power : The power to raise to. Raises ------ Exception Must override this method. """ raise Exception("Must override this method.")
[docs] def sin(self, power): """Sin to the power. Parameters ---------- power : The power to raise to. Raises ------ Exception Must override this method. """ raise Exception("Must override this method.")
[docs] def cos(self, power): """Cos to the power. Parameters ---------- power : The power to raise to. Raises ------ Exception Must override this method. """ raise Exception("Must override this method.")
[docs] def toComplex(self, variable): """Converts calculation variable to native python complex. Parameters ---------- variable : Calculation variable to convert. Raises ------ Exception Must override this method. """ raise Exception("Must override this method.")
[docs]class CalculationStrategyMPMath(CalculationStrategy): """Use mpmath for calculation.""" def __init__(self): """ Constructor. """ import mpmath self.mpmath_sin = numpy.vectorize(mpmath.sin) self.mpmath_cos = numpy.vectorize(mpmath.cos) self.mpmath_exp = numpy.vectorize(mpmath.exp) self.mpmath_mpc = mpmath.mpc # Use 32 digits in mpmath calculations. mpmath.mp.dps = 32
[docs] def createVariable(self, initial_value): """Factory method for calculation variable. Parameters ---------- initial_value : float, complex or numpy array Initial value of the variable. Returns ------- instance of CalculationStrategyMPMath variable. """ if not(isinstance(initial_value, numpy.ndarray)): initial_value = numpy.array(initial_value) if initial_value.size == 1: mpc = self.mpmath_mpc(complex(initial_value.real) + 1j * complex(initial_value.imag)) else: mpc = self.mpmath_mpc(complex(1) + 1j * complex(0)) * initial_value return mpc
[docs] def exponentiate(self, power): """Exponentiates to the power. Parameters ---------- power : float The power to raise to. Returns ------- mpmath variable Exponential. """ return self.mpmath_exp(power)
[docs] def sin(self, power): """Sin function. Parameters ---------- power : float or numpy array The arg of sin. Returns ------- mpmath variable Sin. """ return self.mpmath_sin(power)
[docs] def cos(self, power): """Cos function. Parameters ---------- power : float or numpy array The arg of cos. Returns ------- mpmath variable Cos. """ return self.mpmath_cos(power)
[docs] def toComplex(self, variable): """Converts calculation variable to native python complex. Parameters ---------- variable : variable to convert. Returns ------- numpy array Native python complex variable. """ return numpy.array(variable, dtype=complex)
[docs]class CalculationStrategyNumpy(CalculationStrategy): """Use plain python for calculation."""
[docs] def createVariable(self, initial_value): """Factory method for calculation variable. Parameters ---------- initial_value : Initial value of the variable. Returns ------- instance of CalculationStrategyNumpy variable. """ return initial_value + 0j # complex(initial_value)
[docs] def exponentiate(self, power): """Exponentiates to the power. Parameters ---------- power : float The power to raise to. Returns ------- numpy array Exponential. """ try: ans = numpy.exp(power) except: ans = float("Inf") return ans
[docs] def sin(self, power): """Sin function. Parameters ---------- power : The sin argument. Returns ------- numpy array Sin. """ return numpy.sin(power)
[docs] def cos(self, power): """Cos function. Parameters ---------- power : The coa argument. Returns ------- numpy array Cos. """ return numpy.cos(power)
[docs] def toComplex(self, variable): """Converts calculation variable to native python complex. Parameters ---------- variable : Calculation variable to convert. Returns ------- numpy array (complex) Native python complex variable. """ return complex(variable)
[docs]class CalculationStrategyNumpyTruncated(CalculationStrategy): """Use plain python for calculation.""" def __init__(self, limit=1000): self.limit = limit
[docs] def createVariable(self, initial_value): """Factory method for calculation variable. Parameters ---------- initial_value : Initial value of the variable. Returns ------- instance of CalculationStrategyNumpy variable. """ return initial_value + 0j # complex(initial_value)
[docs] def exponentiate(self, power): """Exponentiates to the power. Parameters ---------- power : float The power to raise to. Returns ------- numpy array Exponential. """ if power.size == 1: power1 = numpy.array([power], dtype=numpy.complex128) else: power1 = numpy.array(power, dtype=numpy.complex128) if numpy.any(power1.real > self.limit): ii = numpy.where(power1.real > self.limit) power1[ii] = self.limit + power1.imag[ii] * 1j try: ans = numpy.exp(power1) except: ans = float("Inf") return ans
[docs] def sin(self, power): """Sin function. Parameters ---------- power : The sin argument. Returns ------- numpy array Sin. """ if power.size == 1: power1 = numpy.array([power]) else: power1 = numpy.array(power) if numpy.any(power1.imag > self.limit): ii = numpy.where(power1.imag > self.limit) power1[ii] = power1.real[ii] + self.limit * 1j if numpy.any(power1.imag < -self.limit): ii = numpy.where(power1.imag < self.limit) power1[ii] = power1.real[ii] - self.limit * 1j ans = numpy.sin(power1) return ans
[docs] def cos(self, power): """Cos function. Parameters ---------- power : The coa argument. Returns ------- numpy array Cos. """ if power.size == 1: power1 = numpy.array([power]) else: power1 = numpy.array(power) if numpy.any(power1.imag > self.limit): ii = numpy.where(power1.imag > self.limit) power1[ii] = power1.real[ii] + self.limit * 1j if numpy.any(power1.imag < -self.limit): ii = numpy.where(power1.imag < self.limit) power1[ii] = power1.real[ii] - self.limit * 1j ans = numpy.cos(power1) return ans
[docs] def toComplex(self, variable): """Converts calculation variable to native python complex. Parameters ---------- variable : Calculation variable to convert. Returns ------- numpy array (complex) Native python complex variable. """ return complex(variable)
if __name__ == "__main__": a = CalculationStrategyMPMath() a0 = a.createVariable(numpy.array(0)) print(type(a)) print("cos(0)", a.cos(a0)) api = a.createVariable(numpy.array(numpy.pi)) print("cos(pi)", a.cos(api)) api = a.createVariable(numpy.array([numpy.pi] * 10)) print("cos(pi)", a.cos(api)) # print("exp(pi)", a.exponentiate(api))