When pattern matching is useful

May be that some other people want to use pattern-matching techniques in wrong ways or contexts. What I am interested in is much simpler and clear.

To be concrete, consider the use of pattern matching based transformation rules. And as an example, consider an expression that has terms of the form  exp(n/5*I*Pi), where n is an integer (from 1 to 4 say). And, for whatever reason I want to apply the rule exp(n/5*I*Pi) -> alpha^n (make it by another method is not the issue here). But 'applyrule'  (presumably  the "latest" development in this field) largely fails:

seq(applyrule(exp(n::integer/5*I*Pi)=alpha^n,exp(i/5*I*Pi)),i=1..4);

alpha, exp(2/5 I Pi), exp(3/5 I Pi), exp(4/5 I Pi)

My point is that instead of so many remains of past development, pattern matching tools should be provided that work well and are maintained. There is also an issue of fragmentation and multiplication, as the absence of reliable system-wide tools make that individual packages provide their own "solution".

 

 

one way

This fails because pattern matching won't 'split' a base type (not sure the correct terminology).  You could get it to work by using x::imaginary(fraction) in the pattern match and then removing the imaginary unit and scaling by five, however, what you would really like is to be able to provide an additional test to ensure that x has a denominator of 5.  That can be done, if crudely, with

seq(applyrule(exp(x::And(imaginary(fraction),`satisfies`(x -> denom(x/I)=5))*Pi)=alpha^(x/I*5)
              ,exp(i/5*I*Pi)),i=1..4);   
                                                 2       3       4
                                     alpha, alpha , alpha , alpha


JacquesC's picture

less type-system gymnastics

One of the under-appreciated aspects of patmatch are its capabilities of doing conditional matching, and thus conditional rewriting with applyrule.  So taking Joe's basic idea, one can encode this as

seq(applyrule(conditional(exp((n::imaginary(fraction))*Pi), _type(5*n/I,integer))=alpha^(5/I*n),exp(i/5*I*Pi)),i=1..4);

which also works.  But one can still see that Maple's internal representation for objects peeks through [there are fewer than 25(?) people in the world who would have been able to figure out the need for imaginary(fraction) here].  And note the use of the underscore in _type!  match suffers less from this particular disease, but there is no convenient wrapper like applyrule that goes along with it. Of course, match heavily relies on solve, so your mileage may vary.

_denom

Thanks for demonstrating the use of conditional; I recall reading of its existence but haven't ever used it. Actually, I'm not sure I've ever used applyrule before, so this should increase my awareness.  Because we've restricted n, one can safely use denom here to make the code a bit more friendly

seq(applyrule(conditional(exp((n::imaginary(fraction))*Pi), _denom(n)=5)=alpha^(5/I*n),exp(i/5*I*Pi)),i=1..4);

Note that the test for equality works fine despite the caveat in the applyrule help page:

... the condition has to be unevaluated or in inert form: use an `_` in front of every name, for example, _type(a,.freeof(x)) and it is not possible to use `=` or `<>`.

If that didn't work, one can do either _Testzero(_denom(n)-5) or _type(_denom(n),5).

Tricks

I may like such tricks as a "sport", but I dislike to be distracted when doing mathematics and I am forced to use them for no good reason. Nothing more than  a "normal" syntax, like that I have  used, should be required to produce the expected result.  I do not  think  that using here something like  "n::imaginary(fraction)"  qualifies as  "normal"  for anybody.

The example above is only one out of many.  Just changing the example a little bit:

seq(applyrule(exp(n::integer/5*q::name*Pi)=alpha^n,exp(i/5*q*Pi)),i=1..4);

requires thinking the trick again. So, my point here is not how to do this particular example, but  to exemplify a "generic" problem.

If this level of "sophistication" and "fine-tuning" is required to make 'applyrule' work for such a simple example, it shows to me that the pattern-matching system still needs much more development  to become useful for the ordinary user.

 

reality

Yes, but the reality is that n::integer/5 is never going to match anything.  It is analogous to using `n::integer + 3' and hoping that it will match some integer.  It won't.  Maple's matchers don't (as a rule) do more than match syntax.  I think we can see that this is the case for integer addition or multiplication.  For division it is not so apparent since we (the user) can see the desired target in the denominator.  However, Maple integer fractions are of type atomic so ...

That doesn't preclude one from creating a more sophisticated matcher that would translate, say, n::integer/5 into a conditional match that does what you want, but I suspect that a general approach would be difficult.

In your example, suppose that exp(q*Pi) appeared.  Mathematically, n=5 matches that, but I suspect you would not want it to match.   How would your hypothetical matcher deal with that?

JacquesC's picture

match

Something above match could do it:

> match(exp(q*Pi)=exp(n/5*q*Pi),{q},'s');

                                 true

> s;

                               {n = 5}

Robert Israel's picture

match

And similarly, for Joe's example:

> match(5 = n + 3,t,'s');

            true

> s;

{n = 2}

Not that match is without its problems.

> match(5*cos(2*t)+sin(2*t)=c*sin(w*t)+d*cos(w*t),t,'s');

    true

> s;

{w = 2, d = 0, c = 6}

and solve/identity

that works in this case where 'match'  does not:

solve(identity(5*cos(2*t)+sin(2*t)=c*sin(w*t)+d*cos(w*t),t),[c,d,w]);
[[c = 1, d = 5, w = 2], [c = -1, d = 5, w = -2]]

And some packages have matchers of their own. In short, there is a bunch of code around but not a single facility that can be relied upon.

my matcher

should replace exp(q*Pi) with alpha^5. Why do you say that I would not want this rule applied?

matches

I had assumed that 5 was in the denominator to enforce a match, that is, the reduced fraction must include a 5 (that you included only elements 1 through 4 in the original sequence suggested that interpretation). Apparently that wasn't your intent.  Rather you didn't want to match purely syntactically, but also algebraically.  Part of the difficulty with designing a matcher is that sometimes we want it to match purely on syntax, other times we want it to have some algebraic smarts.  Note that none of the solutions offered match the case i=0, which reduces to exp(0)=1.

algebraic pattern matching

Yes, I am mainly interested in "algebraic" pattern matching, as I  want to  use it for  mathematical calculations,  rather than data structure manipulations. 

My  point of view is that after so many years of development,  it is time that Maple provides a layer of abstraction that allows the user to operate in (close to)  "pure" mathematical  terms rather than being forced to think in syntactic terms. I mean here the difference between using 'subs' and 'algsubs'. So, my request is for more development in 'algsubs' kind of tools.

Indeed, I have avoided the case i=0 trying to keep the example simple. Automatic simplification is an additional nuisance here as eg I cannot have (unsimplified) alpha^0.

 

transformation

Realizing that this is merely an example, what you really want to be able to do is

superalgsubs(exp(q*Pi/5)=alpha, exp(2*q*Pi/5));
                                                 2
                                            alpha
JacquesC's picture

in theory

In theory one could write a thin shell above match to implement superalgsubs.  Of course, that would inherit all of match's bugs -- but I think that that would still be the right way to do it.  If match gets used enough, then its bugs might get fixed!

Minor typo: I am sure Joe meant to put alpha^q on the rhs.

typo free

No typo.  This corresponds to the modification Alejandro made (above).

JacquesC's picture

Oops

Silly me, my error.

superalgsubs

Yes, though I am not sure whether this 'superalgsubs' could resolve ambiguities  without providing it type information (or something equivalent) on the pattern as it is done for 'applyrule'. By the way, I largely regret that 'algsubs'  has not been enhanced for such a long time.

If this is the way to force an improvement of the underlying pattern-matching machinery, or the development of a new "PatternMatchingTools" package, for me it is OK.

JacquesC's picture

I completely agree

We are witnessing a fundamental shift in software these days.  In the 80s, it was expected that internal concerns of the developers were going to be visible in the interface (API or GUI) of a piece of software, and that "users" were sophisticated people who could deal with that.  But 20 years later, things have now changed drastically: users see software as tools to get a job done, and expect the software to intrude into their thinking as little as possible. 

This is not to say that this is easy to do.  But take a look at Google maps, for example, and you will see a beautiful such example.  There are many others, of course. 

alec's picture

Pattern based transforms

I have a procedure for pattern based transforms in my blog, written in 2005. It worked in many cases. I didn't continue working on it for 2 reasons. First - there were too many bugs in patmatch related procedures (such as matching regular parentheses with square brackets and inverse), and second - I had stopped using Maple myself at that time.

Alec

In Mathematica 5

For reference, and for the example of above, I have looked on how this can be done in Mathematica 5:

Table[Exp[i/5*q*Pi], {i, 4}] /. Exp[Rational[n_Integer, 5]*q*Pi] -> alpha^n

{alpha, alpha^2, alpha^3, alpha^4}

Not perfect (it does not work for i=0 or 5), and this 'Rational' is not the most obvious thing, but not so bad either. I believe that the equivalent syntax in Maple would imply a structured type, something like 'fraction(n::integer,5)' but as such does not seem correct.

What I would like to see available

Apparently there is nothing in Maple as a structured type like 'fraction(n::integer,5)' (I would like to be wrong). So I have hacked the following code which is quite primitive, and probably close to useless, just see how far something that resembles it is possible and to show what I would like to see available:

mypatmatch:=proc(ex,pt,n)
local tr1,tr2,l:
tr1:=e->evalindets(e,fraction,se->fr([op(se)]));
tr2:=p->evalindets(p,specfunc(anything,fraction),se->r::specfunc([op(se)],fr));
patmatch(tr1(ex),tr2(pt),'l');
if type(l,list(equation)) then
op([1,n],subs(l,r));
else print("no match");
end if:
end proc:

mypatmatch(exp(3/5*I*q),exp(fraction(integer,5)*c::name*I),1);

                                  3

mypatmatch(exp(u/5*I*q),exp(fraction(integer,5)*c::name*I),1);

                              "no match"

mypatmatch(exp(5/3*I*q),exp(fraction(integer,5)*c::name*I),1);

                              "no match"

mypatmatch(exp(5/7*I*q),exp(fraction(5,integer)*c::name*I),2);

                                  7

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
}