[PATCH] Improve normalisation of negative exponents. master
authorVladimir V. Kisil <V.Kisilv@leeds.ac.uk>
Mon, 5 Apr 2021 19:01:30 +0000 (21:01 +0200)
committerRichard Kreckel <kreckel@ginac.de>
Mon, 5 Apr 2021 19:06:45 +0000 (21:06 +0200)
If an expression contains exponents with opposite signs,
then the respective symbolic substitutions need to be properly
attributed to numerator/denominator slots.

check/exam_normalization.cpp
ginac/normal.cpp

index 7ed7464d8b5d167988eaabcf9c25764617309e3d..17cf83db1ea1e83cc37c3db5424ee75edc4a1175 100644 (file)
@@ -252,6 +252,20 @@ static unsigned exam_exponent_law()
                result += check_normal(e, den);
        }
 
+       // Negative exponents
+       e = (exp(2*x)-exp(-2*x))/(exp(x)-exp(-x));
+       ex en = e.normal();
+       // Either exp(x) or exp(-x) can be viewed as a "symbol" during run-time
+       // thus two different forms of the result are possible
+       ex r1 = (exp(2*x)+1)/exp(x) ;
+       ex r2 = (exp(-2*x)+1)/exp(-x);
+
+       if (!en.is_equal(r1) && !en.is_equal(r2)) {
+               clog << "normal form of " << e << " erroneously returned "
+                    << en << " (should be " << r1 << " or " << r2 << ")" << endl;
+               result += 1;
+       }
+
        return result;
 }
 
@@ -305,6 +319,12 @@ static unsigned exam_power_law()
                e /= 2*pow(b, y/2)-3*pow(b, z/2);
                d = 2*pow(b, y/2)+3*pow(b, z/2);
                result += check_normal(e, d);
+
+               // Negative powers
+               e = (b -pow(b,-1));
+               e /= (pow(b, numeric(1,2)) - pow(b, numeric(-1,2)));
+               d = (b+1)*pow(b, numeric(-1,2));
+               result += check_normal(e, d);
        }
 
        return result;
index ce606f0809411286cfef98e0f93df9b4ad5ac7ae..818aa808159a1789c7d577a3f3e7f6b4a6e0ea36 100644 (file)
@@ -2196,14 +2196,18 @@ ex basic::normal(exmap & repl, exmap & rev_lookup, lst & modifier) const
 
        normal_map_function map_normal;
        int nmod = modifier.nops(); // To watch new modifiers to the replacement list
-       lst result = dynallocate<lst>({replace_with_symbol(map(map_normal), repl, rev_lookup, modifier), _ex1});
+       ex result = replace_with_symbol(map(map_normal), repl, rev_lookup, modifier);
        for (int imod = nmod; imod < modifier.nops(); ++imod) {
                exmap this_repl;
                this_repl.insert(std::make_pair(modifier.op(imod).op(0), modifier.op(imod).op(1)));
-               result = ex_to<lst>(result.subs(this_repl, subs_options::no_pattern));
+               result = result.subs(this_repl, subs_options::no_pattern);
        }
 
-       return result;
+       // Sometimes we may obtain negative powers, they need to be placed to denominator
+       if (is_a<power>(result) && result.op(1).info(info_flags::negative))
+               return dynallocate<lst>({_ex1, power(result.op(0), -result.op(1))});
+       else
+               return dynallocate<lst>({result, _ex1});
 }