quiz about symbolic manipulation

Bengt Richter bokr at oz.net
Sat Dec 14 01:44:46 EST 2002


On 14 Dec 2002 05:43:05 GMT, bokr at oz.net (Bengt Richter) wrote:

>On 14 Dec 2002 00:05:19 GMT, bokr at oz.net (Bengt Richter) wrote:
>[ ... first version substitute routine ...]
>> 'square(square(x+y)+z)+square(x+w)'
>> >>> substitute(e, 'square','(%s)**2')
>> '((x+y)**2+z)**2+(x+w)**2'
>>
>>Well, this is not so exciting for functions with multiple parameters. How
>>might you want to rewrite those? Probably isolate terms and rewrite each term
>>and then feed that as a tuple to a rewfmt? If you can assume no terms containing
>>nested commas (probably reasonable for math expressions) then it shouldn't be
>>too hard. But much beyond that and you may want to use the Python parser after all ;-)
>>
>>Anyway, I'll leave the rest as an exercise ;-)
>
>It was such a jellybean project I couldn't resist modding it a it to handle
>comma separated function args, and multiple functions:
>
One more time, allowing rewrite specs in terms of function parameters
specified as $1, $2, etc in the rewrite format.

====< simiosub.py >=======================================
# simiosub.py
# a program to rewrite function calls in an expression

from __future__ import generators
import tokenize, StringIO

def tokens(expr):
    tokens = tokenize.generate_tokens(StringIO.StringIO(expr).readline)
    return [t[1] for t in tokens]

def substitute(expr, **funs):
    def funrew(expr, funs):
        if isinstance(expr, str): toks = tokens(expr)
        else: toks = expr
        while toks:
            if toks[0] not in funs:
                yield toks.pop(0)
                continue
            currfun = toks.pop(0)
            # find and process parenthesized call parameter expression
            i = ump = 0
            for t in toks:
                i += 1
                if t =='(': ump += 1
                if t == ')':
                    ump -= 1
                    if not ump: break
            rest = toks[i:]
            parenexp = toks[1:i-1]
            ixcommas = [t[1] for t in zip(parenexp,range(len(parenexp)))
                       if t[0]==',']+[len(parenexp)]
            i = j = 0; paramdir= {}
            for k in ixcommas:
                i += 1  # for $1, $2, etc
                paramdir[str(i)] = ''.join(funrew(parenexp[j:k], funs))
                j = k+1
            yield (funs[currfun] % paramdir)
            toks = rest
            
    # change $x to %(x)s in formats
    sfuns = {}
    for k, v in funs.items():
        sl = v.split('$')
        for i in range(1,len(sl)): sl[i] = '%%(%s)s%s' % (sl[i][0],sl[i][1:])
        sfuns[k] = ''.join(sl)
    return ''.join(funrew(expr, sfuns))

if __name__ == '__main__':
    import sys
    args = sys.argv[1:]
    if not args: args = ['square(square(x+y)+z)+square(x+w)', 'square=($1)**2']
                        # should return '((x+y)**2+z)**2+(x+w)**2'
    e = args.pop(0); funs = dict(map(lambda x: tuple(x.split('=')),args))
    
    print 'before:', e
    for sub in args: print '   ',sub
    print ' after:', substitute(e, **funs)
==========================================================
Default test:

[22:42] C:\pywk\clp>simiosub.py
before: square(square(x+y)+z)+square(x+w)
    square=($1)**2
 after: ((x+y)**2+z)**2+(x+w)**2

A little more complex, changing to infix function calls:

[22:42] C:\pywk\clp>simiosub.py foo(x*y)+zeep(1,foo(2),3) "foo=(foo $1)" "zeep=(zeep $1 $2 $3)"
before: foo(x*y)+zeep(1,foo(2),3)
    foo=(foo $1)
    zeep=(zeep $1 $2 $3)
 after: (foo x*y)+(zeep 1 (foo 2) 3)

Using the reusability of parameters in the rewrite format:

[22:42] C:\pywk\clp>simiosub.py square(x+y) "square=($1)*($1)"
before: square(x+y)
    square=($1)*($1)
 after: (x+y)*(x+y)

And on the original test:

[22:45] C:\pywk\clp>simiosub.py square(square(x+y)+z)+square(x+w) "square=($1)*($1)"
before: square(square(x+y)+z)+square(x+w)
    square=($1)*($1)
 after: ((x+y)*(x+y)+z)*((x+y)*(x+y)+z)+(x+w)*(x+w)

Kind of fun, but that's enough following myself up ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list