[4025019] | 1 | # This program is public domain |
---|
| 2 | |
---|
| 3 | """ |
---|
| 4 | Error propogation algorithms for simple arithmetic |
---|
| 5 | |
---|
| 6 | Warning: like the underlying numpy library, the inplace operations |
---|
| 7 | may return values of the wrong type if some of the arguments are |
---|
| 8 | integers, so be sure to create them with floating point inputs. |
---|
| 9 | """ |
---|
| 10 | |
---|
| 11 | |
---|
| 12 | from __future__ import division # Get true division |
---|
| 13 | import numpy |
---|
| 14 | |
---|
| 15 | def div(X,varX, Y,varY): |
---|
| 16 | """Division with error propagation""" |
---|
| 17 | # Direct algorithm: |
---|
| 18 | # Z = X/Y |
---|
| 19 | # varZ = (varX/X**2 + varY/Y**2) * Z**2 |
---|
| 20 | # = (varX + varY * Z**2) / Y**2 |
---|
| 21 | # Indirect algorithm to minimize intermediates |
---|
| 22 | Z = X/Y # truediv => Z is a float |
---|
| 23 | varZ = Z**2 # Z is a float => varZ is a float |
---|
| 24 | varZ *= varY |
---|
| 25 | varZ += varX |
---|
| 26 | T = Y**2 # Doesn't matter if T is float or int |
---|
| 27 | varZ /= T |
---|
| 28 | return Z, varZ |
---|
| 29 | |
---|
| 30 | def mul(X,varX, Y,varY): |
---|
| 31 | """Multiplication with error propagation""" |
---|
| 32 | # Direct algorithm: |
---|
| 33 | Z = X * Y |
---|
| 34 | varZ = Y**2 * varX + X**2 * varY |
---|
| 35 | # Indirect algorithm won't ensure floating point results |
---|
| 36 | # varZ = Y**2 |
---|
| 37 | # varZ *= varX |
---|
| 38 | # Z = X**2 # Using Z to hold the temporary |
---|
| 39 | # Z *= varY |
---|
| 40 | # varZ += Z |
---|
| 41 | # Z[:] = X |
---|
| 42 | # Z *= Y |
---|
| 43 | return Z, varZ |
---|
| 44 | |
---|
| 45 | def sub(X,varX, Y, varY): |
---|
| 46 | """Subtraction with error propagation""" |
---|
| 47 | Z = X - Y |
---|
| 48 | varZ = varX + varY |
---|
| 49 | return Z, varZ |
---|
| 50 | |
---|
| 51 | def add(X,varX, Y,varY): |
---|
| 52 | """Addition with error propagation""" |
---|
| 53 | Z = X + Y |
---|
| 54 | varZ = varX + varY |
---|
| 55 | return Z, varZ |
---|
| 56 | |
---|
| 57 | def exp(X,varX): |
---|
| 58 | """Exponentiation with error propagation""" |
---|
| 59 | Z = numpy.exp(X) |
---|
| 60 | varZ = varX * Z**2 |
---|
| 61 | return Z,varZ |
---|
| 62 | |
---|
| 63 | def log(X,varX): |
---|
| 64 | """Logarithm with error propagation""" |
---|
| 65 | Z = numpy.log(X) |
---|
| 66 | varZ = varX / X**2 |
---|
| 67 | return Z,varZ |
---|
| 68 | |
---|
| 69 | # Confirm this formula before using it |
---|
| 70 | # def pow(X,varX, Y,varY): |
---|
| 71 | # Z = X**Y |
---|
| 72 | # varZ = (Y**2 * varX/X**2 + varY * numpy.log(X)**2) * Z**2 |
---|
| 73 | # return Z,varZ |
---|
| 74 | # |
---|
| 75 | |
---|
| 76 | def pow(X,varX,n): |
---|
| 77 | """X**n with error propagation""" |
---|
| 78 | # Direct algorithm |
---|
| 79 | # Z = X**n |
---|
| 80 | # varZ = n*n * varX/X**2 * Z**2 |
---|
| 81 | # Indirect algorithm to minimize intermediates |
---|
| 82 | Z = X**n |
---|
| 83 | varZ = varX/X |
---|
| 84 | varZ /= X |
---|
| 85 | varZ *= Z |
---|
| 86 | varZ *= Z |
---|
| 87 | varZ *= n**2 |
---|
| 88 | return Z, varZ |
---|
| 89 | |
---|
| 90 | def div_inplace(X,varX, Y,varY): |
---|
| 91 | """In-place division with error propagation""" |
---|
| 92 | # Z = X/Y |
---|
| 93 | # varZ = (varX + varY * (X/Y)**2) / Y**2 = (varX + varY * Z**2) / Y**2 |
---|
| 94 | X /= Y # X now has Z = X/Y |
---|
| 95 | T = X**2 # create T with Z**2 |
---|
| 96 | T *= varY # T now has varY * Z**2 |
---|
| 97 | varX += T # varX now has varX + varY*Z**2 |
---|
| 98 | del T # may want to use T[:] = Y for vectors |
---|
| 99 | T = Y # reuse T for Y |
---|
| 100 | T **=2 # T now has Y**2 |
---|
| 101 | varX /= T # varX now has varZ |
---|
| 102 | return X,varX |
---|
| 103 | |
---|
| 104 | def mul_inplace(X,varX, Y,varY): |
---|
| 105 | """In-place multiplication with error propagation""" |
---|
| 106 | # Z = X * Y |
---|
| 107 | # varZ = Y**2 * varX + X**2 * varY |
---|
| 108 | T = Y**2 # create T with Y**2 |
---|
| 109 | varX *= T # varX now has Y**2 * varX |
---|
| 110 | del T # may want to use T[:] = X for vectors |
---|
| 111 | T = X # reuse T for X**2 * varY |
---|
| 112 | T **=2 # T now has X**2 |
---|
| 113 | T *= varY # T now has X**2 * varY |
---|
| 114 | varX += T # varX now has varZ |
---|
| 115 | X *= Y # X now has Z |
---|
| 116 | return X,varX |
---|
| 117 | |
---|
| 118 | def sub_inplace(X,varX, Y, varY): |
---|
| 119 | """In-place subtraction with error propagation""" |
---|
| 120 | # Z = X - Y |
---|
| 121 | # varZ = varX + varY |
---|
| 122 | X -= Y |
---|
| 123 | varX += varY |
---|
| 124 | return X,varX |
---|
| 125 | |
---|
| 126 | def add_inplace(X,varX, Y,varY): |
---|
| 127 | """In-place addition with error propagation""" |
---|
| 128 | # Z = X + Y |
---|
| 129 | # varZ = varX + varY |
---|
| 130 | X += Y |
---|
| 131 | varX += varY |
---|
| 132 | return X,varX |
---|
| 133 | |
---|
| 134 | def pow_inplace(X,varX,n): |
---|
| 135 | """In-place X**n with error propagation""" |
---|
| 136 | # Direct algorithm |
---|
| 137 | # Z = X**n |
---|
| 138 | # varZ = abs(n) * varX/X**2 * Z**2 |
---|
| 139 | # Indirect algorithm to minimize intermediates |
---|
| 140 | varX /= X |
---|
| 141 | varX /= X # varX now has varX/X**2 |
---|
| 142 | X **= n # X now has Z = X**n |
---|
| 143 | varX *= X |
---|
| 144 | varX *= X # varX now has varX/X**2 * Z**2 |
---|
| 145 | varX *= n**2 # varX now has varZ |
---|
| 146 | return X,varX |
---|