I gave two presentations at the 2006 PyCon in Dallas, TX.
Here are some of the projects I'm doing in Python.
As an exercise (and to avoid the overhead of importing a large numerical analysis package just to do a matrix inversion), I put together a simple Matrix class that computes transpose, inverse, determinant, eigenvectors and eigenvalues of a matrix, and supports matrix addition and multiplication. Also supports a simple matrix initialization from a formatted string, similar to Matlab. (Also like Matlab, row/column references are 1-based, not 0-based.)
m = Matrix("""1 2 3 4 5 11 20 3 2 7 11 1 0 5 3 1""") m_inv = m.inverse() print m print m_inv print m*m_invprints
1.0, 2.0, 3.0, 4.0 5.0, 11.0, 20.0, 3.0 2.0, 7.0, 11.0, 1.0 0.0, 5.0, 3.0, 1.0 -0.5, 1.167, -2.167, 0.667 -0.167, 0.241, -0.519, 0.463 0.167, -0.352, 0.796, -0.407 0.333, -0.148, 0.204, -0.093 1.0, 0.0, 0.0, 0.0 0.0, 1.0, 0.0, 0.0 0.0, 0.0, 1.0, 0.0 0.0, 0.0, 0.0, 1.0It's not blazingly fast, but it is a simple small-footprint matrix class for simple equation solving and eigenvectors (up to about 10x10 matrices). This class also makes heavy use of memoizing, so that repeated calls to inverse() do not recalculate the matrix inverse every time.
This parsing module takes a different approach from the traditional lex/yacc method of creating parsers. This module defines several classes for constructing your grammar as a composed object directly within your program source code. As you define the grammar, you can associate parsing actions and tag names to the various grammar elements. Your code then uses this object to parse text strings, and as various elements in the grammar are matched, the parsing actions get invoked. After all parsing is completed, the resulting token strings are organized into lists, dictionaries, or named attributes. While this sounds complicated, the examples are actually quite simple.
Here is a grammar for a simple SQL parser.
# define SQL tokens selectToken = CaselessLiteral( "select" ) fromToken = CaselessLiteral( "from" ) starToken = Literal( "*" ) commaToken = Literal( "," ) dotToken = Literal( "." ) ident = Word( alphas, alphanums + "_$" ) columnName = Upcase( ident ) columnNameList = delimitedList( columnName ) tableName = Upcase( Combine( ident + Optional( dotToken + ident ) ) ) tableNameList = delimitedList( tableName ) # define the grammar simpleSQL = selectToken + \ ( starToken | columnNameList ).setResultsName( "columns" ) + \ fromToken + \ tableNameList.setResultsName( "tables" )(Note that by default, the parser ignores any extra whitespace between tokens, so the grammar does not have to be cluttered with lots of "ws" elements.)
Here is the code that uses this grammar:
def test( str ): print str,"->" try: tokens = simpleSQL.parseString( str ) print "tokens = ", tokens print "tokens.columns =", tokens.columns print "tokens.tables =", tokens.tables except ParseException, err: print " "*err.loc + "^\n" + err.msg print err print test( "SELECT * from XYZZY, ABC" ) test( "select * from SYS.XYZZY" ) test( "Select A from Sys.dual" ) test( "Select A,B,C from Sys.dual" ) test( "Select A, B, C from Sys.dual" ) test( "Select A, B, C from Sys.dual, Table2 " ) test( "Xelect A, B, C from Sys.dual" ) test( "Select A, B, C frox Sys.dual" )Finally here is the output from this test program.
SELECT * from XYZZY, ABC -> tokens = ['select', '*', 'from', ['XYZZY', 'ABC']] tokens.columns = * tokens.tables = ['XYZZY', 'ABC'] select * from SYS.XYZZY -> tokens = ['select', '*', 'from', ['SYS.XYZZY']] tokens.columns = * tokens.tables = ['SYS.XYZZY'] Select A from Sys.dual -> tokens = ['select', ['A'], 'from', ['SYS.DUAL']] tokens.columns = ['A'] tokens.tables = ['SYS.DUAL'] Select A,B,C from Sys.dual -> tokens = ['select', ['A', 'B', 'C'], 'from', ['SYS.DUAL']] tokens.columns = ['A', 'B', 'C'] tokens.tables = ['SYS.DUAL'] Select A, B, C from Sys.dual -> tokens = ['select', ['A', 'B', 'C'], 'from', ['SYS.DUAL']] tokens.columns = ['A', 'B', 'C'] tokens.tables = ['SYS.DUAL'] Select A, B, C from Sys.dual, Table2 -> tokens = ['select', ['A', 'B', 'C'], 'from', ['SYS.DUAL', 'TABLE2']] tokens.columns = ['A', 'B', 'C'] tokens.tables = ['SYS.DUAL', 'TABLE2'] Xelect A, B, C from Sys.dual -> ^ Expected 'select' Expected 'select' (0), (1,1) Select A, B, C frox Sys.dual -> ^ Expected 'from' Expected 'from' (15), (1,16)
Here's another parsing example, of a 4-function infix notation algebraic parser.
This module is now available at SourceForge (http://sourceforge.net/projects/pyparsing/).
Thanks to Dave Kuhlman for converting my "how to" text to HTML.
This is a simple module for creation of basic graphic in BMP format files, with or without RLE compression, if you want to display graphics but don't want all the overhead of a complex graphics package, such as PIL.
bmp = BitMap( 400, 400, Color.TEAL.lighten() ) bmp.drawSquare( 0, 0, 400 ) # draw variety of colors colors = [ Color.BLACK, Color.RED, Color.GREEN, Color.BLUE, \ Color.CYAN, Color.MAGENTA, Color.YELLOW, Color.BLUE, \ Color.DKRED, Color.DKGREEN, Color.DKBLUE, Color.TEAL, \ Color.PURPLE, Color.BROWN, Color.GRAY ] for i,c in enumerate(colors): bmp.setPenColor( c ) for j in range(8): bmp.drawRect( i*25, j*45, 25, 45, True ) bmp.setPenColor( bmp.getPenColor().lighten() ) bmp.setDefaultPenColor() bmp.drawRect( i*25, 0, 25, 360, False ) # test drawing lines at various angles bmp.setPenColor( Color.WHITE ) bmp.drawSquare( 10, 10, 380 ) bmp.drawSquare( 9, 9, 382 ) bmp.drawLine( 10, 10, 389, 389 ) bmp.drawLine( 10, 10, 70, 389 ) bmp.drawLine( 10, 10, 389, 70 ) bmp.drawLine( 10, 389, 389, 10 ) bmp.drawLine( 10, 389, 70, 10 ) bmp.drawLine( 10, 70, 389, 10 ) # test saving and restoring pen color saveColor = bmp.setPenColor( Color.DKGREEN ) bmp.drawRect( 90, 100, 40, 30, fill=True ) bmp.setPenColor( saveColor ) bmp.drawRect( 95, 105, 30, 20, fill=True ) # test drawing circles bmp.setPenColor( Color.DKRED ) bmp.drawCircle( 250, 150, 40, fill=True ) bmp.setPenColor( Color.WHITE ) bmp.drawCircle( 250, 150, 25, fill=True ) bmp.setPenColor( Color.BLUE ) bmp.drawCircle( 250, 150, 20, fill=True ) bmp.setPenColor( Color.WHITE ) bmp.drawCircle( 250, 150, 18, fill=True ) bmp.setPenColor( Color.BLUE ) bmp.drawCircle( 250, 150, 8 ) # test lines of different types bmp.setPenColor( Color.BLACK ) bmp.drawLine( 10, 380, 389, 380, BitMap.LINE_DASHED ) bmp.drawLine( 10, 373, 389, 373, BitMap.LINE_DOTTED ) bmp.drawLine( 10, 365, 389, 365, BitMap.LINE_DOT_DASH ) bmp.drawLine( 10, 358, 389, 325, BitMap.LINE_DASHED ) bmp.drawLine( 10, 353, 389, 320, BitMap.LINE_DOTTED ) bmp.drawLine( 10, 348, 389, 315, BitMap.LINE_DOT_DASH ) bmp.saveFile( "test.bmp" )
Over the past few days I've been working with Matlab, calling it from Python through Matlab's COM interface. In this way, I can build data sets and test cases in Python, and then pass the data through to Matlab for running Matlab functions and matrix commands. As part of working this through, I developed a wrapper class, for handling Matlab's special API issues.