function.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import numpy
  2. import functools
  3. def fval(t,W):
  4. if callable(W):
  5. return W(t)
  6. return W
  7. def L(t,t0,W):
  8. ft0=fval(t,t0)
  9. fW=fval(t,W)
  10. x=(t-ft0)/fW
  11. if x<-18:
  12. return 0
  13. if x>18:
  14. return 1
  15. return 1/(1+numpy.exp(-x))
  16. def dL(t,t0,W):
  17. return L(t,t0,W)*(1-L(t,t0,W))
  18. def dLdW(t,t0,W):
  19. fW=fval(t,W)
  20. ft0=fval(t,t0)
  21. return dL(t,t0,W)*(t-ft0)/fW/fW
  22. def dLdt0(t,t0,W):
  23. fW=fval(t,W)
  24. return dL(t,t0,W)/fW
  25. def logisticPar(par):
  26. t0=par['t0']['value']
  27. W=par['W']['value']
  28. f=functools.partial(L,t0=t0,W=W)
  29. #D1[x] could be a function !!!
  30. Dt0=par['t0']['derivatives']
  31. dfdt0=functools.partial(dLdt0,t0=t0,W=W)
  32. dt0=generate(dfdt0,Dt0)
  33. #D2[x] could be a function !!!
  34. DW=par['W']['derivatives']
  35. dfdW=functools.partial(dLdW,t0=t0,W=W)
  36. dW=generate(dfdW,DW)
  37. #merge
  38. return Object(f,[dt0,dW])
  39. def deltaW(t,t1,t2):
  40. ft1=fval(t,t1)
  41. ft2=fval(t,t2)
  42. return ft2-ft1
  43. def deltaT(t,t1):
  44. ft1=fval(t,t1)
  45. return t-t1
  46. def fq(t,t1,t2):
  47. return deltaT(t,t1)/deltaW(t,t1,t2)
  48. def f1(t,C,t1,t2,L1,L2):
  49. fC=fval(t,C)
  50. return fC*fq(t,t1,t2)*L1(t)*(1-L2(t))
  51. def f2(t,C,L1,L2):
  52. fC=fval(t,C)
  53. return fC*L1(t)*L2(t)
  54. def lg(t,C,t1,t2,eps,L1,L2):
  55. fC=fval(t,C)
  56. return eps*fC+f1(t,C,t1,t2,L1,L2)+f2(t,C,L1,L2)
  57. def dlgdt1(t,C,t1,t2,L1,L2):
  58. fC=fval(t,C)
  59. return -fC*L1(t)*(1-L2(t))*(1+fq(t,t1,t2))/deltaW(t,t1,t2)
  60. def dlgdt2(t,C,t1,t2,L1,L2):
  61. return -f1(t,C,t1,t2,L1,L2)/deltaW(t,t1,t2)
  62. def dlgdL1(t,C,t1,t2,L1,L2):
  63. fC=fval(t,C)
  64. fL2=L2(t)
  65. return fC*(fq(t,t1,t2)*(1-fL2)+fL2)
  66. def dlgdL2(t,C,t1,t2,L1,L2):
  67. fC=fval(t,C)
  68. return fC*L1(t)*(1-fq(t,t1,t2))
  69. def dlgdC(t,C,t1,t2,L1,L2):
  70. fL2=L2(t)
  71. return L1(t)*(fq(t,t1,t2)*(1-fL2)+fL2)
  72. def lgFixedSlope(t,alpha,t1,t2,eps,L1,L2):
  73. fA=fval(t,alpha)
  74. ft1=fval(t,t1)
  75. dW=deltaW(t,t1,t2)
  76. return fA*(dW*eps+L1(t)*((t-ft1)*(1-L2(t))+dW*L2(t)))
  77. def dlgFixedSlopedt1(t,alpha,L1,L2):
  78. fA=fval(t,alpha)
  79. return -fA*L1(t)
  80. def dlgFixedSlopedt2(t,alpha,L1,L2):
  81. fA=fval(t,alpha)
  82. return -fA*L1(t)*L2(t)
  83. def dlgFixedSlopedL1(t,alpha,t1,t2,L1,L2):
  84. return lgFixedSlope(t,alpha,t1,t2,L1,L2)/L1(t)
  85. def dlgFixedSlopedL2(t,alpha,t1,t2,L1,L2):
  86. fA=fval(t,alpha)
  87. ft2=fval(t,t2)
  88. return fA*L1(t)*(ft2-t)
  89. def dlgFixedSlopedalpha(t,alpha,t1,t2,L1,L2):
  90. fA=fval(t,alpha)
  91. return lgFixedSlope(t,alpha,t1,t2,L1,L2)/fA
  92. def linearGrowth(par):
  93. #make sure we never return zero or negative
  94. C=par['C']['value']
  95. t1=par['t1']['value']
  96. t2=par['t2']['value']
  97. eps=1e-8
  98. pL1=logisticPar({'t0':par['t1'],'W':par['W1']})
  99. pL2=logisticPar({'t0':par['t2'],'W':par['W2']})
  100. L1=pL1['value']
  101. L2=pL2['value']
  102. f=functools.partial(lg,C=C,t1=t1,t2=t2,eps=eps,L1=L1,L2=L2)
  103. Dt1=par['t1']['derivatives']
  104. dfdt1=functools.partial(dlgdt1,C=C,t1=t1,t2=t2,L1=L1,L2=L2)
  105. dt1=generate(dfdt1,Dt1)
  106. Dt2=par['t2']['derivatives']
  107. dfdt2=functools.partial(dlgdt2,C=C,t1=t1,t2=t2,L1=L1,L2=L2)
  108. dt2=generate(dfdt2,Dt2)
  109. DL1=pL1['derivatives']
  110. dfdL1=functools.partial(dlgdL1,C=C,t1=t1,t2=t2,L1=L1,L2=L2)
  111. dL1=generate(dfdL1,DL1)
  112. DL2=pL2['derivatives']
  113. dfdL2=functools.partial(dlgdL2,C=C,t1=t1,t2=t2,L1=L1,L2=L2)
  114. dL2=generate(dfdL2,DL2)
  115. DC=par['C']['derivatives']
  116. dfdC=functools.partial(dlgdC,C=C,t1=t1,t2=t2,L1=L1,L2=L2)
  117. dC=generate(dfdC,DC)
  118. return Object(f,[dt1,dt2,dL1,dL2,dC])
  119. def linearGrowthFixedSlope(par):
  120. #make sure we never return zero or negative
  121. alpha=par['alpha']['value']
  122. t1=par['t1']['value']
  123. t2=par['t2']['value']
  124. eps=1e-8
  125. pL1=logisticPar({'t0':par['t1'],'W':par['W1']})
  126. pL2=logisticPar({'t0':par['t2'],'W':par['W2']})
  127. L1=pL1['value']
  128. L2=pL2['value']
  129. f=functools.partial(lgFixedSlope,alpha=alpha,t1=t1,t2=t2,eps=eps,L1=L1,L2=L2)
  130. Dt1=par['t1']['derivatives']
  131. dfdt1=functools.partial(dlgFixedSlopedt1,alpha=alpha,L1=L1,L2=L2)
  132. dt1=generate(dfdt2,Dt1)
  133. Dt2=par['t2']['derivatives']
  134. dfdt2=functools.partial(dlgFixedSlopedt2,alpha=alpha,L1=L1,L2=L2)
  135. dt2=generate(dfdt2,Dt2)
  136. DL1=pL1['derivatives']
  137. dfdL1=functools.partial(dlgFixedSlopedL1,alpha=alpha,t1=t1,t2=t2,L1=L1,L2=L2)
  138. dL1=generate(dfdL1,DL1)
  139. DL2=pL2['derivatives']
  140. dfdL2=functools.partial(dlgFixedSlopedL2,alpha=alpha,t1=t1,t2=t2,L1=L1,L2=L2)
  141. dL2=generate(dfdL2,DL2)
  142. DA=par['alpha']['derivatives']
  143. dfdA=functools.partial(dlgFixedSlopedalpha,alpha=alpha,t1=t1,t2=t2,L1=L1,L2=L2)
  144. dA=generate(dfdA,DA)
  145. return Object(f,[dt1,dt2,dL1,dL2,dA])
  146. def Object(v,dArray):
  147. o={'value':v,'function':True}
  148. allKeys=[]
  149. for x in dArray:
  150. allKeys.extend(x.keys())
  151. allKeys=list(set(allKeys))
  152. o['derivatives']={x:sumDict(dArray,x) for x in allKeys}
  153. return o
  154. def sumDict(dArray,x):
  155. #print('sumFunctions for {}'.format(x))
  156. fs=[]
  157. for a in dArray:
  158. #print('\tChecking {}'.format(a))
  159. try:
  160. #check if a[x] is a function with a dummy parameter
  161. fs.append(a[x])
  162. #print('\tAdding [{}]'.format(v))
  163. except KeyError:
  164. #print('\t{} not in table'.format(x))
  165. continue
  166. return sumArray(fs)
  167. def sumArray(fs,w=1):
  168. return lambda t,fs=fs,w=w: w*sum([to(f)(t) for f in fs])
  169. def to(a):
  170. if callable(a):
  171. return a
  172. return lambda t,a=a:a
  173. def contains(arr):
  174. for a in arr:
  175. if callable(a):
  176. return True
  177. return False
  178. def multiply(t,a,b):
  179. #abstract actual type of a and b
  180. fa=fval(t,a)
  181. fb=fval(t,b)
  182. return fa*fb
  183. def generate(df,D):
  184. return {x:functools.partial(multiply,a=D[x],b=df) for x in D}