motifcontext.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. '''This file is part of AToMPM - A Tool for Multi-Paradigm Modelling
  2. Copyright 2011 by the AToMPM team and licensed under the LGPL
  3. See COPYING.lesser and README.md in the root of this project for full details'''
  4. '''
  5. Transformation context for MoTif
  6. Author: Huseyin Ergin (hergin)
  7. Purpose: MoTif integration to AtomPM
  8. '''
  9. import random
  10. import collections
  11. import datetime
  12. from time import *
  13. import timeit
  14. from .tconstants import TConstants as TC
  15. from .utils import Utilities as utils
  16. from .tcontext import TransformationContext
  17. from .pytcore.tcore.messages import Pivots
  18. from .pytcore.rules.arule import ARule
  19. from .pytcore.rules.query import Query
  20. from .pytcore.rules.query import CQuery2
  21. from .pytcore.rules.query import CQuery3
  22. from .pytcore.rules.srule import SRule
  23. from .pytcore.rules.crule import CRule
  24. from .pytcore.rules.frule import FRule
  25. from .pytcore.rules.brule import BRule
  26. from .pytcore.rules.bsrule import BSRule
  27. from .pytcore.rules.lrule import LRule
  28. from .pytcore.rules.lfrule import LFRule
  29. from .pytcore.rules.lsrule import LSRule
  30. from .pytcore.rules.lqsrule import LQSRule
  31. from .pytcore.rules.sequence import Sequence
  32. '''
  33. holds the execution context of a 'Transformation' construct
  34. t
  35. fname the filename of the transformation model '''
  36. class MotifContext(TransformationContext) :
  37. def __init__(self,fname,ptcal):
  38. super(MotifContext,self).__init__(ptcal._transfData[fname])
  39. self.fname = fname
  40. self.metamodel = TC.MOTIFMM
  41. self.pivots=Pivots()
  42. self.totalExecutionTime=0
  43. self.sendAndApplyDeltaFunc = ptcal.sendAndApplyDelta
  44. self.nextInput = "packetIn"
  45. self.compiler = ptcal._compiler
  46. self.ptcal = ptcal
  47. self.rules = {}
  48. self.startStateID = None
  49. for id in self.t['nodes']:
  50. rule = self.ruleIdentifier(self.t['nodes'], id)
  51. if rule == None:
  52. if self.t['nodes'][id]['$type'] == self.metamodel+"/LRule" or \
  53. self.t['nodes'][id]['$type'] == self.metamodel+"/LSRule" or \
  54. self.t['nodes'][id]['$type'] == self.metamodel+"/LFRule" or \
  55. self.t['nodes'][id]['$type'] == self.metamodel+"/LQSRule":
  56. maxIterations = int(self.t['nodes'][id]['maxIterations']['value'])
  57. nested = int(self.t['nodes'][id]['nested']['value'])
  58. outerFirst = True if nested==0 else False
  59. def f(e) :
  60. return e['src'] == id
  61. lruleEdges = list(filter(f,self.t['edges']))
  62. baseEdgeId=None
  63. loopEdgeId=None
  64. for edge in lruleEdges:
  65. if self.t['nodes'][edge['dest']]['$type']==self.metamodel+"/base":
  66. baseEdgeId=edge['dest']
  67. elif self.t['nodes'][edge['dest']]['$type']==self.metamodel+"/loop":
  68. loopEdgeId=edge['dest']
  69. def f(e) :
  70. return e['src'] == baseEdgeId
  71. baseRuleIds = list(filter(f,self.t['edges']))
  72. baseRuleID=baseRuleIds[0]['dest']
  73. compiledBaseRule = None
  74. if self.t['nodes'][id]['$type'] == self.metamodel+"/LRule" or \
  75. self.t['nodes'][id]['$type'] == self.metamodel+"/LQSRule":
  76. baseRuleName = self.t['nodes'][baseRuleID]['query']['value']
  77. compiledBaseRule = self.compiler.compileRule(None,baseRuleName)
  78. else:
  79. baseRuleName = self.t['nodes'][baseRuleID]['rule']['value']
  80. compiledBaseRule = self.compiler.compileRule(None,baseRuleName)
  81. #baseRule = ARule(compiledBaseRule['lhs'],compiledBaseRule['rhs'],self.sendAndApplyDeltaFunc)
  82. def f(e) :
  83. return e['src'] == loopEdgeId
  84. loopRuleIds = list(filter(f,self.t['edges']))
  85. loopRuleID=loopRuleIds[0]['dest']
  86. loopRuleType = self.t['nodes'][loopRuleID]['$type']
  87. if loopRuleType != self.metamodel+"/CRule":
  88. loopRuleName = self.t['nodes'][loopRuleID]['rule']['value']
  89. compiledLoopRule = self.compiler.compileRule(None,loopRuleName)
  90. loopRule = None
  91. if loopRuleType == self.metamodel+"/ARule":
  92. loopRule = ARule(compiledLoopRule['lhs'],compiledLoopRule['rhs'],self.sendAndApplyDeltaFunc)
  93. elif loopRuleType == self.metamodel+"/FRule":
  94. loopRule = FRule(compiledLoopRule['lhs'],compiledLoopRule['rhs'],maxIterations,self.sendAndApplyDeltaFunc)
  95. elif loopRuleType == self.metamodel+"/SRule":
  96. loopRule = SRule(compiledLoopRule['lhs'],compiledLoopRule['rhs'],maxIterations,self.sendAndApplyDeltaFunc)
  97. elif loopRuleType == self.metamodel+"/CRule":
  98. ruleName = self.t['nodes'][loopRuleID]['ref']['value']
  99. self.ptcal._transfData[ruleName] = utils.fread('/users/%s/%s'%(self.ptcal.username,ruleName))
  100. motifContext = MotifContext(ruleName,self.ptcal)
  101. loopRule = CRule(motifContext)
  102. if self.t['nodes'][id]['$type'] == self.metamodel+"/LRule":
  103. rule = LRule(compiledBaseRule['lhs'],loopRule,max_iterations=maxIterations)
  104. elif self.t['nodes'][id]['$type'] == self.metamodel+"/LQSRule":
  105. rule = LQSRule(compiledBaseRule['lhs'],loopRule,max_iterations=maxIterations)
  106. elif self.t['nodes'][id]['$type'] == self.metamodel+"/LSRule":
  107. rule = LSRule(compiledBaseRule['lhs'],compiledBaseRule['rhs'],loopRule,outer_first=outerFirst,sendAndApplyDeltaFunc=self.sendAndApplyDeltaFunc,max_iterations=maxIterations)
  108. elif self.t['nodes'][id]['$type'] == self.metamodel+"/LFRule":
  109. rule = LFRule(compiledBaseRule['lhs'],compiledBaseRule['rhs'],loopRule,outer_first=outerFirst,sendAndApplyDeltaFunc=self.sendAndApplyDeltaFunc,max_iterations=maxIterations)
  110. elif self.t['nodes'][id]['$type'] == self.metamodel+"/BRule" or \
  111. self.t['nodes'][id]['$type'] == self.metamodel+"/BSRule":
  112. def f(e) :
  113. return e['src'] == id
  114. bruleEdges = list(filter(f,self.t['edges']))
  115. branchRuleList=[]
  116. for edge in bruleEdges:
  117. if self.t['nodes'][edge['dest']]['$type']==self.metamodel+"/branch":
  118. branchID=edge['dest']
  119. def f(e) :
  120. return e['src'] == branchID
  121. branchRuleID=list(filter(f,self.t['edges']))[0]['dest']
  122. rule = self.ruleIdentifier(self.t['nodes'],branchRuleID)
  123. if rule == None and self.t['nodes'][branchRuleID]['$type']==self.metamodel+"/CRule":
  124. ruleName = self.t['nodes'][branchRuleID]['ref']['value']
  125. self.ptcal._transfData[ruleName] = utils.fread('/users/%s/%s'%(self.ptcal.username,ruleName))
  126. motifContext = MotifContext(ruleName,self.ptcal)
  127. rule = CRule(motifContext)
  128. branchRuleList.append(rule)
  129. if self.t['nodes'][id]['$type'] == self.metamodel+"/BRule":
  130. rule = BRule(branchRuleList)
  131. elif self.t['nodes'][id]['$type'] == self.metamodel+"/BSRule":
  132. maxIterations = int(self.t['nodes'][id]['maxIterations']['value'])
  133. rule = BSRule(branchRuleList,maxIterations)
  134. elif self.t['nodes'][id]['$type'] == self.metamodel+"/CRule":
  135. rule = self.t['nodes'][id]['ref']['value']
  136. elif self.t['nodes'][id]['$type'] == self.metamodel+"/Sequence":
  137. sequenceRuleList=[]
  138. rulesFile = self.t['nodes'][id]['ref']['value']
  139. self.ptcal._transfData[rulesFile] = utils.fread('/users/%s/%s'%(self.ptcal.username,rulesFile))
  140. rulesOrdered = collections.OrderedDict(sorted(self.ptcal._transfData[rulesFile]['nodes'].items()))
  141. for ruleId in rulesOrdered:
  142. rule = self.ruleIdentifier(rulesOrdered,ruleId)
  143. if rule != None:
  144. sequenceRuleList.append(rule)
  145. else: # TODO decide for CRule
  146. pass
  147. rule = Sequence(sequenceRuleList)
  148. elif self.t['nodes'][id]['$type'] == self.metamodel+"/Start":
  149. self.startStateID = id
  150. rule = None
  151. if rule != None:
  152. self.rules[id] = {'id':id,
  153. 'name':self.t['nodes'][id]['name']['value'],
  154. 'alias':self.t['nodes'][id]['alias']['value'],
  155. 'rule':rule}
  156. def ruleIdentifier(self,ruleList,ruleId):
  157. rule = None
  158. if ruleList[ruleId]['$type']==self.metamodel+"/ARule":
  159. ruleName = ruleList[ruleId]['rule']['value']
  160. compiledRule = self.compiler.compileRule(None,ruleName)
  161. rule = ARule(compiledRule['lhs'],compiledRule['rhs'],self.sendAndApplyDeltaFunc)
  162. elif ruleList[ruleId]['$type']==self.metamodel+"/QRule":
  163. ruleName = ruleList[ruleId]['query']['value']
  164. compiledRule = self.compiler.compileRule(None,ruleName)
  165. rule = Query(compiledRule['lhs'])
  166. elif ruleList[ruleId]['$type']==self.metamodel+"/FRule":
  167. maxIterations = ruleList[ruleId]['maxIterations']['value']
  168. ruleName = ruleList[ruleId]['rule']['value']
  169. compiledRule = self.compiler.compileRule(None,ruleName)
  170. rule = FRule(compiledRule['lhs'],compiledRule['rhs'],int(maxIterations),self.sendAndApplyDeltaFunc)
  171. elif ruleList[ruleId]['$type']==self.metamodel+"/SRule":
  172. maxIterations = ruleList[ruleId]['maxIterations']['value']
  173. ruleName = ruleList[ruleId]['rule']['value']
  174. compiledRule = self.compiler.compileRule(None,ruleName)
  175. rule = SRule(compiledRule['lhs'],compiledRule['rhs'],int(maxIterations),self.sendAndApplyDeltaFunc)
  176. elif ruleList[ruleId]['$type'] == self.metamodel+"/CQRule2":
  177. ruleName = ruleList[ruleId]['query']['value']
  178. innerRuleName = ruleList[ruleId]['innerQuery']['value']
  179. compiledRule = self.compiler.compileRule(None,ruleName)
  180. compiledInnerRule = self.compiler.compileRule(None,innerRuleName)
  181. innerQuery = Query(compiledInnerRule['lhs'])
  182. rule = CQuery2(compiledRule['lhs'],innerQuery)
  183. elif ruleList[ruleId]['$type'] == self.metamodel+"/CQRule3":
  184. ruleName = ruleList[ruleId]['query']['value']
  185. innerRuleName = ruleList[ruleId]['innerQuery']['value']
  186. secondInnerRuleName = ruleList[ruleId]['secondInnerQuery']['value']
  187. compiledRule = self.compiler.compileRule(None,ruleName)
  188. compiledInnerRule = self.compiler.compileRule(None,innerRuleName)
  189. compiledSecondInnerRule = self.compiler.compileRule(None,secondInnerRuleName)
  190. innerQuery = Query(compiledInnerRule['lhs'])
  191. secondInnerQuery = Query(compiledSecondInnerRule['lhs'])
  192. rule = CQuery3(compiledRule['lhs'],innerQuery,secondInnerQuery)
  193. return rule
  194. def setLastStepExecTime(self,a):
  195. self._lastStep['time'] = a
  196. self.totalExecutionTime += a
  197. '''
  198. returns the id of the current step in the transformation model '''
  199. def getCurrentStepId(self) :
  200. if self._lastStep == {} :
  201. assert False, \
  202. "this function shouldn't be called when there is no current step"
  203. else :
  204. return self._lastStep['id']
  205. '''
  206. Returns the initial step of transformation which is the step after start state
  207. Steps to find initial step:
  208. 1- Find start state id in self.t['nodes']
  209. 2- Find the edge where start is the 'src'
  210. 3- The edge has the initial step as 'dest' after the link between
  211. Structure:
  212. (startID) ----- (linkID) -----> (initialID)
  213. (startID, linkID) is an edge
  214. (linkID, initialID) is another edge
  215. '''
  216. def _getInitialStep(self) :
  217. if self.startStateID==None:
  218. raise RuntimeError('There is no start state in loaded MoTif instance!')
  219. def f(e) :
  220. return e['src'] == self.startStateID
  221. startStateEdges = list(filter(f,self.t['edges']))
  222. initialStepID=None
  223. if len(startStateEdges) == 0 :
  224. raise RuntimeError('Start state is not connected to any other state!')
  225. else:
  226. firstLinkID=startStateEdges[0]['dest']
  227. def f(e) :
  228. return e['src'] == firstLinkID
  229. startStateEdges = list(filter(f,self.t['edges']))
  230. initialStepID=startStateEdges[0]['dest']
  231. if initialStepID in self.rules:
  232. return self.rules[initialStepID]
  233. else:
  234. if self.t['nodes'][initialStepID]['$type']==self.metamodel+"/EndSuccess":
  235. return {'trafoResult':TC.SUCCEEDED,
  236. 'feedbackReceived':'True'}
  237. elif self.t['nodes'][initialStepID]['$type']==self.metamodel+"/EndFail":
  238. return {'trafoResult':TC.FAILED,
  239. 'feedbackReceived':'True'}
  240. '''
  241. return the next step to run in this transformation... this is either
  242. the initial step OR a neighbour of the last step... which one of these
  243. neighbours is the next step is determined by the application information
  244. of the said last step
  245. 0. if self._expired is true (i.e., a race condition occurred causing this
  246. context to be called after it terminated but before ptcal.stop()
  247. removed it from ptcal._mtContexts), raise error
  248. 1. if there is no last step, return initial step
  249. 2. filter through edges to find appropriate edge out of last step
  250. a) if none is found, reset lastStep, set self._expired flag, and
  251. return the application information of this entire transformation
  252. context
  253. b) otherwise, return step on the other end of the said edge
  254. Next step structure
  255. lastStepID --> successID --> nextID
  256. --> failID --> nextID
  257. Steps to find next
  258. 1- Filter edges and get (lastStepID, successID) and (lastStepID,failID) edges
  259. 2- Select success or fail according to _lastStep['applicationInfo']
  260. 3- Find this edge (nextPath, nextStepID) where nextPath is one of the success or fail ids.
  261. '''
  262. def nextStep(self) :
  263. timeNextStep = clock()
  264. if self._expired == True :
  265. raise RuntimeError('can not step in expired mtContext')
  266. elif self._lastStep == {} :
  267. ns = self._getInitialStep()
  268. if ns == None :
  269. return {'$err':'could not find initial transformation step'}
  270. self._lastStep = ns
  271. return ns
  272. else :
  273. def f(e) :
  274. return e['src'] == self._lastStep['id']
  275. edgesFromLastStep = list(filter(f,self.t['edges']))
  276. if len(edgesFromLastStep) == 0 :
  277. ai = self._applicationInfo()
  278. self._lastStep = {}
  279. self._expired = True
  280. return ai
  281. else :
  282. targetLinkID=None
  283. resString = None
  284. if self._lastStep['applicationInfo'] == TC.SUCCEEDED :
  285. resString = self.metamodel+"/success"
  286. else :
  287. resString = self.metamodel+"/fail"
  288. for edgeLS in edgesFromLastStep:
  289. if self.t['nodes'][edgeLS['dest']]['$type'] == resString:
  290. targetLinkID=edgeLS['dest']
  291. break
  292. def f(e) :
  293. return e['src'] == targetLinkID
  294. nodesAfterLastStep = list(filter(f,self.t['edges']))
  295. nextStepID = nodesAfterLastStep[0]['dest']
  296. if nextStepID in self.rules:
  297. self._lastStep = self.rules[nextStepID]
  298. else:
  299. if self.t['nodes'][nextStepID]['$type']==self.metamodel+"/EndSuccess":
  300. self._lastStep = {'trafoResult':TC.SUCCEEDED,
  301. 'feedbackReceived':'True'}
  302. elif self.t['nodes'][nextStepID]['$type']==self.metamodel+"/EndFail":
  303. self._lastStep = {'trafoResult':TC.FAILED,
  304. 'feedbackReceived':'True'}
  305. #print clock()-timeNextStep
  306. return self._lastStep
  307. '''
  308. set the application information of the last step '''
  309. def setLastStepApplicationInfo(self,applicationInfo) :
  310. if applicationInfo == TC.SUCCEEDED :
  311. self._notApplicable = False
  312. self._lastStep['applicationInfo'] = applicationInfo
  313. def isLastStepFeedbackReceived(self) :
  314. return (not self._expired and self._lastStep=={}) or \
  315. 'feedbackReceived' in self._lastStep