Module Automata
[hide private]
[frames] | no frames]

Source Code for Module Automata

  1  #Automata.py 
  2  #A Phyton implementation of a Deterministic Finite Automaton DFA 
  3  #Author: Matteo Cantarelli 
  4  #E-mail: matteo.cantarelli@lurpa.ens-cachan.fr 
  5  #Release: 0.2.2 
  6   
  7  import copy 
  8   
  9  #------------------------------------------------------------------------------  
 10  #CAutomata     (it manages a list of automata) 
 11  #CAutomaton     
 12  #    | 
 13  #    |-CEvent 
 14  #    |-CState 
 15  #        |-transitions     ( a dictionary of the form ['eventname']:CState ) 
 16  #        |-intransitions   ( a list of list [ ['eventname'][CState] ] ) 
 17  #------------------------------------------------------------------------------  
 18   
19 -class CAutomata(object):
20 "A Class to manage a list of automata" 21
22 - def __init__(self,name,minor=0,major=0):
23 """ 24 Initializes the CAutomata class. 25 26 The list of automata is initially empty. 27 28 @type name: string 29 @param name: The name of the Automata 30 @type minor: number 31 @type major: number 32 @return: void 33 """ 34 #private attributes 35 self.__name=name 36 self.__minor=minor 37 self.__major=major 38 self.__automata=[]
39
40 - def getName(self):
41 """ 42 @return: The Name of the Automata 43 """ 44 return self.__name
45
46 - def setName(self,name):
47 """ 48 Set the name of the Automata list. 49 50 @type name: string 51 @param name: The name of the Automata 52 @return: I{void} 53 """ 54 self.__name=name
55
56 - def getMinor(self):
57 """ 58 @return: The minor parameter of the Automata 59 """ 60 return self.__minor
61
62 - def getMajor(self):
63 """ 64 @return: The major parameter of the Automata 65 """ 66 return self.__major
67
68 - def getAutomaton(self,name):
69 """ 70 Returns the automaton instance corresponding to the specified name 71 72 @type name: string 73 @param name: The name of the automaton to retrieve 74 @return: the L{CAutomaton} instance associated to the specified I{name} if it is in the list. I{False} otherwise. 75 """ 76 for a in self.__automata: 77 if a.name==name: 78 return a 79 return False
80
81 - def setMinor(self,minor):
82 """ 83 Sets the minor parameter of the Automata list. 84 85 @type minor: integer 86 @return: I{void} 87 """ 88 self.__minor=minor
89
90 - def setMajor(self,major):
91 """ 92 Sets the major parameter of the Automata list. 93 94 @type major: integer 95 @return: I{void} 96 """ 97 self.__major=major
98
99 - def addAutomaton(self,automaton):
100 """ 101 Adds an automaton to the automata list 102 103 @type automaton: a L{CAutomaton} instance 104 @param automaton: the automaton instance to add to the current automata 105 @return: I{void} 106 """ 107 self.__automata.append(automaton)
108
109 - def getAutomata(self):
110 """ 111 Returns a copy of the list of automata. 112 113 @return: A copy of the list of automata 114 """ 115 return copy.copy(self.__automata)
116 117 # properties 118 name=property(fget=getName,fset=setName) 119 minor=property(fget=getMinor,fset=setMinor) 120 major=property(fget=getMajor,fset=setMajor)
121 122 #=============================================================================== 123 124 125
126 -class CAutomaton(object):
127 "A Class for a Deterministic Finite Automaton DFA" 128 129 #=============================================================================== 130 #private declarations 131 #=============================================================================== 132
133 - class __CEvent(object):
134 """ 135 A class to implement an event object. 136 137 This class is privately declared inside the L{CAutomaton} class. 138 Every instance will then be created by the L{CAutomaton} public methods (see the L{CAutomaton.addEvent} method). 139 """ 140
141 - def __init__(self,automaton,id,name,comment,controllable):
142 #private attributes 143 self.__id=id 144 self.__name=name 145 self.__comment=comment 146 self.__controllable=controllable 147 self.__automaton=automaton 148 self.__prioritylist=set([]) #A set of event for which the considered event have priority
149
150 - def getId(self):
151 """ 152 @return: The ID of the Event 153 """ 154 return self.__id
155
156 - def setId(self,id):
157 """ 158 Set the ID of the Event. 159 160 @type id: integer 161 @param id: the ID of the event (univocal key) 162 @return: I{void} 163 """ 164 self.__id=id
165
166 - def getName(self):
167 """ 168 @return: The Name of the Event 169 """ 170 return self.__name
171
172 - def setName(self,name):
173 """ 174 Set the name of the Event. 175 176 @type name: string 177 @param name: the name of the Event 178 @return: I{void} 179 """ 180 self.__name=name
181
182 - def getComment(self):
183 """ 184 @return: The comment associated to the Event 185 """ 186 return self.__comment
187
188 - def setComment(self,comment):
189 """ 190 Set a comment for the Event. 191 192 @type comment: string 193 @param comment: a description of the Event 194 @return: I{void} 195 """ 196 self.__comment=comment
197
198 - def setControllable(self,controllable):
199 """ 200 Set the controllable flag of the event. 201 A I{True} value means that the event is controllable, a I{False} value that it is not controllable. 202 203 @type controllable: boolean 204 @param controllable: a flag which determines if the Event is controllable or not 205 @return: I{void} 206 """ 207 self.__controllable=controllable
208
209 - def setPriorityList(self,events):
210 """ 211 Add one ore more event for which the current one has top priority. 212 213 The priorities over events are used when an automaton which represents a Supervisor is processed in 214 order to carry out a deterministic Controller (see the L{CAutomaton.toDeterministicController} method) 215 216 217 @type events: string 218 @param events: a list of the names of the less priority events 219 @return: I{True} if the list has been properly added, I{False} if some error has occurred (mostly one of the specified event name is not a valid one for the current automaton) 220 """ 221 for e in events: 222 if self._CEvent__automaton.getEvent(e): 223 self._CEvent__prioritylist.add(e) 224 else: 225 return False 226 return True
227
228 - def getPriorityList(self):
229 """ 230 Returns a copy of the list of prioritized events. 231 See the L{setPriorityList} method for further information. 232 233 @return: A copy of the list of prioritized events names 234 """ 235 return copy.copy(self._CEvent__prioritylist)
236
237 - def isSubdued(self,event):
238 """ 239 Returns I{True} if the specified event has less priority than the current one (than it is Subdued). 240 241 The method looks for if the specified event is in the Priority List of the current event 242 or in the Priority List of one of its subdueds. 243 244 @type event: string 245 @param event: the name of the event to check 246 247 @return: I{True} if the I{event} is subdued, I{False} otherwise 248 """ 249 if event in self._CEvent__prioritylist: #if the event is present in the priority list it is subdued 250 return True 251 else: #else look if it is subdued to someone of its subdueds 252 for e in self.__prioritylist: 253 if self._CEvent__automaton.getEvent(e).isSubdued(event): 254 return True 255 return False
256
257 - def isControllable(self):
258 """ 259 Returns a flag which states if the current Event is controllable or not. 260 261 @return: I{True} if the Event is controllable, I{False} otherwise 262 """ 263 return self.__controllable
264 265 # properties 266 267 id=property(fget=getId,fset=setId) 268 name=property(fget=getName,fset=setName) 269 comment=property(fget=getComment,fset=setComment) 270 controllable=property(fget=isControllable,fset=setControllable)
271 272 #------------------------------------------------------------------------------ 273
274 - class __CState(object):
275 """ 276 A class to implement a state object. 277 278 This class is privately declared inside the L{CAutomaton} class. 279 Every instance will then be created by the L{CAutomaton} public methods (see the L{CAutomaton.addState} method). 280 """
281 - def __init__(self,automaton,id,name,comment,initial,marked): #the class constructor
282 #private attributes 283 self.__id=id 284 self.__name=name 285 self.__comment=comment 286 self.__marked=marked 287 self.__initial=initial 288 self.__weight=-1 289 self.__transitions={} 290 self.__intransitions=[] 291 self.__automaton=automaton
292
293 - def getId(self):
294 """ 295 @return: The ID of the State 296 """ 297 return self.__id
298
299 - def setId(self,id):
300 """ 301 Sets the ID of the State. 302 303 @type id: integer 304 @param id: the ID of the state 305 @return: I{void} 306 """ 307 self.__id=id
308
309 - def getName(self):
310 """ 311 @return: The Name of the State 312 """ 313 return self.__name
314
315 - def setName(self,name):
316 """ 317 Sets the name of the State. 318 319 @type name: number 320 @param name: the name of the State 321 @return: I{void} 322 """ 323 self.__name=name
324
325 - def getComment(self):
326 """ 327 @return: The comment associated to the State 328 """ 329 return self.__comment
330
331 - def setComment(self,comment):
332 """ 333 Sets a comment for the State. 334 335 @type comment: string 336 @param comment: a description of the State 337 @return: I{void} 338 """ 339 self.__comment=comment
340 341
342 - def setInitial(self,initial):
343 """ 344 Sets the initial flag for the state. 345 A I{True} value means that the state is initial, a I{False} value that it is not initial. 346 347 @type initial: boolean 348 @param initial: a flag which determines if the State is initial or not 349 @return: I{void} 350 """ 351 self.__initial=initial
352
353 - def isInitial(self):
354 """ 355 Returns a flag which states if the current State is initial or not. 356 357 @return: I{True} if the State is intial, I{False} otherwise 358 """ 359 return self.__initial
360
361 - def setMarked(self,marked):
362 """ 363 Sets the marked flag for the state. 364 A I{True} value means that the state is marked, a I{False} value that it is not marked. 365 366 @type marked: boolean 367 @param marked: a flag which determines if the State is marked or not 368 @return: I{void} 369 """ 370 self.__marked=marked
371
372 - def isMarked(self):
373 """ 374 Returns a flag which states if the current State is marked or not. 375 376 @return: I{True} if the State is marked, I{False} otherwise 377 """ 378 return self.__marked
379
380 - def isBlocking(self):
381 """ 382 Returns a flag which states if the current State is blocking or not. 383 384 @return: I{True} if the State is blocking, I{False} otherwise 385 """ 386 return (not(len(self.__transitions)))
387
388 - def getWeight(self):
389 """ 390 Returns the weight associated to the state. 391 If a weight has never been set the method returns the B{-1} value. 392 393 The weights are used when an automaton which represents a Supervisor is processed in 394 order to carry out a deterministic Controller (see the L{CAutomaton.toDeterministicController} method). 395 396 @return: The weight associated to the State 397 """ 398 return self.__weight
399
400 - def setWeight(self,weight):
401 """ 402 Sets a weight to the state. 403 404 The weights are used when an automaton which represents a Supervisor is processed in 405 order to carry out a deterministic Controller (see the L{CAutomaton.toDeterministicController} method). 406 407 The weights are usually assigned by the L{expandWeight} method. 408 409 @type weight: integer 410 @param weight: a flag which determines the weight of the State 411 @return: I{void} 412 """ 413 self.__weight=weight
414
415 - def addTransition(self,event,arrivalstate):
416 """ 417 Adds an outgoing transition to the State. 418 419 To add the transition the event and the arrival state must already be in the automaton. 420 421 @type event: a L{CAutomaton._CAutomaton__CEvent} instance 422 @param event: the event associated to the transition 423 @type arrivalstate: a L{CAutomaton._CAutomaton__CState} instance 424 @param arrivalstate: the arrival state of the transition 425 @return: I{True} if the transition is successfully added, I{False} if some error has occured (mostly the event or the arrivalstate are not present in the automaton) 426 """ 427 if(not(arrivalstate in self.__automaton._CAutomaton__states)): 428 return False 429 if(not(event in self.__automaton._CAutomaton__events)): 430 return False 431 self.__transitions[event.name]=arrivalstate 432 arrivalstate.__intransitions.append([event.name,self]) 433 return True
434
435 - def getTransition(self,event):
436 """ 437 Returns the arrival state associated to the specified event for the outgoing transitions. 438 439 @type event: a L{CAutomaton._CAutomaton__CEvent} instance 440 @param event: the event which drives the transition 441 @return: a L{CAutomaton._CAutomaton__CState} instance 442 """ 443 return self.__transitions[event.name]
444
445 - def getInTransition(self,event):
446 """ 447 Returns the departure state associated to the event for the ingoing transitions. 448 449 @type event: a L{CAutomaton._CAutomaton__CEvent} instance 450 @param event: the event which drives the transition 451 @return: a L{CAutomaton._CAutomaton__CState} instance 452 """ 453 for it in self.__intransitions: 454 if it[0]==event.name: 455 return it[1] 456 else: return False
457 458
459 - def cutTransitions(self):
460 """ 461 This method called by the L{CAutomaton.toDeterministicController} method cuts the transitions which made 462 the supervisor non-deterministic by rapport to the control function it should achieve. 463 464 The controllable tranistions for the current state are cut in three steps. 465 466 1. B{Cutting no-WeightGain End event getWeight(nextstate)>=getWeight(currentstate)} 467 - The transitions associated to an I{End} event which don't provide a gain in terms of weight are suppressed. 468 2. B{Cutting lossy controllable events getWeight(nextstate)>getWeight(currentstate)} 469 - The transitions associated to the controllable events which make increase the weight are suppressed. 470 3. B{Using priority to resolve transition conflict} 471 - When a conflict is present between prioritized events the transition associated to the events with less priority are suppressed. 472 473 @return: void 474 """ 475 minweight=999999 476 event2del={} 477 for e,s in self.__transitions.iteritems(): 478 event2del[e]=False 479 if s.__weight<minweight: 480 minweight=s.__weight 481 482 transitionscopy=copy.copy(self.__transitions) 483 484 #First step: Cutting no-WeightGain End event (nextstate)>=weight(currentstate) 485 for e,s in transitionscopy.iteritems(): 486 if self._CState__automaton.getEvent(e).isControllable(): 487 if (not(s._CState__weight<self._CState__weight) and self._CState__automaton.getEvent(e).name==self._CState__automaton._CAutomaton__endevent): 488 s._CState__intransitions.remove([e,self]) 489 del self.__transitions[e] 490 491 transitionscopy=copy.copy(self.__transitions) 492 493 #Second step: Cutting lossy controllable events (nextstate)>weight(currentstate) 494 for e,s in transitionscopy.iteritems(): 495 if self._CState__automaton.getEvent(e).isControllable(): 496 if (s._CState__weight>self.__weight): 497 s._CState__intransitions.remove([e,self]) 498 del self.__transitions[e] 499 500 transitionscopy=copy.copy(self.__transitions) 501 502 #Third step: Using priority to resolve transition conflict 503 for e,s in transitionscopy.iteritems(): 504 for ae in event2del: 505 if self._CState__automaton.getEvent(e).isSubdued(ae): #if the current event have less priority than someoneother on the list.. 506 event2del[ae]=True 507 508 for e,s in transitionscopy.iteritems(): 509 if event2del[e]==True: 510 s._CState__intransitions.remove([e,self]) 511 del self.__transitions[e]
512
513 - def getTransitions(self): #return a copy of the directory of transitions
514 """ 515 Returns a copy of the outgoing transitions dictionary. 516 The dictionary has the form ['eventname']:CState. 517 518 @return: a copy of the dictionary of outgoing transitions 519 """ 520 return (copy.copy(self.__transitions))
521
522 - def getInTransitions(self): #return a copy of the list of input transitions
523 """ 524 Returns a copy of the ingoing transitions list. 525 The list has the form [ ['eventname'][CState] ]. 526 527 @return: a copy of the list of ingoing transitions 528 """ 529 return (copy.copy(self.__intransitions))
530
531 - def expandWeight(self,weight):
532 """ 533 Sets the weight for the current state and look for linked states with the same weight. 534 Returns a list of all the linked states with the next weight. 535 536 @type weight: integer 537 @param weight: the weight to assign to the current state and to all the same weight linked states. 538 @return: a list of the the linked states which have the next weight (weight + 1) 539 """ 540 until=set() #the list of the nextweightstates 541 if self.__weight==-1 : #avoids infinite loop: the state must not have a weight yet 542 self.__weight=weight #set the weight 543 #print 'State: ',self.__name,' - Weight: ',self.__weight 544 for t in self.getInTransitions(): #for every transition in input to the current state... 545 if t[0]==self.__automaton._CAutomaton__endevent: #if the event is endevent then its a state for the next class of weight 546 until.add(t[1]) #then add it to the list 547 else: 548 until=until|t[1].expandWeight(weight) #else recursively call the same function for the discovered sameweightstate 549 return until
550
551 - def getMealyList(self,list):
552 """ 553 Returns a list of the unchained controllable events from the current state. 554 When an uncontrollable event is found the chain is interrupted, the arrival state added and the list returned. 555 556 List format: [Controllable event,Controllable event,...,Controllable event,Arrival State] 557 558 @type list: a list of controllable events names which termines with a L{CAutomaton._CAutomaton__CState} instance 559 @param list: the first controllable event at the beginning, the list recurisively builded in next step 560 561 """ 562 for t in self.getTransitions(): 563 if self._CState__automaton.getEvent(t).isControllable(): 564 list.append(t) 565 self.getTransitions()[t].getMealyList(list) 566 else: 567 list.append(self) 568 return self
569 570 571 # properties 572 573 id=property(fget=getId,fset=setId) 574 name=property(fget=getName,fset=setName) 575 comment=property(fget=getComment,fset=setComment) 576 initial=property(fget=isInitial,fset=setInitial) 577 marked=property(fget=isMarked,fset=setMarked) 578 579 580 #=============================================================================== 581 #public methods 582 #=============================================================================== 583
584 - def __init__(self,name,comment,Type): #the class constructor
585 """ 586 Initializes the CAutomaton class. 587 588 The new automaton has no events or state. 589 590 @type name: string 591 @param name: The name of the Automaton 592 @type comment: string 593 @param comment: A description of the Automaton 594 @type Type: string 595 @param Type: The type of Automaton ('Plant', 'Specification', 'Supervisor') 596 @return: void 597 """ 598 599 #private attributes 600 self.__name=name 601 self.__comment=comment 602 self.__type=Type 603 self.__events=[] #the list of events E 604 self.__states=[] #the list of states X 605 self.__initialstates=[] #the initial states x0 606 self.__markedstates=[] #the marked states 607 self.__endevent=-1 608
609 - def getName(self):
610 """ 611 @return: The Name of the Automaton 612 """ 613 return self.__name
614
615 - def setName(self,name):
616 """ 617 Sets the name of the Automaton. 618 619 @type name: string 620 @param name: the name of the Automaton 621 @return: I{void} 622 """ 623 self.__name=name
624
625 - def getComment(self):
626 """ 627 @return: The comment associated to the Automaton 628 """ 629 return self.__comment
630
631 - def setComment(self,comment):
632 """ 633 Sets a comment for the Automaton. 634 635 @type comment: string 636 @param comment: a description of the Automaton 637 @return: I{void} 638 """ 639 self.__comment=comment
640
641 - def getType(self):
642 """ 643 @return: The type associated to the Automaton 644 """ 645 return self.__type
646
647 - def setType(self,Type):
648 """ 649 Sets the type of Automaton. 650 651 @type Type: string 652 @param Type: The type of Automaton ('Plant', 'Specification', 'Supervisor') 653 @return: I{void} 654 """ 655 self.__type=Type
656 657
658 - def resetWeights(self):
659 """ 660 Resets the weights of the state in the Automaton. 661 The default set weight is B{-1}. 662 663 @return: I{void} 664 """ 665 for s in self.getStates(): 666 s.setWeight(-1)
667
668 - def setWeights2End(self):
669 """ 670 Sets the weight of every state of the Automaton. 671 672 The weight represents the minimum number of I{End} events to reach a marked state. 673 This method uses the L{CAutomaton._CAutomaton__CState.expandWeight} recursive method to assign the weights. 674 675 @return: I{True} if the weights are assigned, I{False} if an error has occurred (mostly the I{End} event is not present in the alphabet events). 676 """ 677 if self.getEvent('End'): #if the 'End' event is present in the alphabet of events... 678 self.__endevent='End' #set the 'End' event as the event which bounds the states with the same weight 679 self.resetWeights() #for every state set its weight to -1 680 states=set() #the current states for which we are setting the weight 681 for s in self.__states: 682 if s.isMarked(): states.add(s) #the algorithm begins with the marked states... 683 weight=0 #..for which the weight is 0 684 while(len(states)): #until there are states to process... 685 newstates=set() #newstates will contains the states for the next class of weight 686 for s in states: 687 newstates=newstates|s.expandWeight(weight) #looks for the new states (expandWeight is charged to set 688 #the weight for the current states as well) 689 weight+=1 #increment the weight 690 states=newstates 691 return True 692 else: 693 return False
694
695 - def toDeterministicController(self):
696 """ 697 For each state of the Automaton cuts the transitions which make the controller not-deterministic. 698 699 The controller must be deterministic meaning that a given input sequence should then always produce 700 the same sequence of outputs. 701 To avoid a non-deterministic choice during the code generation it is then necessary to suppress 702 this choice among more controllable events. 703 704 The L{CAutomaton._CAutomaton__CState.cutTransitions} methos is invoked for each state. 705 706 @return: void 707 """ 708 709 for s in self.__states: 710 s.cutTransitions() 711 712
713 - def addState(self,id,name,comment,initial,marked):
714 """ 715 Adds a state to the Automaton. 716 717 @type id: integer 718 @param id: an id for the state (univocal key) 719 @type name: string 720 @param name: the name of the State 721 @type comment: string 722 @param comment: a description of the State 723 @type initial: boolean 724 @param initial: a flag which determines if the State is initial or not 725 @type marked: boolean 726 @param marked: a flag which determines if the State is marked or not 727 728 @return: a new L{CAutomaton._CAutomaton__CState} instance 729 """ 730 731 for s in self.__states: 732 if (s.getName()==name): 733 return False 734 s=self.__CState(self,id,name,comment,initial,marked) 735 self.__states.append(s) 736 if(initial): 737 self.__initialstates.append(s) 738 if(marked): 739 self.__markedstates.append(s) 740 return s 741
742 - def addEvent(self,id,name,comment,controllable):
743 """ 744 Adds an event to the Automaton. 745 746 @type id: integer 747 @param id: an id for the Event (univocal key) 748 @type name: string 749 @param name: the name of the Event 750 @type comment: string 751 @param comment: a description of the State 752 @type controllable: boolean 753 @param controllable: a flag which determines if the Event is controllable or not 754 755 @return: a new L{CAutomaton._CAutomaton__CEvent} instance 756 """ 757 for e in self.__events: 758 if (e.name==name)|(e.id==id): 759 return False 760 e=self.__CEvent(self,id,name,comment,controllable) 761 self.__events.append(e) 762 return e 763
764 - def getEvent(self,name):
765 """ 766 Returns the event instance corresponding to the specified name 767 768 @type name: string 769 @param name: the name of the Event 770 @return: the corresponding L{CAutomaton._CAutomaton__CEvent} instance if it exist, I{False} otherwise 771 """ 772 for e in self.__events: 773 if (e.name==name): 774 return e 775 return False 776
777 - def getEventFromId(self,id):
778 """ 779 Returns the event instance corresponding to the specified id 780 781 @type id: integer 782 @param id: the id of the Event (univocal key) 783 @return: the corresponding L{CAutomaton._CAutomaton__CEvent} instance if it exist, I{False} otherwise 784 """ 785 for e in self.__events: 786 if (e.id==id): 787 return e 788 return False 789
790 - def getEvents(self):
791 """ 792 Returns a copy of the list of events. 793 794 @return: a list of L{CAutomaton._CAutomaton__CEvent} instances 795 """ 796 return (copy.copy(self.__events)) 797
798 - def getInitialStates(self):
799 """ 800 Returns a copy of the list of initial states. 801 In a DFA it is present just one initial state. 802 803 @return: a list of L{CAutomaton._CAutomaton__CState} instances 804 """ 805 return (copy.copy(self.__initialstates)) 806
807 - def getStates(self):
808 """ 809 Returns a copy of the list of states. 810 811 @return: a list of L{CAutomaton._CAutomaton__CState} instances 812 """ 813 return (copy.copy(self.__states)) 814
815 - def getState(self,name):
816 """ 817 Returns the state instance corresponding to the specified name 818 819 @type name: string 820 @param name: the name of the State 821 @return: the corresponding L{CAutomaton._CAutomaton__CState} instance if it exist, I{False} otherwise 822 """ 823 for s in self.__states: 824 if (s.name==name): 825 return s 826 return False 827
828 - def getStateFromId(self,id):
829 """ 830 Returns the state instance corresponding to the specified id 831 832 @type id: integer 833 @param id: the id of the State (univocal key) 834 @return: the corresponding L{CAutomaton._CAutomaton__CState} instance if it exist, I{False} otherwise 835 """ 836 for s in self.__states: 837 if (s.id==id): 838 return s 839 return False 840
841 - def getTransitionsNumber(self):
842 """ 843 Return the number of transitions present in the current automaton 844 845 @return: the number of transitions 846 """ 847 nt=0 848 for s in self.__states: 849 nt+=len(s.getTransitions()) 850 return nt 851 852
853 - def getMarkedStates(self):
854 """ 855 Returns a copy of the list of marked states. 856 857 @return: a list of L{CAutomaton._CAutomaton__CState} instances 858 """ 859 return (copy.copy(self.__markedstates)) 860
861 - def __mul__(self,automaton):
862 """ 863 Returns an automaton obtained with a synchronous composition between the current automaton and the one given as parameter. 864 865 >>> #Example: 866 >>> resulting_automaton=a*b 867 868 @type automaton: a L{CAutomaton} instance 869 @param automaton: the second automaton in the multiplication operation 870 @return: the composed automaton 871 """ 872 fname=self.name + '||' + automaton.name 873 fcomment='This is the automaton resulting from the composition of "'+self.comment+'" & "' + automaton.comment + '"' 874 fa=CAutomaton(fname,fcomment,'Plant') 875 876 Xnew=[] #at each step it contains the left states to explore, at the beginning it contain the composite initial state 877 X=[] #it will contain all the states created for the automaton 878 x0=[] #the couple of all the states that will be in the initial state 879 880 for s in self.__initialstates: 881 x0.append(s.name) 882 for s in automaton.__initialstates: 883 x0.append(s.name) 884 885 x0name=x0[0]+x0[1] 886 marked=self.getState(x0[0]).isMarked() or automaton.getState(x0[1]).isMarked() 887 fa.addState(1,x0name,'Composited initial state',1,marked) 888 Xnew.append(x0) 889 statecount=2 #the number of states, it will be the id of the state 890 a1only=set(self._CAutomaton__events) - set(automaton._CAutomaton__events) #A-B 891 a2only=set(automaton._CAutomaton__events) - set(self._CAutomaton__events) #B-A 892 a1a2=set(self._CAutomaton__events) & set(automaton._CAutomaton__events) #A&B 893 a1Ua2=set(self._CAutomaton__events) | set(automaton._CAutomaton__events) #A|B 894 895 for xnext in Xnew: 896 897 for e in a1Ua2: 898 newx=[] 899 newxname='' 900 if e in a1only: #events in E'\E'' 901 if e in self.getState(xnext[0]).getTransitions(): 902 903 newx.append(self.getState(xnext[0]).getTransition(e).getName()) #the states that will be in the state that we are creating 904 newx.append(xnext[1]) 905 906 elif e in a2only: #events in E''\E' 907 if e in automaton.getState(xnext[1]).getTransitions(): 908 909 newx.append(xnext[0]) #the states that will be in the state that we are creating 910 newx.append(automaton.getState(xnext[1]).getTransition(e).getName()) 911 912 elif e in a1a2: #events in E' and in E'' 913 if e in self.getState(xnext[0]).getTransitions(): 914 if e in automaton.getState(xnext[1]).getTransitions(): 915 916 newx.append(self.getState(xnext[0]).getTransition(e).getName()) #the states that will be in the state that we are creating 917 newx.append(automaton.getState(xnext[1]).getTransition(e).getName()) 918 919 if len(newx): #if there's not a new state associated to the event break for the current event 920 newxname=newx[0]+newx[1] #the name for the created state 921 if(not(newx in fa._CAutomaton__states)): 922 if(not(newx in Xnew)): 923 Xnew.append(newx) 924 marked=0 925 if self.getState(newx[0]).isMarked() or automaton.getState(newx[1]).isMarked(): 926 marked=1 927 fa.addState(statecount,newxname,'Composited state',0,marked) 928 statecount=statecount+1 929 930 xnextname=xnext[0]+xnext[1] 931 fa.addEvent(e.name,e.comment,e.controllable) 932 fa.getState(xnextname).addTransition(e,fa.getState(newxname)) 933 return fa 934 935 # properties 936 937 name=property(fget=getName,fset=setName) 938 Type=property(fget=getType,fset=setType) 939 comment=property(fget=getComment,fset=setComment) 940 events=property(fget=getEvents) 941