Revision: 6276 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6276&view=rev Author: fer_perez Date: 2008-10-19 09:11:30 +0000 (Sun, 19 Oct 2008)
Log Message: ----------- Workbook updates. Modified Paths: -------------- trunk/py4science/workbook/bessel.tex trunk/py4science/workbook/fft_imdenoise.tex trunk/py4science/workbook/qsort.tex trunk/py4science/workbook/quad_newton.tex trunk/py4science/workbook/trapezoid.tex trunk/py4science/workbook/update_problems.py trunk/py4science/workbook/wallis_pi.tex Added Paths: ----------- trunk/py4science/examples/mkprob.py Removed Paths: ------------- trunk/py4science/examples/mkskel.py Copied: trunk/py4science/examples/mkprob.py (from rev 6270, trunk/py4science/examples/mkskel.py) =================================================================== --- trunk/py4science/examples/mkprob.py (rev 0) +++ trunk/py4science/examples/mkprob.py 2008-10-19 09:11:30 UTC (rev 6276) @@ -0,0 +1,325 @@ +#!/usr/bin/env python +"""Make skeletons out of Python scripts. + +Usage: + + mkprob.py [--test] file1.py file2.py .... + +If --test is given, the test suite is run instead. + +For each input filename f.py, a pair of output files is generated, f_soln.py +and f_skel.py. + +Source markup is very simple. The tests in the file show precisely how it +works, but in summary: + +- Pure comment lines with the special marker (#@) are left in the skeleton + (only the marker is stripped, but they remain as valid comments). These are + typically used for hints. + +- Code lines terminated with the marker are: + + - In the skeleton, replaced by a NotImplementedError call. Consecutive lines + are replaced by a single call. + + - In the solution, kept as is but the marker is removed. +""" + +from __future__ import with_statement + +#----------------------------------------------------------------------------- +# Stdlib imports +import os +import re +import shutil +import sys + +# Third-party imports +import nose + +# Constants +MARKER = '#@' +DEL_RE = re.compile(r'''^((\s*)(.*?))\s*%s\s*$''' % MARKER) +HINT_RE = re.compile(r'''^(?P<space>\s*)%s\s+(?P<hint>.*)$''' % MARKER) + + +#----------------------------------------------------------------------------- +# Main code begins + +def src2soln(src): + """Remove markers from input source, leaving all else intact. + + Inputs: + src : sequence of lines (file-like objects work out of the box) + """ + + out = [] + addline = out.append + for line in src: + # Check for lines to delete and with hints + mdel = DEL_RE.match(line) + mhint = HINT_RE.match(line) + + # All hints are unconditionally removed + if mhint is None: + if mdel: + # if marker is matched in code, strip it and leave the code + line = mdel.group(1)+'\n' + addline(line) + + return ''.join(out) + + +def src2skel(src): + """Remove markers from input source, replacing marked lines. + + Marked lines are replaced with "raise NotImplementedError" calls that + summarize the total number of deleted lines. + + Inputs: + src : sequence of lines (file-like objects work out of the box) + """ + + def flush_buffers(normal_lines,del_lines=0): + """Local function to reuse some common code""" + + if state_cur == normal: + # add the normal lines + out.extend(normal_lines) + normal_lines[:] = [] + else: + # Add the summary of 'raise' lines + + # flush counter of code (disabled, we report static summary) + #msg = '1 line' if del_lines==1 else ('%s lines' % del_lines) + #exc = exc_tpl % msg + exc = exc_tpl + + # Use the last value of 'space' + line = '%s%s' % (spaces[0],exc) + out.append(line) + del_lines = 0 + spaces[:] = [] + + return del_lines + + # used to report actual # of lines removed - disabled + #exc_tpl = "raise NotImplementedError('%s missing')\n" + exc_tpl = "raise NotImplementedError('insert missing code here')\n" + + # states for state machine and other initialization + normal,delete = 0,1 + state_cur = normal + del_lines = 0 # counter, in case we want to report # of deletions + spaces = [] + normal_lines = [] + out = [] + + # To remove multiple consecutive lines of input marked for deletion, we + # need a small state machine. + for line in src: + # Check for lines to delete and with hints + mdel = DEL_RE.match(line) + mhint = HINT_RE.match(line) + + if mhint: + state_new = normal + hint = mhint.group('space')+'# ' + mhint.group('hint') +'\n' + normal_lines.append(hint) + else: + if mdel is None: + state_new = normal + normal_lines.append(line) + else: + state_new = delete + del_lines += 1 + spaces.append(mdel.group(2)) + + # Flush output only when there's a change of state + if state_new != state_cur: + del_lines = flush_buffers(normal_lines,del_lines) + + # Update state machine + state_cur = state_new + + # Final buffer flush is unconditional + flush_buffers(normal_lines) + + return ''.join(out) + + +def transform_file(fpath,fname_skel,fname_soln): + """Run the cleanup routines for a given input, creating skel and soln. + """ + + # get the mode of the input so that we can create the output files with the + # same mode + fmode = os.stat(fpath).st_mode + + with open(fpath) as infile: + # Generate the skeleton + skel = src2skel(infile) + with open(fname_skel,'w') as fskel: + fskel.write(skel) + os.chmod(fname_skel,fmode) + + # Reset the input file pointer and generate the solution + infile.seek(0) + soln = src2soln(infile) + with open(fname_soln,'w') as fsoln: + fsoln.write(soln) + os.chmod(fname_soln,fmode) + +#----------------------------------------------------------------------------- +# Main execution routines + +def copyforce(src,dest): + """Forceful file link/copy that overwrites destination files.""" + try: + copy = os.link + except AttributeError: + copy = shutil.copy + if os.path.isfile(dest): + os.remove(dest) + copy(src,dest) + + +def mvforce(src,dest): + """Forceful file copy that overwrites destination files.""" + if os.path.isfile(dest): + os.remove(dest) + shutil.move(src,dest) + + +def main(argv=None): + """Main entry point as a command line script for normal execution""" + + if argv is None: + argv = sys.argv + + # If there are subdirs called skel and soln, we populate them by moving the + # generated files there, otherwise they're left in the current dir. + skel_dir = 'skel' + soln_dir = 'soln' + has_skel_dir = os.path.isdir(skel_dir) + has_soln_dir = os.path.isdir(soln_dir) + + # First, check that all files are present and abort immediately if any of + # them isn't there. + for fpath in argv[1:]: + if not os.path.isfile(fpath): + raise OSError("file %r not found" % fpath) + + # If all files are there, then go ahead and process them unconditionally + for fpath in argv[1:]: + basename, ext = os.path.splitext(fpath) + fname_skel = basename + '_skel' + ext + fname_soln = basename + '_soln' + ext + transform_file(fpath,fname_skel,fname_soln) + # Move files over to final dirs if present + if has_skel_dir: + mvforce(fname_skel,os.path.join(skel_dir,fname_skel)) + if has_soln_dir: + mvforce(fname_soln,os.path.join(soln_dir,fname_soln)) + +#----------------------------------------------------------------------------- +# Tests + +def str_match(s1,s2): + """Check that two strings are equal ignoring trailing whitespace.""" + #print '***S1\n',s1,'\n***S2\n',s2 # dbg + nose.tools.assert_equal(s1.rstrip(),s2.rstrip()) + + +def test_simple(): + src = """ + first line + del line #@ + second line + """ + srclines = src.splitlines(True) + + clean = """ + first line + raise NotImplementedError('insert missing code here') + second line + """ + + cleaned = src2skel(srclines) + yield str_match,cleaned,clean + + clean = """ + first line + del line + second line + """ + cleaned = src2soln(src.splitlines(True)) + yield str_match,cleaned,clean + + +def test_multi(): + src = """ + first line + #@ Hint: remember that + #@ idea we discussed before... + del line #@ + del line2 #@ + del line3 #@ + second line: + del line4 #@ + del line5 #@ + third line + + some indented code: #@ + with more... #@ + """ + srclines = src.splitlines(True) + + clean = """ + first line + # Hint: remember that + # idea we discussed before... + raise NotImplementedError('insert missing code here') + second line: + raise NotImplementedError('insert missing code here') + third line + + raise NotImplementedError('insert missing code here') + """ + cleaned = src2skel(srclines) + yield str_match,cleaned,clean + + clean = """ + first line + del line + del line2 + del line3 + second line: + del line4 + del line5 + third line + + some indented code: + with more... + """ + cleaned = src2soln(srclines) + yield str_match,cleaned,clean + + [EMAIL PROTECTED] +def test(): + """Simple self-contained test runner.""" + nose.runmodule(__name__,exit=False, + argv=['--doctests', + #'-s', + #'--pdb-failures', + ]) + +#----------------------------------------------------------------------------- +# Execution from the command line. + +if __name__ == "__main__": + if '--test' in sys.argv: + test() + else: + main(sys.argv) Property changes on: trunk/py4science/examples/mkprob.py ___________________________________________________________________ Added: svn:executable + * Added: svn:mergeinfo + Deleted: trunk/py4science/examples/mkskel.py =================================================================== --- trunk/py4science/examples/mkskel.py 2008-10-19 09:04:27 UTC (rev 6275) +++ trunk/py4science/examples/mkskel.py 2008-10-19 09:11:30 UTC (rev 6276) @@ -1,325 +0,0 @@ -#!/usr/bin/env python -"""Make skeletons out of Python scripts. - -Usage: - - mkskel [--test] file1.py file2.py .... - -If --test is given, the test suite is run instead. - -For each input filename f.py, a pair of output files is generated, f_soln.py -and f_skel.py. - -Source markup is very simple. The tests in the file show precisely how it -works, but in summary: - -- Pure comment lines with the special marker (#@) are left in the skeleton - (only the marker is stripped, but they remain as valid comments). These are - typically used for hints. - -- Code lines terminated with the marker are: - - - In the skeleton, replaced by a NotImplementedError call. Consecutive lines - are replaced by a single call. - - - In the solution, kept as is but the marker is removed. -""" - -from __future__ import with_statement - -#----------------------------------------------------------------------------- -# Stdlib imports -import os -import re -import shutil -import sys - -# Third-party imports -import nose - -# Constants -MARKER = '#@' -DEL_RE = re.compile(r'''^((\s*)(.*?))\s*%s\s*$''' % MARKER) -HINT_RE = re.compile(r'''^(?P<space>\s*)%s\s+(?P<hint>.*)$''' % MARKER) - - -#----------------------------------------------------------------------------- -# Main code begins - -def src2soln(src): - """Remove markers from input source, leaving all else intact. - - Inputs: - src : sequence of lines (file-like objects work out of the box) - """ - - out = [] - addline = out.append - for line in src: - # Check for lines to delete and with hints - mdel = DEL_RE.match(line) - mhint = HINT_RE.match(line) - - # All hints are unconditionally removed - if mhint is None: - if mdel: - # if marker is matched in code, strip it and leave the code - line = mdel.group(1)+'\n' - addline(line) - - return ''.join(out) - - -def src2skel(src): - """Remove markers from input source, replacing marked lines. - - Marked lines are replaced with "raise NotImplementedError" calls that - summarize the total number of deleted lines. - - Inputs: - src : sequence of lines (file-like objects work out of the box) - """ - - def flush_buffers(normal_lines,del_lines=0): - """Local function to reuse some common code""" - - if state_cur == normal: - # add the normal lines - out.extend(normal_lines) - normal_lines[:] = [] - else: - # Add the summary of 'raise' lines - - # flush counter of code (disabled, we report static summary) - #msg = '1 line' if del_lines==1 else ('%s lines' % del_lines) - #exc = exc_tpl % msg - exc = exc_tpl - - # Use the last value of 'space' - line = '%s%s' % (spaces[0],exc) - out.append(line) - del_lines = 0 - spaces[:] = [] - - return del_lines - - # used to report actual # of lines removed - disabled - #exc_tpl = "raise NotImplementedError('%s missing')\n" - exc_tpl = "raise NotImplementedError('insert missing code here')\n" - - # states for state machine and other initialization - normal,delete = 0,1 - state_cur = normal - del_lines = 0 # counter, in case we want to report # of deletions - spaces = [] - normal_lines = [] - out = [] - - # To remove multiple consecutive lines of input marked for deletion, we - # need a small state machine. - for line in src: - # Check for lines to delete and with hints - mdel = DEL_RE.match(line) - mhint = HINT_RE.match(line) - - if mhint: - state_new = normal - hint = mhint.group('space')+'# ' + mhint.group('hint') +'\n' - normal_lines.append(hint) - else: - if mdel is None: - state_new = normal - normal_lines.append(line) - else: - state_new = delete - del_lines += 1 - spaces.append(mdel.group(2)) - - # Flush output only when there's a change of state - if state_new != state_cur: - del_lines = flush_buffers(normal_lines,del_lines) - - # Update state machine - state_cur = state_new - - # Final buffer flush is unconditional - flush_buffers(normal_lines) - - return ''.join(out) - - -def transform_file(fpath,fname_skel,fname_soln): - """Run the cleanup routines for a given input, creating skel and soln. - """ - - # get the mode of the input so that we can create the output files with the - # same mode - fmode = os.stat(fpath).st_mode - - with open(fpath) as infile: - # Generate the skeleton - skel = src2skel(infile) - with open(fname_skel,'w') as fskel: - fskel.write(skel) - os.chmod(fname_skel,fmode) - - # Reset the input file pointer and generate the solution - infile.seek(0) - soln = src2soln(infile) - with open(fname_soln,'w') as fsoln: - fsoln.write(soln) - os.chmod(fname_soln,fmode) - -#----------------------------------------------------------------------------- -# Main execution routines - -def copyforce(src,dest): - """Forceful file link/copy that overwrites destination files.""" - try: - copy = os.link - except AttributeError: - copy = shutil.copy - if os.path.isfile(dest): - os.remove(dest) - copy(src,dest) - - -def mvforce(src,dest): - """Forceful file copy that overwrites destination files.""" - if os.path.isfile(dest): - os.remove(dest) - shutil.move(src,dest) - - -def main(argv=None): - """Main entry point as a command line script for normal execution""" - - if argv is None: - argv = sys.argv - - # If there are subdirs called skel and soln, we populate them by moving the - # generated files there, otherwise they're left in the current dir. - skel_dir = 'skel' - soln_dir = 'soln' - has_skel_dir = os.path.isdir(skel_dir) - has_soln_dir = os.path.isdir(soln_dir) - - # First, check that all files are present and abort immediately if any of - # them isn't there. - for fpath in argv[1:]: - if not os.path.isfile(fpath): - raise OSError("file %r not found" % fpath) - - # If all files are there, then go ahead and process them unconditionally - for fpath in argv[1:]: - basename, ext = os.path.splitext(fpath) - fname_skel = basename + '_skel' + ext - fname_soln = basename + '_soln' + ext - transform_file(fpath,fname_skel,fname_soln) - # Move files over to final dirs if present - if has_skel_dir: - mvforce(fname_skel,os.path.join(skel_dir,fname_skel)) - if has_soln_dir: - mvforce(fname_soln,os.path.join(soln_dir,fname_soln)) - -#----------------------------------------------------------------------------- -# Tests - -def str_match(s1,s2): - """Check that two strings are equal ignoring trailing whitespace.""" - #print '***S1\n',s1,'\n***S2\n',s2 # dbg - nose.tools.assert_equal(s1.rstrip(),s2.rstrip()) - - -def test_simple(): - src = """ - first line - del line #@ - second line - """ - srclines = src.splitlines(True) - - clean = """ - first line - raise NotImplementedError('insert missing code here') - second line - """ - - cleaned = src2skel(srclines) - yield str_match,cleaned,clean - - clean = """ - first line - del line - second line - """ - cleaned = src2soln(src.splitlines(True)) - yield str_match,cleaned,clean - - -def test_multi(): - src = """ - first line - #@ Hint: remember that - #@ idea we discussed before... - del line #@ - del line2 #@ - del line3 #@ - second line: - del line4 #@ - del line5 #@ - third line - - some indented code: #@ - with more... #@ - """ - srclines = src.splitlines(True) - - clean = """ - first line - # Hint: remember that - # idea we discussed before... - raise NotImplementedError('insert missing code here') - second line: - raise NotImplementedError('insert missing code here') - third line - - raise NotImplementedError('insert missing code here') - """ - cleaned = src2skel(srclines) - yield str_match,cleaned,clean - - clean = """ - first line - del line - del line2 - del line3 - second line: - del line4 - del line5 - third line - - some indented code: - with more... - """ - cleaned = src2soln(srclines) - yield str_match,cleaned,clean - - [EMAIL PROTECTED] -def test(): - """Simple self-contained test runner.""" - nose.runmodule(__name__,exit=False, - argv=['--doctests', - #'-s', - #'--pdb-failures', - ]) - -#----------------------------------------------------------------------------- -# Execution from the command line. - -if __name__ == "__main__": - if '--test' in sys.argv: - test() - else: - main(sys.argv) Modified: trunk/py4science/workbook/bessel.tex =================================================================== --- trunk/py4science/workbook/bessel.tex 2008-10-19 09:04:27 UTC (rev 6275) +++ trunk/py4science/workbook/bessel.tex 2008-10-19 09:11:30 UTC (rev 6276) @@ -1,6 +1,10 @@ \section{Bessel functions} \label{sec:bessel} +\textbf{Illustrates}: Special functions library, array manipulations +to check recursion relation. + + In this exercise, you will verify a few simple relations involving the Bessel functions of the first kind. The important relations to keep in mind are the asymptotic form of $J_n(x)$ for $x>>n$: Modified: trunk/py4science/workbook/fft_imdenoise.tex =================================================================== --- trunk/py4science/workbook/fft_imdenoise.tex 2008-10-19 09:04:27 UTC (rev 6275) +++ trunk/py4science/workbook/fft_imdenoise.tex 2008-10-19 09:11:30 UTC (rev 6276) @@ -1,6 +1,9 @@ \section{FFT Image Denoising} \label{sec:fft_imdenoise} +\textbf{Illustrates}: 2-d image denoising, use of the scipy FFT library, +array manipulations, image plotting. + Convolution of an input with with a linear filter in the termporal or spatial domain is equivalent to multiplication by the fourier transforms of the input and the filter in the spectral domain. This provides a conceptually simple way Modified: trunk/py4science/workbook/qsort.tex =================================================================== --- trunk/py4science/workbook/qsort.tex 2008-10-19 09:04:27 UTC (rev 6275) +++ trunk/py4science/workbook/qsort.tex 2008-10-19 09:11:30 UTC (rev 6276) @@ -1,6 +1,7 @@ - \section{Sorting quickly with QuickSort } +\textbf{Illustrates}: lists, recursion. + Quicksort is one of the best known, and probably the simplest, fast algorithm for sorting $n$ items. It is fast in the sense that it requires on average $\mathcal{O}(n\log n)$ comparisons instead of Modified: trunk/py4science/workbook/quad_newton.tex =================================================================== --- trunk/py4science/workbook/quad_newton.tex 2008-10-19 09:04:27 UTC (rev 6275) +++ trunk/py4science/workbook/quad_newton.tex 2008-10-19 09:11:30 UTC (rev 6276) @@ -1,6 +1,9 @@ \section{Newton's method} \label{sec:quad_newton} +\textbf{Illustrates:} functions as first class objects, use of the +scipy libraries. + Consider the problem of solving for $t$ in \begin{equation} \int_{o}^{t}f(s)ds=u Modified: trunk/py4science/workbook/trapezoid.tex =================================================================== --- trunk/py4science/workbook/trapezoid.tex 2008-10-19 09:04:27 UTC (rev 6275) +++ trunk/py4science/workbook/trapezoid.tex 2008-10-19 09:11:30 UTC (rev 6276) @@ -1,6 +1,9 @@ \section{Trapezoidal rule} \label{sec:trapezoid} +\textbf{Illustrates}: basic array slicing, functions as first class +objects. + In this exercise, you are tasked with implementing the simple trapezoid rule formula for numerical integration. If we want to compute the definite integral \begin{equation} Modified: trunk/py4science/workbook/update_problems.py =================================================================== --- trunk/py4science/workbook/update_problems.py 2008-10-19 09:04:27 UTC (rev 6275) +++ trunk/py4science/workbook/update_problems.py 2008-10-19 09:11:30 UTC (rev 6276) @@ -10,10 +10,11 @@ from IPython.genutils import target_outdated # Constants -SRC_DIR = '../examples' -UPDATE = './mkskel.py' -PROBLEMS_DIR = 'problems' +SRC_DIR = '../examples' # source dir for the examples +UPDATE = './mkprob.py' # executable to make problems (in SRC_DIR) +PROBLEMS_DIR = 'problems' # directory for problem output (in this dir) + if __name__ == '__main__': problems = [f for f in os.listdir(PROBLEMS_DIR) if f.endswith('.py')] Modified: trunk/py4science/workbook/wallis_pi.tex =================================================================== --- trunk/py4science/workbook/wallis_pi.tex 2008-10-19 09:04:27 UTC (rev 6275) +++ trunk/py4science/workbook/wallis_pi.tex 2008-10-19 09:11:30 UTC (rev 6276) @@ -1,6 +1,7 @@ - \section{Wallis' slow road to $\pi$} +\textbf{Illustrates}: arbitrary size integers, simple function definitions. + Wallis' formula is an infinite product that converges (slowly) to $\pi$:\begin{equation} \pi=\prod_{i=1}^{\infty}\frac{4i^{2}}{4i^{2}-1}.\end{equation} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------- This SF.Net email is sponsored by the Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK & win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world http://moblin-contest.org/redirect.php?banner_id=100&url=/ _______________________________________________ Matplotlib-checkins mailing list Matplotlib-checkins@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins