Rule-based symbolic programming in Maxima?



Alasdair,

I've kind of jumped the gun, so to speak. As programming rules in
Maxima is something of a black art, I got started on some rules for
z-transforms to make sure it's actually possible before I tell you so...
Anyway, I've appended this attempt (such as it is) to this message.

To learn about rules, in the reference manual see defrule,
tellsimpafter, and matchdeclare. There are some share packages
which construct and apply rules; one of them is ezunits.mac.
I think vect.mac defines some rules too.

The stuff below is sketchy, but I think we can beef it up.
It would be nice to get this z-transform stuff working since the
basic model of general rules + some special cases applies to
other integral transforms.

I hope I haven't spoiled the fun. I'm pretty sure there remains
a lot of work (maybe meaning a completely different approach)
to make a practically useful package.

HTH
Robert

PS. Here's the script as it stands (unfinished).
/* z-transform stuff
 * Examples:

    e0 : z_transform (kron_delta (m, x), m, u);
    e1 : z_transform (1, m, u);
    e2 : z_transform (m, m, u);
    e3 : z_transform (convolution (f(m, u), g(m, u)), m, u);
    e4 : z_transform (sin (m*omega), m, u);

    apply_z_transform (e0);
        => 1/u^x
    apply_z_transform (e1);
        => 1/(1-1/u)
    apply_z_transform (e2);
        => 1/((1-1/u)^2*u)
    apply_z_transform (e3);
        => z_transform(f(m,u),m,u)*z_transform(g(m,u),m,u)
    apply_z_transform (e4);
        => sin(omega)/((-2*cos(omega)/u+1/u^2+1)*u)
 */

matchdeclare ([nn, zz], symbolp);

/* Reverse the arguments so zz and nn are known when
 * Maxima tries to match the expression to be transformed
 */
matchdeclare (aa, all);
defrule (r1,
    z_transform (aa, nn, zz),
    mrofsnart_z (zz, nn, aa));

defrule (r2,
    mrofsnart_z (zz, nn, 1),
    1/(1 - 1/zz));

/* Have to try kron_delta both ways ... sigh */

simp : false;
defrule (r3,
    mrofsnart_z (zz, nn, kron_delta (nn, aa)),
    zz^(- aa));
defrule (r4,
    mrofsnart_z (zz, nn, kron_delta (aa, nn)),
    zz^(- aa));
simp : true;

defrule (r5,
    mrofsnart_z (zz, nn, nn),
    (1/zz)/(1 - 1/zz)^2);

defrule (r6,
    mrofsnart_z (zz, nn, nn^2),
    (1/zz)*(1 + 1/zz)/(1 - 1/zz)^3);

matchdeclare (cc, lambda ([e], not atom(e) and op(e) = 'convolution));
defrule (r7,
    mrofsnart_z (zz, nn, cc),
    block ([a : args(cc)], product (z_transform (a[i], nn, zz), i, 1 ,
length(a))));

matchdeclare (aa, lambda ([e], e # n));

defrule (r8,
    mrofsnart_z (zz, nn, sin (aa*nn)),
    sin(aa)*(1/zz)/(1 - 2*(1/zz)*cos(aa) + 1/zz^2));

defrule (r9,
    mrofsnart_z (zz, nn, cos (aa*nn)),
    (1 - cos(aa)*(1/zz))/(1 - 2*(1/zz)*cos(aa) + 1/zz^2));

matchdeclare (aa, all);
defrule (r10,
    mrofsnart_z (zz, nn, aa),
    z_transform (aa, nn, zz));

apply_z_transform (e) :=
    apply1 (e, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10);

declare (z_transform, linear);