tcontext.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. '''*****************************************************************************
  2. AToMPM - A Tool for Multi-Paradigm Modelling
  3. Copyright (c) 2011 Raphael Mannadiar (raphael.mannadiar@mail.mcgill.ca)
  4. This file is part of AToMPM.
  5. AToMPM is free software: you can redistribute it and/or modify it under the
  6. terms of the GNU Lesser General Public License as published by the Free Software
  7. Foundation, either version 3 of the License, or (at your option) any later
  8. version.
  9. AToMPM is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  11. PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with AToMPM. If not, see <http://www.gnu.org/licenses/>.
  14. *****************************************************************************'''
  15. import random
  16. from tconstants import TConstants as TC
  17. from utils import Utilities as utils
  18. '''
  19. holds a transformation execution context
  20. t the model transformation data
  21. rconfig data from the transformation's RuntimeConfiguration entity,
  22. if any
  23. _expired true when this context's transformation has terminated
  24. _lastStep the last executed transformation step
  25. MTC : ([fname,] [id,] applicationInfo, feedbackInfo)
  26. EC : (step#, applicationInfo, feedbackInfo)
  27. _notApplicable true if all steps in this transformation were N/A '''
  28. class TransformationContext(object) :
  29. def __init__(self,t) :
  30. self.t = t
  31. self._rconfig = None
  32. self._expired = False
  33. self._lastStep = {}
  34. self._notApplicable = True
  35. '''
  36. returns the application information associated with this entire
  37. transformation context '''
  38. def _applicationInfo(self) :
  39. if self._lastStep['applicationInfo'] == TC.FAILED :
  40. return TC.FAILED
  41. elif self._notApplicable :
  42. return TC.NOT_APPLICABLE
  43. else :
  44. return TC.SUCCEEDED
  45. '''
  46. returns the data stored in this context's transformation's
  47. RuntimeConfiguration entity, if any... also remembers it in '_rconfig' for
  48. future reference '''
  49. def getRuntimeConfiguration(self) :
  50. if self._rconfig == None :
  51. mm = '/Formalisms/__Transformations__/Transformation/Transformation/'
  52. for id in self.t['nodes'] :
  53. if self.t['nodes'][id]['$type'] == mm+'RuntimeConfiguration' :
  54. self._rconfig = self.t['nodes'][id]['options']['value']
  55. self._rconfig = (self._rconfig or {})
  56. return self._rconfig
  57. '''
  58. return true if no step has run yet (1st condition), or if the last step's
  59. (which may be a proper last step or {} if the context's transformation
  60. has terminated) feedbackReceived flag is set '''
  61. def isLastStepFeedbackReceived(self) :
  62. return (not self._expired and self._lastStep == {}) or \
  63. 'feedbackReceived' in self._lastStep
  64. '''
  65. returns true if the context's transformation has begun (i.e., the first
  66. step has been taken) '''
  67. def isTransformationUnderWay(self) :
  68. return not self._lastStep == {}
  69. '''
  70. return the next step to run '''
  71. def nextStep(self) :
  72. raise NotImplementedError('implement in subclass')
  73. '''
  74. set the application information of the last step (i.e., whether it was
  75. a) N/A, b) applicable and succeeded or c) applicable and failed '''
  76. def setLastStepApplicationInfo(self,applicationInfo) :
  77. raise NotImplementedError('implement in subclass')
  78. '''
  79. set the feedbackReceived flag of the last step to true (i.e., indicate
  80. that all relevant asworker changelogs have been received and handled '''
  81. def setLastStepFeedbackReceived(self) :
  82. self._lastStep['feedbackReceived'] = True
  83. '''
  84. add 'a' amount of time to total execution time '''
  85. def setLastStepExecTime(self,a):
  86. raise NotImplementedError('implement in subclass')
  87. '''
  88. holds the execution context of a 'Transformation' construct
  89. fname the filename of the transformation model '''
  90. class ModelTransformationContext(TransformationContext) :
  91. def __init__(self,t,fname) :
  92. super(ModelTransformationContext,self).__init__(t)
  93. self.fname = fname
  94. ''' hergin :: motifIntegration '''
  95. self.nextInput = "packetIn"
  96. self.metamodel = TC.TRANSFMM
  97. '''
  98. returns the id of the current step in the transformation model '''
  99. def getCurrentStepId(self) :
  100. if self._lastStep == {} :
  101. assert False, \
  102. "this function shouldn't be called when there is no current step"
  103. else :
  104. return self._lastStep['id']
  105. '''
  106. return the step within this transformation that has its 'isStart'
  107. attribute set to true '''
  108. def _getInitialStep(self) :
  109. for id in self.t['nodes'] :
  110. if 'isStart' in self.t['nodes'][id] and \
  111. self.t['nodes'][id]['isStart']['value'] :
  112. if 'filename' in self.t['nodes'][id] :
  113. return {'fname':self.t['nodes'][id]['filename']['value'],
  114. 'id':id}
  115. else :
  116. return {'id':id}
  117. '''
  118. return the next step to run in this transformation... this is either
  119. the initial step OR a neighbour of the last step... which one of these
  120. neighbours is the next step is determined by the application information
  121. of the said last step
  122. 0. if self._expired is true (i.e., a race condition occurred causing this
  123. context to be called after it terminated but before ptcal.stop()
  124. removed it from ptcal._mtContexts), raise error
  125. 1. if there is no last step, return initial step
  126. 2. filter through edges to find appropriate edge out of last step
  127. a) if none is found, reset lastStep, set self._expired flag, and
  128. return the application information of this entire transformation
  129. context
  130. b) otherwise, return step on the other end of the said edge '''
  131. def nextStep(self) :
  132. if self._expired == True :
  133. raise RuntimeError('can not step in expired mtContext')
  134. elif self._lastStep == {} :
  135. ns = self._getInitialStep()
  136. if ns == None :
  137. return {'$err':'could not find initial transformation step'}
  138. self._lastStep['id'] = ns['id']
  139. return ns
  140. else :
  141. mm = '/Formalisms/__Transformations__/Transformation/Transformation/'
  142. def f(e) :
  143. return e['src'] == self._lastStep['id'] and \
  144. self.t['nodes'][e['dest']]['$type'] == \
  145. mm+'On'+self._lastStep['applicationInfo']
  146. ne = filter(f,self.t['edges'])
  147. if len(ne) == 0 :
  148. ai = self._applicationInfo()
  149. self._lastStep = {}
  150. self._expired = True
  151. return ai
  152. else :
  153. ne = ne[0]
  154. for e in self.t['edges'] :
  155. if e['src'] == ne['dest'] :
  156. if 'filename' in self.t['nodes'][e['dest']] :
  157. self._lastStep = \
  158. {'fname':self.t['nodes'][e['dest']]['filename']['value'],
  159. 'id':e['dest']}
  160. else :
  161. self._lastStep = {'id':e['dest']}
  162. return self._lastStep
  163. raise ValueError('invalid transformation model, dangling '+\
  164. 'On'+self._lastStep['applicationInfo']+' edge')
  165. '''
  166. set the application information of the last step '''
  167. def setLastStepApplicationInfo(self,applicationInfo) :
  168. if applicationInfo == TC.SUCCEEDED :
  169. self._notApplicable = False
  170. self._lastStep['applicationInfo'] = applicationInfo
  171. def setLastStepExecTime(self,a):
  172. ''' to be implemented '''
  173. pass
  174. '''
  175. holds the execution context of an 'Exhaust[Random]' construct
  176. _id the Exhaust[Random]'s id in the transformation model
  177. _randomGen holds a random number generator if this is an ExhaustRandom
  178. _NAs holds the ids of the non-applicable steps in this
  179. Exhaust[Random] '''
  180. class ExhaustContext(TransformationContext) :
  181. def __init__(self,t,id,randomGen=None) :
  182. super(ExhaustContext,self).__init__(t)
  183. self._id = id
  184. self._randomGen = randomGen
  185. self._NAs = set()
  186. '''
  187. return the next step to run in this Exhaust[Random]... this is either
  188. the next step listed in the 'filenames' attribute OR a random not-N/A
  189. step listed in the 'filenames' attribute
  190. 0. if self._expired is true (i.e., a race condition occurred causing this
  191. context to be called after it terminated but before ptcal.stop()
  192. removed it from ptcal._mtContexts), raise error
  193. 1. if all steps are N/A, reset lastStep, set self._expired flag, and
  194. return the application information of this entire transformation
  195. context
  196. 2. if this is an ExhaustRandom, randomly choose a not-N/A step and set
  197. it as self._lastStep
  198. 2. if this is an Exhaust, increment self._lastStep
  199. 3. return self._lastStep '''
  200. def nextStep(self) :
  201. steps = self.t['nodes'][self._id]['filenames']['value']
  202. if self._expired == True :
  203. raise RuntimeError('can not step in expired mtContext')
  204. elif len(steps) == 0 :
  205. return TC.NOT_APPLICABLE
  206. elif len(set(steps)) == len(self._NAs) :
  207. ai = self._applicationInfo()
  208. self._lastStep = None
  209. self._expired = True
  210. return ai
  211. if self._randomGen != None :
  212. notNAs = set(range(0,len(steps))) - self._NAs
  213. r = self._randomGen.choice(list(notNAs))
  214. self._lastStep = {'step#':r}
  215. else :
  216. if self._lastStep == {} :
  217. self._lastStep = {'step#':0}
  218. else :
  219. self._lastStep = {'step#':(self._lastStep['step#']+1)%len(steps)}
  220. return {'fname':steps[self._lastStep['step#']]}
  221. '''
  222. set the application information of the last step
  223. NOTE: on success, we switch the self._notApplicable flag... this flag
  224. indicates whether a rule was succesfully applied within this
  225. transformation context... we also reset self._NAs to indicate
  226. that each step should be run at least once to re-establish its
  227. (non-)applicability '''
  228. def setLastStepApplicationInfo(self,applicationInfo) :
  229. if applicationInfo == TC.SUCCEEDED :
  230. self._notApplicable = False
  231. self._NAs = set()
  232. elif applicationInfo == TC.NOT_APPLICABLE :
  233. self._NAs.add(self._lastStep['step#'])
  234. self._lastStep['applicationInfo'] = applicationInfo