def logSpaceAdd(update, before): ''' Assume a >= b We want to calculate ln(exp(ln(a))+exp(ln(b))), thus ln( exp(ln(b))*(1+exp(ln(a)-ln(b))) ) -> ln(b) + ln(1+exp(ln(a)-ln(b))) -> ln(b) + ln1p(exp(ln(a)-ln(b))) ''' #As there is no neutral element of addition in log space we only start adding when two values are given if before == None: return update else: a = None b = None #Check which value is larger if update > before: b = update a = before else: b = before a = update x = mp.mpf(a) - mp.mpf(b) #print(update,before) xexp = memoexp(x) #print('Exp:',xexp) val = memolog1p(xexp) #print('Log:',val) val = val + b if val == 0: print('a:{} b:{} x:{} xexp:{} log1p:{}'.format(a, b, x, xexp, val)) raise ValueError( 'LogSpace Addition has resulted in a value of 0: a = {} b = {} (possible underflow)' .format(a, b)) #elif val > 0: #print('a:{} b:{} x:{} xexp:{} log1p:{}'.format(a,b,x,xexp,val)) #raise ValueError('Prior Update has resulted in a value > 0: a = {} b = {} val = {}'.format(a,b,val)) if before == val: #print('a:{} b:{} x:{} xexp:{} log1p:{}'.format(a,b,x,xexp,val)) logging.warning( 'LogAddition had no effect: a = {} b = {} val = {}'.format( a, b, val)) #raise ValueError('LogAddition had no effect: a = {} b = {} val = {}'.format(a,b,val)) #raise ValueError('LogAddition had no effect!') if mp.isnan(val): raise ValueError( 'LogSpace Addition has resulted in a value of nan: a = {} b = {}' .format(a, b)) if mp.fabs(val) > 1000: #At this point who cares let's round a bit val = mp.floor(val) return val
def __refine_results(self, intermediate_results: List[Match], print_results=True): """ validate intermediate results to 100 digit precision :param intermediate_results: list of results from first enumeration :param print_results: if true print status. :return: final results. """ results = [] counter = 0 n_iterations = len(intermediate_results) constant_vals = [const() for const in self.constants_generator] for r in intermediate_results: counter += 1 if (counter % 50) == 0 and print_results: print( 'passed {} permutations out of {}. found so far {} matches' .format(counter, n_iterations, len(results))) try: val = self.hash_table.evaluate(r.lhs_key, constant_vals) if mpmath.isinf(val) or mpmath.isnan(val): # safety continue except (ZeroDivisionError, KeyError) as e: continue # create a_n, b_n with huge length, calculate gcf, and verify result. an = self.create_an_series(r.rhs_an_poly, g_N_verify_terms) bn = self.create_bn_series(r.rhs_bn_poly, g_N_verify_terms) gcf = EfficientGCF(an, bn) val_str = mpmath.nstr(val, g_N_verify_compare_length) rhs_str = mpmath.nstr(gcf.evaluate(), g_N_verify_compare_length) if val_str == rhs_str: results.append(r) return results
def mpc_to_np(x): if isnan(x): return np.nan if x.imag == 0: return np.float64(x.real) return np.complex128(x)
def mpf_matrix_fadd(A, B): """ Given a m x n matrix A and m x n matrix B either in numpy.matrix or mpmath.matrix format, this function computes the sum C = A + B exactly. The output matrix C is always given in the MPMATH format. Parameters ---------- A - m x n matrix B - m x n matrix Returns ------- C - m x n matrix """ if isinstance(A, numpy.matrix): try: A = python2mpf_matrix(A) except ValueError as e: raise ValueError('Cannot compute exact sum of two matrices. %s' % e) else: if not isinstance(A, mpmath.matrix): raise ValueError('Cannot compute exact sum of two matrices: unexpected input type, excpected numpy.matrix or mpmath.matrix but got %s') %type(A) if isinstance(B, numpy.matrix): try: B = python2mpf_matrix(B) except ValueError as e: raise ValueError('Cannot compute exact sum of two matrices. %s' % e) else: if not isinstance(B, mpmath.matrix): raise ValueError('Cannot compute exact sum of two matrices: unexpected input type, excpected numpy.matrix or mpmath.matrix but got %s') % type(B) #here both A and B are mpmath matrices #we consider that A and B are MPF matrices if their first elements are of type mpf, let's test it if not isinstance(A[0,0], mpmath.mpf) or not isinstance(B[0,0], mpmath.mpf): raise ValueError('Cannot compute exact product of two matrices: cannot sum complex matrices.') #test sizes if A.rows != B.rows or A.cols != B.cols: raise ValueError('Cannot compute exact sum of two matrices: incorrect sizes.') m = A.rows n = A.cols C = mp.zeros(m, n) for i in range(0, m): for j in range(0, n): C[i,j] = mpmath.fadd(A[i,j], B[i,j], exact=True) if mpmath.isnan(C[i,j]) or mpmath.isinf(C[i,j]): print('WARNING: in matrix sum an abnormal number (NaN/Inf) occured: %f' % C[i,j]) return C
def apply(self, z, evaluation): '%(name)s[z__]' args = z.numerify(evaluation).get_sequence() mpmath_function = self.get_mpmath_function(args) result = None # if no arguments are inexact attempt to use sympy if all(not x.is_inexact() for x in args): result = Expression(self.get_name(), *args).to_sympy() result = self.prepare_mathics(result) result = from_sympy(result) # evaluate leaves to convert e.g. Plus[2, I] -> Complex[2, 1] return result.evaluate_leaves(evaluation) elif mpmath_function is None: return if not all(isinstance(arg, Number) for arg in args): return if any(arg.is_machine_precision() for arg in args): # if any argument has machine precision then the entire calculation # is done with machine precision. float_args = [ arg.round().get_float_value(permit_complex=True) for arg in args ] if None in float_args: return result = self.call_mpmath(mpmath_function, float_args) if isinstance(result, (mpmath.mpc, mpmath.mpf)): if mpmath.isinf(result) and isinstance(result, mpmath.mpc): result = Symbol('ComplexInfinity') elif mpmath.isinf(result) and result > 0: result = Expression('DirectedInfinity', Integer(1)) elif mpmath.isinf(result) and result < 0: result = Expression('DirectedInfinity', Integer(-1)) elif mpmath.isnan(result): result = Symbol('Indeterminate') else: result = Number.from_mpmath(result) else: prec = min_prec(*args) d = dps(prec) args = [ Expression('N', arg, Integer(d)).evaluate(evaluation) for arg in args ] with mpmath.workprec(prec): mpmath_args = [x.to_mpmath() for x in args] if None in mpmath_args: return result = self.call_mpmath(mpmath_function, mpmath_args) if isinstance(result, (mpmath.mpc, mpmath.mpf)): result = Number.from_mpmath(result, d) return result
def default_color_function(ctx, z): if math.isinf(z): return (1.0, 1.0, 1.0) if math.isnan(z): return (0.5, 0.5, 0.5) pi = 3.1415926535898 a = (float(math.arg(z)) + math.pi) / (2 * math.pi) a = (a + 0.5) % 1.0 b = 1.0 - float(1 / (1.0 + abs(z)**0.3)) return hls_to_rgb(a, b, 0.8)
def run_mpfr_conversions(self): import pybind11_test_01 as p if not p.has_mpfr(): return try: from mpmath import mpf, mp, workprec, isnan except ImportError: return self.assertTrue(p.test_real_conversion(mpf()) == 0) self.assertTrue(p.test_real_conversion(mpf(1)) == 1) self.assertTrue(p.test_real_conversion(mpf(-1)) == -1) self.assertTrue(p.test_real_conversion(mpf("inf")) == mpf("inf")) self.assertTrue(p.test_real_conversion(-mpf("inf")) == -mpf("inf")) self.assertTrue(isnan(p.test_real_conversion(mpf("nan")))) self.assertTrue( p.test_real_conversion(mpf("1.323213210010203")) == mpf( "1.323213210010203")) self.assertTrue( p.test_real_conversion(-mpf("1.323213210010203")) == -mpf("1.323213210010203")) # Test with different precision. # Less precision in output from C++ is ok. self.assertTrue(p.test_real_conversion(mpf(-1), 30) == -1) self.assertTrue(p.test_real_conversion(mpf("inf"), 30) == mpf("inf")) self.assertTrue(isnan(p.test_real_conversion(mpf("nan"), 30))) # More precision in output from C++ will be lossy, so an error # is raised instead. self.assertRaises(ValueError, lambda: p.test_real_conversion(mpf(-1), 300)) self.assertRaises(ValueError, lambda: p.test_real_conversion(mpf("inf"), 300)) self.assertRaises(ValueError, lambda: p.test_real_conversion(mpf("nan"), 300)) # Try the workprec construct. with workprec(100): self.assertTrue(p.test_real_conversion(mpf("1.1")) == mpf("1.1")) self.assertTrue(p.test_real_conversion(mpf("-1.1")) == mpf("-1.1"))
def are_matrices_close(mat1, mat2, rtol=1e-05, atol=1e-08, equal_nan=False): if mode == mode_python: return np.allclose(mat1, mat2, rtol, atol, equal_nan) else: # Just make sure we have matrices and not lists. np.allclose supports # lists. List support is useful for tests as can have test data that is # common to both representations in list form. mat1_ = matrix(mat1) mat2_ = matrix(mat2) if shape(mat1_) != shape(mat2_): return False for r in range(mat1_.rows): for c in range(mat1_.cols): a = mat1_[r, c] b = mat2_[r, c] if mpmath.isnan(a) and mpmath.isnan(b) and equal_nan: pass elif not num_cmp(a, b, atol, rtol): return False return True
def select(): global lastop, a, listindex, argindex, theFile if lastop == 0: print( 'Parse Error: SELECT. came before corresponding EXP. or LOG. at instruction ' + str(pointer)) print(greporig(pointer)) left = val middle = a[listindex] right = val if listindex > 0: left = a[listindex - 1] if listindex < len(a) - 1: right = a[listindex + 1] print('Nearby Tape Values: ' + mpmath.nstr(left) + ',' + mpmath.nstr(middle) + ',' + mpmath.nstr(right)) sys.exit() elif lastop == 1: if a[argindex] != 0 or mpmath.im( a[listindex]) != 0 or a[listindex] >= 0: try: a[argindex] = mpmath.power(a[argindex], a[listindex]) except OverflowError: print( 'Number too large to represent. Try increasing precision or moving default tape value closer to 1.' ) print(greporig(pointer)) a[argindex] = mpmath.chop(a[argindex], tol) else: a[argindex] = mpmath.mpc('inf') else: if a[listindex] == 1: print('Tried to take a log base one at instruction ' + str(pointer)) print(greporig(pointer)) left = val middle = a[listindex] right = val if listindex > 0: left = a[listindex - 1] if listindex < len(a) - 1: right = a[listindex + 1] print('Nearby Tape Values: ' + mpmath.nstr(left) + ',' + mpmath.nstr(middle) + ',' + mpmath.nstr(right)) sys.exit() a[argindex] = mpmath.log(a[argindex], a[listindex]) #patch up nans when arg is infinite, since we usually want zero for the real part then if mpmath.isinf(mpmath.im(a[argindex])) and mpmath.isnan( mpmath.re(a[argindex])): a[argindex] = mpmath.mpc(0, mpmath.im(a[argindex])) a[argindex] = mpmath.chop(a[argindex], tol) oparg = 0
def apply(self, z, evaluation): '%(name)s[z__]' args = z.numerify(evaluation).get_sequence() mpmath_function = self.get_mpmath_function(args) result = None # if no arguments are inexact attempt to use sympy if all(not x.is_inexact() for x in args): result = Expression(self.get_name(), *args).to_sympy() result = self.prepare_mathics(result) result = from_sympy(result) # evaluate leaves to convert e.g. Plus[2, I] -> Complex[2, 1] return result.evaluate_leaves(evaluation) elif mpmath_function is None: return if not all(isinstance(arg, Number) for arg in args): return if any(arg.is_machine_precision() for arg in args): # if any argument has machine precision then the entire calculation # is done with machine precision. float_args = [arg.round().get_float_value(permit_complex=True) for arg in args] if None in float_args: return result = self.call_mpmath(mpmath_function, float_args) if isinstance(result, (mpmath.mpc, mpmath.mpf)): if mpmath.isinf(result) and isinstance(result, mpmath.mpc): result = Symbol('ComplexInfinity') elif mpmath.isinf(result) and result > 0: result = Expression('DirectedInfinity', Integer(1)) elif mpmath.isinf(result) and result < 0: result = Expression('DirectedInfinity', Integer(-1)) elif mpmath.isnan(result): result = Symbol('Indeterminate') else: result = Number.from_mpmath(result) else: prec = min_prec(*args) d = dps(prec) args = [Expression('N', arg, Integer(d)).evaluate(evaluation) for arg in args] with mpmath.workprec(prec): mpmath_args = [x.to_mpmath() for x in args] if None in mpmath_args: return result = self.call_mpmath(mpmath_function, mpmath_args) if isinstance(result, (mpmath.mpc, mpmath.mpf)): result = Number.from_mpmath(result, d) return result
def _refine_results(self, intermediate_results: List[Match], print_results=True): """ validate intermediate results to 100 digit precision :param intermediate_results: list of results from first enumeration :param print_results: if true print status. :return: final results. """ results = [] counter = 0 n_iterations = len(intermediate_results) constant_vals = [const() for const in self.constants_generator] for res in intermediate_results: counter += 1 if (counter % 50) == 0 and print_results: print( 'passed {} permutations out of {}. found so far {} matches' .format(counter, n_iterations, len(results))) try: all_matches = self.hash_table.evaluate(res.lhs_key) # check if all values encountered are not inf or nan if not all([ not (mpmath.isinf(val) or mpmath.isnan(val)) for val, _, _ in all_matches ]): # safety print('Something wicked happened!') print( f'Encountered a NAN or inf in LHS db, at {res.lhs_key}, {constant_vals}' ) continue except (ZeroDivisionError, KeyError): # if there was an exeption here, there is no need to halt the entire execution, but only note it to the # user continue # create a_n, b_n with huge length, calculate gcf, and verify result. an = self.create_an_series(res.rhs_an_poly, g_N_verify_terms) bn = self.create_bn_series(res.rhs_bn_poly, g_N_verify_terms) gcf = EfficientGCF(an, bn) rhs_str = mpmath.nstr(gcf.evaluate(), g_N_verify_compare_length) for i, match in enumerate(all_matches): val_str = mpmath.nstr(match[0], g_N_verify_compare_length) if val_str == rhs_str: # This patch is ment to allow support for multiple matches for an # LHS key, i will later be used to determind which item in the LHS dict # was matched results.append(RefinedMatch(*res, i, match[1], match[2])) return results
def mpf_get_representation(a): """ Given a MP floating-point number of type mpmath.mpf this function returns a tuple (y, n) of python long integers such that a = y * 2**n exactly. If the number is +Inf, -Inf or NaN WARNING: we get into the internal structure of MPF class. a._mpf_ yeilds a tuple of four variables: _mpf_[0] - sign _mpf_[1] - mantissa _mpf_[2] - exponent _mpf_[3] - size of mantissa with which the number was created Parameters ---------- a - MP number Returns ------- y - long n - int or long """ if not isinstance(a, mpmath.mpf): raise ValueError('Expected mpmath.mpf but got %s' % type(a)) if mpmath.isinf(a) or mpmath.isnan(a): raise ValueError( 'Cannot get a representation of number: an Inf or NaN occured') t = a._mpf_ if len(t) != 4: raise ValueError( 'Something is wrong, could not get mpf number structure') n = t[2] y = -t[1] if t[0] else t[1] return y, n
def _refine_results(self, precise_intermediate_results, verbose=True): """ validate intermediate results to 100 digit precision :param precise_intermediate_results: list of results from first enumeration :param verbose: if true print status. :return: final results. """ results = [] counter = 0 n_iterations = len(precise_intermediate_results) constant_vals = [const() for const in self.constants_generator] for res, rhs_str in precise_intermediate_results: counter += 1 if (counter % 10_000 == 0 or counter == n_iterations) and verbose: print( 'Passed {} permutations out of {}. Found so far {} matches' .format(counter, n_iterations, len(results))) try: all_matches = self.hash_table.evaluate(res.lhs_key) # check if all values encountered are not inf or nan if not all([ not (mpmath.isinf(val) or mpmath.isnan(val)) for val, _, _ in all_matches ]): # safety print('Something wicked happened!') print( f'Encountered a NAN or inf in LHS db, at {res.lhs_key}, {constant_vals}' ) continue except (ZeroDivisionError, KeyError): # if there was an exception here, there is no need to halt the entire execution, # but only note it to the user continue for i, match in enumerate(all_matches): val_str = mpmath.nstr(match[0], g_N_verify_compare_length) if val_str == rhs_str: # This patch is meant to allow support for multiple matches for an # LHS key, it will later be used to determine which item in the LHS dict # was matched results.append(RefinedMatch(*res, i, match[1], match[2]))
def drawbox(): global a, listindex, centerx, centery, pixdict, z, red, green, blue, canv, verbose if verbose: print('Outputting: ' + mpmath.nstr(mpmath.chop(a[listindex]))) if mpmath.isnan(a[listindex]) or mpmath.isinf(a[listindex]): return try: x = int(mpmath.nint(mpmath.re(a[listindex]))) + centerx y = int(mpmath.nint(mpmath.im(a[listindex]))) + centery if (x, y) in pixdict: canv.delete(pixdict[(x, y)]) del pixdict[(x, y)] pixdict[(x, y)] = canv.create_rectangle(x * z - z + 1, y * z - z + 1, x * z + 1, y * z + 1, fill=rgb(red, green, blue), width=0) except OverflowError: #the number is so huge it's not going to be displayed anyway, so just suppress the error and move on pass
def Perr(Qtildep, Q, Qp, FNR, FPR): """ Returns observed error-prone probability distribution. Args ---- Qtildep (int): number of positive tests. Qp (int): number of positive tests. Q (int): number of tests. FNR (float): false-negative fraction. FPR (float): false-positive fraction. """ Qm = Q - Qp Perr = power(FNR, Qp) * power(1 - FPR, Qm - Qtildep ) * power(FPR, Qtildep) \ * binomial( Qm, Qtildep ) * hyp2f1( -Qp, -Qtildep, Qm + 1 - Qtildep, \ (FNR-1)*(FPR-1)/(FNR*FPR) ) if isnan(Perr): Perr = 0 return Perr
def solve(key,debug=False,showcode=False,showequations=False): code = "from sympy import *\n\n" url = "https://docs.google.com/spreadsheets/d/%s/export?format=csv"%(key) # don't put the gid id in, then always returned the first sheet in tabs r = requests.get(url) data = r.content if debug: print data df = pd.read_csv(StringIO(data),header=-1) if debug: print df locInput = 1 locName = 2 locOutput = 3 locRule = 0 locSt = 0 locGroup = 0 parserState = None variables = [] rules = [] #print df.iloc[0,0] for i in range(0,len(df)): if df.iloc[i,locGroup] == 'st': continue if df.iloc[i,locGroup] == 'variables': parserState = 'inVariables' continue if parserState == 'inVariables': if pd.isnull(df.iloc[i,locName]): parserState = None else: variables.append({'st':df.iloc[i,locSt], 'name':df.iloc[i,locName], 'input':df.iloc[i,locInput], 'row':i}) if df.iloc[i,locGroup] == 'rules': parserState = 'inRules' continue if parserState == 'inRules': if pd.isnull(df.iloc[i,locRule]): parserState = None break else: rules.append(df.iloc[i,locRule]) if debug: print variables print rules code += "# variables\n" initialGuess = 10000.1 outputs = collections.OrderedDict() for v in variables: if len(v['name']) == 1: code += "%-5s = Symbol('%s')\n"%(v['name'],v['name']) else: code += "%-5s = Symbol('%c_%s')\n"%(v['name'],v['name'][0],v['name'][1:]) if v['st'] =='g': outputs[v['name']] = float(v['input']) else: if isnan(v['input']): outputs[v['name']] = initialGuess else: code += "%-5s = %f\n"%(v['name'],float(v['input'])) code += "\n" if debug: print code print outputs code += "# rules\n" ans = "ans = nsolve((" i = 1 for r in rules: lhs,rhs = r.split('=',1) code += "e%d = Eq( %10s,%-20s )\n"%(i,lhs,rhs) if showequations: code += "display(e%d)\n"%i ans += "e%d,"%i i += 1 code += "\n# solve\n"+ans[0:-1]+"),("+",".join(outputs.keys())+"),(" code += ",".join(map(str,outputs.values()))+"),verify=True)" code += "\n\n# answers\n" i = 0 if len(outputs.keys()) == 1: code += "print ans\n" else: for k in outputs.keys(): code += "print \"%-5s = %%14.6f\"%%ans[%d]\n"%(k,i) i += 1 if debug or showcode: print code print print "# ------------------------------------------------------------------\n\n" try: exec(code) except ValueError as msg: print msg except TypeError as msg: print msg print "modify initial values"
def solve(key,debug=False,showcode=False,showequations=False): code = "from sympy import *\n\n" url = "https://docs.google.com/spreadsheets/d/%s/export?format=csv"%(key) # don't put the gid id in, then always returned the first sheet in tabs r = requests.get(url) data = r.content if debug: print data df = pd.read_csv(StringIO(data),header=-1) if debug: print df locInput = 1 locName = 2 locOutput = 3 locRule = 0 locSt = 0 locGroup = 0 parserState = None variables = [] rules = [] #print df.iloc[0,0] for i in range(0,len(df)): if df.iloc[i,locGroup] == 'st': continue if df.iloc[i,locGroup] == 'variables': parserState = 'inVariables' continue if parserState == 'inVariables': if pd.isnull(df.iloc[i,locName]): parserState = None else: variables.append({'st':df.iloc[i,locSt], 'name':df.iloc[i,locName], 'input':df.iloc[i,locInput], 'row':i}) if df.iloc[i,locGroup] == 'rules': parserState = 'inRules' continue if parserState == 'inRules': if pd.isnull(df.iloc[i,locRule]): parserState = None break else: rules.append(df.iloc[i,locRule]) if debug: print variables print rules code += "# variables\n" initialGuess = 10000.1 outputs = collections.OrderedDict() for v in variables: if len(v['name']) == 1: code += "%-10s = Symbol('%s')\n"%(v['name'],v['name']) else: code += "%-10s = Symbol('%c_%s')\n"%(v['name'],v['name'][0],v['name'][1:]) if v['st'] =='g': outputs[v['name']] = float(v['input']) else: if isnan(v['input']): outputs[v['name']] = initialGuess else: code += "%-10s = %f\n"%(v['name'],float(v['input'])) code += "\n" if debug: print "-- code -----------------------------------------------------------" print code print "-- code -----------------------------------------------------------" print print outputs code += "# rules\n" ans = "ans = nsolve((" i = 1 for r in rules: lhs,rhs = r.split('=',1) code += "e%d = Eq( %10s,%-20s )\n"%(i,lhs,rhs) if showequations: code += "display(e%d)\n"%i ans += "e%d,"%i i += 1 code += "\n# solve\n"+ans[0:-1]+"),("+",".join(outputs.keys())+"),(" code += ",".join(map(str,outputs.values()))+"),verify=True)" code += "\n\n# answers\n" i = 0 if len(outputs.keys()) == 1: code += "print ans\n" else: for v in variables: if not isnan(v['input']) and v['st'] != 'g': code += "print \"%-10s = %14.6f\"\n"%(v['name'],float(v['input'])) code += "print\n" for k in outputs.keys(): code += "print \"%-10s = %%14.6f\"%%ans[%d]\n"%(k,i) i += 1 if debug or showcode: print variables print code try: exec(code) except ValueError as msg: print msg except TypeError as msg: print msg print "modify initial values"
def run_quadmath_conversions(self): import pybind11_test_01 as p if not p.has_quadmath(): return try: from mpmath import mpf, mp, workprec, isnan, isinf except ImportError: return # Default precision is 53, so the conversion will fail. self.assertRaises(TypeError, lambda: p.test_real128_conversion(mpf())) self.assertRaises(TypeError, lambda: p.test_real128_conversion(mpf("inf"))) self.assertRaises(TypeError, lambda: p.test_real128_conversion(mpf("nan"))) # Set precision to quadruple. mp.prec = 113 self.assertTrue(p.test_real128_conversion(mpf()) == 0) self.assertTrue(p.test_real128_conversion(mpf(1)) == 1) self.assertTrue(p.test_real128_conversion(mpf(-1)) == -1) self.assertTrue(p.test_real128_conversion(mpf("inf")) == mpf("inf")) self.assertTrue(p.test_real128_conversion(-mpf("inf")) == -mpf("inf")) self.assertTrue(isnan(p.test_real128_conversion(mpf("nan")))) self.assertTrue( p.test_real128_conversion( mpf("1.32321321001020301293838201938121203")) == mpf( "1.32321321001020301293838201938121203")) self.assertTrue( p.test_real128_conversion( -mpf("1.32321321001020301293838201938121203")) == -mpf("1.32321321001020301293838201938121203")) self.assertTrue( p.test_real128_conversion(mpf(2)**-16382) == mpf(2)**-16382) self.assertTrue( p.test_real128_conversion(-(mpf(2)**-16382)) == -(mpf(2)**-16382)) # Try subnormal numbers behaviour. self.assertTrue(mpf(2)**-16495 != 0) self.assertTrue(p.test_real128_conversion(mpf(2)**-16495) == mpf(0)) # Try the workprec construct. with workprec(2000): self.assertRaises(TypeError, lambda: p.test_real128_conversion(mpf())) self.assertRaises(TypeError, lambda: p.test_real128_conversion(mpf("inf"))) self.assertRaises(TypeError, lambda: p.test_real128_conversion(mpf("nan"))) # Test that the real128 overload is picked before the real one, # if instantiated before. self.assertTrue(p.test_overload(mpf(2)**-16495) == 0) if not p.has_mpfr(): with workprec(2000): self.assertTrue(p.test_overload(mpf(2)**-16495) != 0) # Test we don't end up to inf if the significand has more than 113 bits. mp.prec = 40000 foo = mpf("1.1") with workprec(113): self.assertFalse(isinf(p.test_real128_conversion(foo))) # Restore prec on exit. mp.prec = 53
def _estimate_approach_type_and_params_inner_alg( self, find_poly_parameter=False, iters=5000, initial_cutoff=1500, iters_step=500, exponential_threshold=1.1): """Returns 'exp', 'super_exp', 'poly2sympoly', 'undefined', 'fast' and 'mixed', as a tuple of (string,num): (approach_type, approach_parameter) or ('poly2sympoly', (approach_parameter, R**2)).""" # This is an old function. It's still in use, but it's yucky and I don't feel like going through it and # document it. Sorry :( # Hopefully it will be replaced with some theoretical insights. # HOWEVER, IT IS GENERAL AND MAY BE USEFUL FOR NEW, FUTURE REPRESENTATION METHODS. # See the "convergence_analysis.pdf" file for further details about theory behind this function. # It evaluates and categorizes by computing linear fitting to the error/iterations plot. Regular or logarithmic. effective_zero = dec(10)**-mp.dps if iters_step < 6: ValueError('iters_step should be at least 4') approach_type = None approach_parameter = 0 delta_pair = [] delta_odd = [] self.gen_iterations(initial_cutoff) res_0 = self.get_result() self.add_iterations(1) res_1 = self.get_result() self.add_iterations(1) res_2 = self.get_result() self.add_iterations(1) res_3 = self.get_result() self.add_iterations(1) res_4 = self.get_result() self.add_iterations(1) res_5 = self.get_result() delta_pair.append((initial_cutoff, abs(res_2 - res_0))) delta_pair.append((initial_cutoff + 2, abs(res_4 - res_2))) delta_odd.append((initial_cutoff + 1, abs(res_3 - res_1))) delta_odd.append((initial_cutoff + 3, abs(res_5 - res_3))) for i in range(initial_cutoff + iters_step, iters + 1, iters_step): # -3 for the iterations of res_1, res_2, res_3 that were already executed self.add_iterations(iters_step - 5) res_0 = self.get_result() self.add_iterations(1) res_1 = self.get_result() self.add_iterations(1) res_2 = self.get_result() self.add_iterations(1) res_3 = self.get_result() self.add_iterations(1) res_4 = self.get_result() self.add_iterations(1) res_5 = self.get_result() delta_pair.append((i, abs(res_2 - res_0))) delta_pair.append((i + 2, abs(res_4 - res_2))) delta_odd.append((i + 1, abs(res_3 - res_1))) delta_odd.append((i + 3, abs(res_5 - res_3))) pair_diminish = False odd_diminish = False if len(delta_pair) > 3 and all( [abs(p[1]) < effective_zero for p in delta_pair[-3:]]): pair_diminish = True if len(delta_odd) > 3 and all( [abs(p[1]) < effective_zero for p in delta_odd[-3:]]): odd_diminish = True # if one diminishes and the other isn't, return 'undefined' if pair_diminish ^ odd_diminish: approach_type = 'undefined' elif pair_diminish and odd_diminish: approach_type = 'fast' # if approach_type: # return (approach_type, approach_parameter) pair_ratio = [ (delta_pair[i][0], delta_pair[i][1] / delta_pair[i + 1][1]) for i in range(0, len(delta_pair), 2) if delta_pair[i][1] != 0 and delta_pair[i + 1][1] != 0 and not isnan(delta_pair[i][1]) and not isnan(delta_pair[i + 1][1]) ] odd_ratio = [ (delta_odd[i][0], delta_odd[i][1] / delta_odd[i + 1][1]) for i in range(0, len(delta_odd), 2) if delta_odd[i][1] != 0 and delta_odd[i + 1][1] != 0 and not isnan(delta_odd[i][1]) and not isnan(delta_odd[i + 1][1]) ] if len(pair_ratio) < 6: return (approach_type, approach_parameter) mean_pair_ratio = sum([p for i, p in pair_ratio]) / len(pair_ratio) mean_pair_ratio_avg_square_error = sum([ (r - mean_pair_ratio)**2 for i, r in pair_ratio ]).sqrt() / len(pair_ratio) mean_odd_ratio = sum([p for i, p in odd_ratio]) / len(odd_ratio) mean_odd_ratio_avg_square_error = sum([ (r - mean_odd_ratio)**2 for i, r in odd_ratio ]).sqrt() / len(odd_ratio) relative_pair_sq_err = mean_pair_ratio_avg_square_error / mean_pair_ratio relative_odd_sq_err = mean_odd_ratio_avg_square_error / mean_odd_ratio if relative_pair_sq_err > 0.5 or relative_odd_sq_err > 0.5: if all([ i[1] > 2 for i in (pair_ratio[3 * int(len(pair_ratio) / 4):] + odd_ratio[3 * int(len(odd_ratio) / 4):]) ]): approach_type = 'super_exp' else: approach_type = 'undefined' if (relative_odd_sq_err <= 0.5 and relative_pair_sq_err <= 0.5) or approach_type == 'super_exp': is_pair_exp = mean_pair_ratio > exponential_threshold is_odd_exp = mean_odd_ratio > exponential_threshold # in case one is exponential and the other isn't return 'mixed' if is_pair_exp ^ is_odd_exp: approach_type = 'mixed' elif is_pair_exp and is_odd_exp: if approach_type != 'super_exp': approach_type = 'exp' approach_parameter_pair = mean_pair_ratio**type( mean_pair_ratio)(0.5) approach_parameter_odd = mean_odd_ratio**type(mean_odd_ratio)( 0.5) approach_parameter = min(approach_parameter_pair, approach_parameter_odd) approach_coeff_pair_list = [ abs(delta_pair[i][1] * approach_parameter**(delta_pair[i][0]) / (1 - approach_parameter**(-2))) for i in range(0, len(delta_pair)) if delta_pair[i][1] != 0 and not isnan(delta_pair[i][1]) ] approach_coeff_pair = sum(approach_coeff_pair_list) / len( approach_coeff_pair_list) approach_coeff_odd_list = [ abs(delta_odd[i][1] * approach_parameter**(delta_odd[i][0]) / (1 - approach_parameter**(-2))) for i in range(0, len(delta_odd)) if delta_odd[i][1] != 0 and not isnan(delta_odd[i][1]) ] approach_coeff_odd = sum(approach_coeff_odd_list) / len( approach_coeff_odd_list) approach_coeff = min(approach_coeff_pair, approach_coeff_odd) approach_parameter = (approach_parameter, approach_coeff) else: approach_type = 'poly2sympoly' if approach_type != 'poly2sympoly' or not find_poly_parameter: return (approach_type, approach_parameter) # We're requested to find the poly2sympoly parameter log_x_pair = [math.log(i) for i, d in delta_pair] log_y_pair = [math.log(d) for i, d in delta_pair] slope_pair, intercept_pair, r_value_pair, p_value_pair, std_err_pair = scipy.stats.linregress( log_x_pair, log_y_pair) log_x_odd = [math.log(i) for i, d in delta_odd] log_y_odd = [math.log(d) for i, d in delta_odd] slope_odd, intercept_odd, r_value_odd, p_value_odd, std_err_odd = scipy.stats.linregress( log_x_odd, log_y_odd) # TODO: replace the -1 by *0.95? need to make sure first what is the slop (is it negative?) approach_parameter = (min(abs(slope_pair), abs(slope_odd)) - 1, min(intercept_pair, intercept_odd), min(r_value_pair**2, r_value_odd**2)) return (approach_type, approach_parameter)
def compute_points_individually(values, colors, convergence_iterations, iteration, stop_iteration_near, predefined_zones_of_attraction, f, compute_timeout): new_values = ['f**k']*len(values) new_colors = ['f**k']*len(colors) new_convergence_iterations = ['f**k']*len(convergence_iterations) # update values and colors matrices for i, val in enumerate(values): # don't reprocess errors if mpmath.isnan(val): new_values[i] = val new_colors[i] = colors[i] continue # stop iteration on values sufficiently close to, for instance zero if any([mpmath.almosteq(stop_iteration_value, val) for stop_iteration_value in stop_iteration_near]): new_values[i] = mpmath.nan new_colors[i] = (0.2588, 0.8314, 1.0) continue # sometimes convergence is too slow to measure with mathematical precision alone, so we predefine some zones of attraction where convergence is known # some examples are converging at a rate that slows the closer it is, or a decaying swirl that traces an infinite path length around the convergence point (but which still converges at infinity) satisfied_zone_of_attraction = False for condition, convergence_value in predefined_zones_of_attraction: if condition(val): new_values[i] = convergence_value new_colors[i] = 'converged' if colors[i] != 'converged': new_convergence_iterations[i] = iteration else: new_convergence_iterations[i] = convergence_iterations[i] satisfied_zone_of_attraction = True break if satisfied_zone_of_attraction == True: continue # try processing point try: new_val = func_timeout(compute_timeout, f, args=(val,)) except FunctionTimedOut: new_values[i] = mpmath.nan new_colors[i] = (0.0, 0.0, 1.0) except OverflowError as e: if e.__str__() in ['int too large to convert to float', 'Python int too large to convert to C ssize_t', 'cannot convert float infinity to integer', 'too many digits in integer']: new_values[i] = mpmath.nan new_colors[i] = (0.0, 0.0, 1.0) else: reraise_error(val) except MemoryError: new_values[i] = mpmath.nan new_colors[i] = (0.0, 0.0, 1.0) except RecursionError: new_values[i] = mpmath.nan new_colors[i] = (0.0, 0.0, 1.0) except: # handle unknown errors reraise_error(val) else: # color point according to normal math rules and store new value if mpmath.almosteq(new_val, val): new_colors[i] = 'converged' if colors[i] != 'converged': new_convergence_iterations[i] = iteration else: new_convergence_iterations[i] = convergence_iterations[i] else: new_colors[i] = (1.0, 1.0, 1.0) new_values[i] = new_val return new_values, new_colors, new_convergence_iterations