473,395 Members | 2,689 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

while/break - The pure-python FSM implementation to Rule Them All.

Well, it doesn't quite rule them all, but it is fast: About three times
faster than using one function per state. Faster than using generators.
Faster than using code objects.

Some, possibly minor, problems:
1. The generated code is ugly.
2. The generated code can be quite large, depending on the shape of the
FSM (Maximum theoretical size left as an exercise for the reader ;-)
3. Not as fast as byte code hacks, or using pyrex/psyco. Peter Hansen is
right. One of those is likely a better solution if you don't need pure
python.

The example FSM has input alphabet ['a','b','c']
and looks like:
state 0:
a -> 1
b -> 2
c -> 1

state 1:
a -> 1
b -> 3
c -> 2

state 2:
a -> 1
b -> 2
c -> 3

state 3:
a -> 2
b -> 3
c -> 0

The algorithm basically transforms the FSM into a tree of while loops,
with breaks letting us go back up the tree, and a variable ("goto"!)
telling us where the chain of breaks should stop.

Note:
1. It would be more efficient with a labelled break (or a labelled
continue) such as is available in Java.
2. There are some opportunities for optimisation of the generated code.

Running this code will print out the generated FSM code for both a
while/break implementation of the FSM and a function-based
implementation. It then does some timing measurements.

Cheers,
Carl.

#!/usr/bin/env python

from StringIO import StringIO

# number of random inputs fed to the FSM (if we are using that input
generator)
r = 1000000
#r = 10

# specific string of input chars (if we are using the appropriate input
generator)
inp = ['a','a','b','a','a','c','b','c','b','c','c','c','c ','c','b']

# list of states, each state is a dict describing transitions to other
states.
states = [
{'a':1,'b':2,'c':1},
{'a':1,'b':3,'c':2},
{'a':1,'b':2,'c':3},
{'a':2,'b':3,'c':0}]

ind = " "

class State(object):
def __init__(self, num):
self.num = num
self.gotos = {}

def show(self, indent = ""):
'''
Representaion of this state, and the states 'underneath' it
'''
print indent+`self.num`+':'
for i,g in self.gotos.items():
if type(g) == State:
print indent+"-"+i+"->"
g.show(indent+" ")
else:
print indent+"-"+i+"-> "+`g`

def code(self, out, lvl):
'''
Spit out code for a while/break based state machine
'''
print >>out,lvl+"while 1: # state",self.num
print >>out,lvl+ind+"#print '%d'"%self.num
print >>out,lvl+ind+"n = next()"
for i,g in self.gotos.items():
print >>out,lvl+ind+"if n == '"+i+"':"
if type(g) == State:
g.code(out,lvl+ind+ind)
else:
if g != self.num:
print >>out,lvl+ind+ind+"goto = "+`g`
print >>out,lvl+ind+ind+"break"
else:
print >>out,lvl+ind+ind+"continue"
print >>out,lvl+ind+"if n == None: return",self.num
print >>out,lvl+ind+"if goto != "+`self.num`+":"
print >>out,lvl+ind+ind+"break"

def functions(out,states, lvl = ""):
'''
Spit out code for a function-based state machine
'''
for num,transitions in enumerate(states):
print >>out,lvl+"def state_"+`num`+"():"
print >>out,lvl+ind+"#print '%d'"%num
print >>out,lvl+ind+"n = next()"
for i,g in transitions.items():
print >>out,lvl+ind+"if n == '"+i+"':"
print >>out,lvl+ind+ind+"return state_"+`g`
print >>out,lvl+ind+"if n == None: return None"
start = State(0)

# set up the hierarchy of State objects
def dfs(state, history):
for i,s in states[state.num].items():
if s in history:
state.gotos[i] = s
else:
child = State(s)
state.gotos[i] = child
dfs(child, history+[s])

dfs(start,[start.num])

#print start
#start.show()
fun = StringIO()
print >>fun,"def fsm():"
start.code(fun," ")
functions(fun,states)
def next_gen(): # for when we want specific input
for i in inp:
print i
yield i
yield None

import random
def next_genr(): # for when we want lots of input
for i in range(r):
n = random.choice(['a','b','c'])
#print n
yield n
yield None

next = next_genr().next

# show the generated code of both FSM implementations
print fun.getvalue()

exec fun.getvalue()
import time

# we want to ignore the cost of getting input, so we measure that first.
a = time.clock()
n = 1
while n:
n = next()
z = time.clock()
in_time = z-a
print "input time:",in_time
print "--"
next = next_genr().next
a = time.clock()
f = fsm()
z = time.clock()
print "while/break:",z-a-in_time

next = next_genr().next
a = time.clock()
state = state_0
while state:
state = state()
z = time.clock()
print "functions:",z-a-in_time
Jan 25 '06 #1
2 1962
Carl Cerecke <cd*@maxnet.co.nz> writes:
3. Not as fast as byte code hacks, or using pyrex/psyco. Peter Hansen
is right. One of those is likely a better solution if you don't need
pure python.


If you don't need pure python than your approach still beats
everything else. Just generate C code (or assembly code) instead of
Python.
Jan 25 '06 #2
Paul Rubin wrote:
Carl Cerecke <cd*@maxnet.co.nz> writes:
3. Not as fast as byte code hacks, or using pyrex/psyco. Peter Hansen
is right. One of those is likely a better solution if you don't need
pure python.

If you don't need pure python than your approach still beats
everything else. Just generate C code (or assembly code) instead of
Python.


If you are generating C code, then you can, instead, use the much
maligned goto to jump directly between states. All this
while/break/continue hackery is just to emulate the humble goto.

Using gotos is probably about as fast as you can get.

Cheers,
Carl.
Jan 25 '06 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

33
by: Diez B. Roggisch | last post by:
Hi, today I rummaged through the language spec to see whats in the for ... else: for me. I was sort of disappointed to learn that the else clauses simply gets executed after the loop-body -...
16
by: Timothy Fitz | last post by:
http://www.python.org/moin/PythonSpeed ] "Starting with Py2.3, the interpreter optimizes 'while 1' to just a single jump. In contrast "while True" takes several more steps. While the latter is...
8
by: shrishjain | last post by:
Dear All, I am having problem in reading bytes from a binary file. I read the file in following way: ifstream in("filename"); char c; while(true) { in.read(&c, 1); if(in.eof()){
36
by: invni | last post by:
I have a nested while. How do I go from the inner while to the beginning of the outer while? Can this be done without using goto? while_1() { some codes here while_2() { if true go to the...
4
by: Gary | last post by:
Hi, I get this error " " when my web page run, what does it mean? Hope someone can help!!! Gary
5
by: Joe Reynolds | last post by:
i have an application that will take user input from a text box and write it to an access database. i need to make sure that if they ever enter a single line of text that it has at least 1 space...
9
by: Cybex | last post by:
I am trying to get this to work but when ever I enter an proper integer it just hangs. The Switch default seems to catch the improper integers but the right ones are not triggering the way I...
26
by: a.mil | last post by:
I am programming for code-speed, not for ansi or other nice-guy stuff and I encountered the following problem: When I have a for loop like this: b=b0; for (a=0,i=0;i<100;i++,b--) { if (b%i)...
12
by: desktop | last post by:
Are there any performance issues between: bool run = true; while(run) { if (bob1 &&){ //dothing break; }
6
by: nickels | last post by:
Ok i already made a program that uses char and when someone enters a letter it will give them a conversion i made for that letter. That looks like this. import java.util.Scanner; public class...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.