match: don't modify subexpression list if expression doesn't match the pattern.
authorAlexei Sheplyakov <varg@theor.jinr.ru>
Tue, 15 Jul 2008 17:08:22 +0000 (21:08 +0400)
committerAlexei Sheplyakov <varg@theor.jinr.ru>
Tue, 9 Sep 2008 10:17:07 +0000 (14:17 +0400)
As of now the match() method modifies the list of matched subexpressions
(its second argument) even if the expression in question does not match
the pattern. Thus, this simple program

 #include <ginac/ginac.h>
 #include <iostream>
using namespace GiNaC;

int main(int argc, char** argv)
{
symbol x;
ex e = pow(x, 5);
ex pattern = pow(wild(), -1);
lst repl;
bool test = e.match(pattern, repl);
std::cout << "repl = " << repl << std::endl;
}

prints

repl = {x}

Such behaviour is a bit unexpected. Sometimes it confuses even GiNaC
developers, see e.g.
http://www.ginac.de/pipermail/ginac-devel/2006-April/000942.html

Hence this patch. Now the above program prints

repl = {}

as expected.

doc/tutorial/ginac.texi
ginac/basic.cpp

index eed9fef391386ed71daa9d4c7a6791c359ec8fe3..11c67f91c4e66aa1fdeb6f86f88ff8928244d655 100644 (file)
@@ -4420,10 +4420,7 @@ This function returns @code{true} when the expression matches the pattern
 and @code{false} if it doesn't. If used in the second form, the actual
 subexpressions matched by the wildcards get returned in the @code{repls}
 object as a list of relations of the form @samp{wildcard == expression}.
-If @code{match()} returns false, the state of @code{repls} is undefined.
-For reproducible results, the list should be empty when passed to
-@code{match()}, but it is also possible to find similarities in multiple
-expressions by passing in the result of a previous match.
+If @code{match()} returns false,  @code{repls} remains unmodified.
 
 The matching algorithm works as follows:
 
index a3de04aab9cd306eda820e8d7b50dadc492f3164..7a0633de19a18221f241292b21742416cdb29dce 100644 (file)
@@ -585,12 +585,18 @@ bool basic::match(const ex & pattern, lst & repl_lst) const
                if (!match_same_type(ex_to<basic>(pattern)))
                        return false;
 
+               // Even if the expression does not match the pattern, some of
+               // its subexpressions could match it. For example, x^5*y^(-1)
+               // does not match the pattern $0^5, but its subexpression x^5
+               // does. So, save repl_lst in order to not add bogus entries.
+               lst tmp_repl = repl_lst;
                // Otherwise the subexpressions must match one-to-one
                for (size_t i=0; i<nops(); i++)
-                       if (!op(i).match(pattern.op(i), repl_lst))
+                       if (!op(i).match(pattern.op(i), tmp_repl))
                                return false;
 
                // Looks similar enough, match found
+               repl_lst = tmp_repl;
                return true;
        }
 }