polmap.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. #Copyright (c) 2008, Riccardo De Maria
  2. #All rights reserved.
  3. from .pol import *
  4. class polmap(dict):
  5. """
  6. >>> from polmap import *
  7. >>> x,xp,l=mkpol('x,xp,l')
  8. >>> drift=polmap(x=x+l*xp,xp=xp)
  9. >>> o=drift(x=0,xp=1.)
  10. >>> print o
  11. x=0.0 + l
  12. xp=1.0
  13. """
  14. def __init__(self,*s,**vars):
  15. dict.__init__(self,*s,**vars)
  16. for k,v in self.items():
  17. self[k]=pol(v)
  18. def copy(self):
  19. return polmap(self)
  20. def vars(self):
  21. return self[self.keys()[0]].vars
  22. def reorder(self,vars):
  23. vars=list(vars)
  24. for k,v in self.items():
  25. self[k]=pol(v).reorder(vars)
  26. return self
  27. def __setattr__(self,k,v):
  28. dict.__setitem__(self,k,v)
  29. dict.__setattr__(self,k,v)
  30. __setitem__=__setattr__
  31. def eval(self,*v,**a):
  32. """Compose self with other using the python interpreter. The argument can be a dictionary, another polmap or a set of named arguments.
  33. >>> from polmap import *
  34. >>> p=polmap(x='1+x+y')
  35. >>> print p({'x':4})
  36. x=5.0 + y
  37. >>> print p(x=4)
  38. x=5.0 + y
  39. >>> print p(polmap(x=4))
  40. x=5.0 + y
  41. >>> print p(p)
  42. x=2.0 + x + 2.0*y
  43. """
  44. loc={}
  45. try:
  46. loc.update(v[0])
  47. except:
  48. pass
  49. loc.update(a)
  50. for n,v in loc.items():
  51. if isinstance(v,str):
  52. loc[n]=pol(v)
  53. out=polmap()
  54. for n,v in self.items():
  55. out[n]=pol(v.eval(**loc))
  56. return out
  57. __call__ = eval
  58. def __repr__(self):
  59. return getattr(polmap,'out')(self)
  60. def truncate(self,order=1):
  61. for n,v in self.items():
  62. v.truncate(order=order)
  63. return self
  64. def float(self):
  65. new=polmap(self)
  66. for n,v in self.items():
  67. new[n]=float(v)
  68. return new
  69. def jacobian(self):
  70. return matrix([ dop(i)(self) for i in i in self])
  71. def table(self):
  72. """Table print
  73. """
  74. out=[]
  75. for n,v in self.items():
  76. out.append('%s=\n%s' % (n,v.table()))
  77. return '\n'.join(out)
  78. def pretty(self):
  79. """Pretty print
  80. """
  81. out=[]
  82. for n,v in self.items():
  83. out.append('%s=%s' % (n,pol(v).pretty()))
  84. return '\n'.join(out)
  85. def __mul__(self,other):
  86. """Compose self with other using a fast but memory consuming algorithm.
  87. >>> from polmap import *
  88. >>> p=polmap(x='1+x+x**2')
  89. >>> print p(p)
  90. x=3.0 + 3.0*x + 4.0*x**2 + 2.0*x**3 + x**4
  91. >>> print p*p
  92. x=3.0 + 3.0*x + 4.0*x**2 + 2.0*x**3 + x**4
  93. """
  94. if isinstance(other,pol):
  95. return other.eval(self)
  96. elif isinstance(other,float):
  97. new=polmap(self)
  98. for i in other.keys():
  99. new[i]=self[i]+other
  100. return new
  101. else:
  102. return compose(self,other)
  103. def __rmul__(self,other):
  104. new=polmap(self)
  105. for i in self.keys():
  106. new[i]=self[i]*other
  107. return new
  108. def __radd__(self,other):
  109. new=polmap(self)
  110. for i in self.keys():
  111. new[i]=self[i]+other
  112. return new
  113. def __pow__(self,other):
  114. """ Return the power of a map defined as a sequence of composition
  115. >>> from polmap import *
  116. >>> p=polmap(x='x+y',y='2*x-y')
  117. >>> print p**0
  118. y=y
  119. x=x
  120. >>> print p**1
  121. y=2.0*x - 1.0*y
  122. x=x + y
  123. >>> print p**2
  124. y=3.0*y
  125. x=3.0*x
  126. >>> print p**3
  127. y=6.0*x - 3.0*y
  128. x=3.0*x + 3.0*y
  129. """
  130. if other==0:
  131. return polmap( [ (i,i) for i in self.keys() ])
  132. else:
  133. new=polmap(self)
  134. for i in range(1,other):
  135. new=new*self
  136. return new
  137. def __add__(self,other):
  138. new=polmap(self)
  139. for i in other.keys():
  140. new[i]=self[i]+other[i]
  141. return new
  142. def __sub__(self,other):
  143. new=polmap(self)
  144. for i in other.keys():
  145. new[i]=self[i]-other[i]
  146. return new
  147. def __neg__(self):
  148. new=polmap(self)
  149. for i in other.keys():
  150. new[i]=-self[i]
  151. return new
  152. def matrix(self,vars=None):
  153. """Return the first order matrix:
  154. >>> from polmap import *
  155. >>> f=polmap(x='1+x+l*y',y='y')
  156. >>> f*=polmap(x='x',y='y+k*x**2')
  157. >>> print f
  158. y=y + x**2*k
  159. x=1.0 + x + y*l + x**2*k*l
  160. >>> print f.matrix()
  161. [[1.0, x*k], [l, 1.0 + x*k*l]]
  162. """
  163. if not vars:
  164. vars=self.keys()
  165. return [ [ self[j].divterm(i) for i in vars] for j in vars if j in self]
  166. def imatrix(self,vars=None):
  167. """ Return inverse first order matrix: EXPERIMENTAL
  168. """
  169. ((a,b),(c,d))=self.matrix(vars=vars)
  170. det=a*d-b*c
  171. return [[d/det,-b/det],[-c/det,a/det]]
  172. def trace(self):
  173. vars=self.keys()
  174. return [self[i].divterm(i) for i in vars]
  175. def der(self,var):
  176. """ Return the derivative with respect to var
  177. >>> from polmap import *
  178. >>> f=polmap(x='1+x+l*y',y='y')
  179. >>> print f.der('y')
  180. y=1.0
  181. x=l
  182. """
  183. new=polmap(self)
  184. for j in new.keys():
  185. new[j]=new[j].der(var)
  186. return new
  187. def const(self,vars):
  188. """ Return the terms that do non depend on vars
  189. >>> from polmap import *
  190. >>> f=polmap(x='1+x+l*y',y='y')
  191. >>> print f.const('ly')
  192. y=0
  193. x=1.0 + x
  194. """
  195. new=polmap(self)
  196. for j in self.keys():
  197. new[j]=new[j].const(vars)
  198. return new
  199. __str__=__repr__
  200. out=pretty
  201. def cdot(a,b):
  202. """ Dot product
  203. >>> from polmap import *
  204. >>> x=polmap(x=1,y=2,z=3)
  205. >>> print cdot(x,x)
  206. 14.0
  207. """
  208. vars=list(set(a).union(set(b)))
  209. out=0
  210. for i in vars:
  211. out+=a.get(i,0)*b.get(i,0)
  212. return out
  213. def compose(a,b):
  214. temp={} #bookkeeping vars
  215. tempvalues={} #bookkeeping values
  216. newm=polmap() #final map
  217. lm=0 #couter for temp values
  218. newv=pol(0) # fix for empty a
  219. for i in a: #store input pol in temp
  220. tempvalues[i]=b[i]
  221. for n,i in a.items(): # for each name,pol in map
  222. new=pol(0) # initialize new pol
  223. for j,c in i.items(): # for each mon in pol
  224. m=[] # prod vector
  225. for k in range(len(j)): # expand powers
  226. vv=i.vars[k] # mon var
  227. if vv in b: # keep
  228. m+=[i.vars[k]]*j[k] # add has list of mul
  229. else:
  230. c*=pol(vv)**j[k] # transfer in the coefficient
  231. # print "coefficient and monomial"
  232. # print c,m
  233. # print "reduce multiplications"
  234. if m: # if mon is not a constant
  235. while len(m)>1: # reduce multiplication
  236. p=m.pop(),m.pop() # terms
  237. if p in temp: # if terms already calculated
  238. t=temp[p] # take it
  239. else: # calculate new term
  240. lm+=1 # create temp var
  241. temp[p]=lm # bookkeep var
  242. t=lm # store for putting in m
  243. newv=tempvalues[p[0]]*tempvalues[p[1]] # compute
  244. tempvalues[t]=newv # store
  245. m.append(t) # put var
  246. # print m
  247. new+=c*tempvalues[m[0]] # add terms, newv carries always the result
  248. else:
  249. new+=c # case mon is a constant
  250. # print new
  251. newm[n]=new # put in the resulting map
  252. return newm
  253. def idmap(vars):
  254. return polmap([(i,i) for i in vars])