bugfix: function: always pass evalf'ed arguments to evalf_funcp
authorAlexey Sheplyakov <asheplyakov@altlinux.org>
Fri, 1 Jan 2021 16:09:47 +0000 (20:09 +0400)
committerAlexey Sheplyakov <asheplyakov@altlinux.org>
Wed, 6 Jan 2021 13:30:00 +0000 (17:30 +0400)
GiNaC passes unevaluted arguments to a function with evalf_funcp
taking an exvector. Fixed that, and added a test case

check/CMakeLists.txt
check/Makefile.am
check/exam_function_exvector.cpp [new file with mode: 0644]
ginac/function.cppy

index 9ef3a709c8f27edbb0116413f7b31baf65adbd51..768b192b53fc6236e8392dd0c1a5f41d296f00c3 100644 (file)
@@ -27,7 +27,9 @@ set(ginac_exams
        exam_pgcd
        exam_mod_gcd
        exam_real_imag
-       exam_chinrem_gcd)
+       exam_chinrem_gcd
+       exam_function_exvector
+)
 
 set(ginac_checks
        check_numeric
index fd0fd126e1558b56dde3e8b37d97adc84974da38..9f8039ea6957f91a0f3ca282674e1dd3092c1fcc 100644 (file)
@@ -27,6 +27,7 @@ EXAMS = exam_paranoia \
        exam_pgcd \
        exam_mod_gcd \
        exam_chinrem_gcd \
+       exam_function_exvector \
        exam_real_imag
 
 CHECKS = check_numeric \
@@ -149,6 +150,9 @@ exam_real_imag_LDADD = ../ginac/libginac.la
 exam_chinrem_gcd_SOURCES = exam_chinrem_gcd.cpp
 exam_chinrem_gcd_LDADD = ../ginac/libginac.la
 
+exam_function_exvector_SOURCES = exam_function_exvector.cpp
+exam_function_exvector_LDADD = ../ginac/libginac.la
+
 check_numeric_SOURCES = check_numeric.cpp
 check_numeric_LDADD = ../ginac/libginac.la
 
diff --git a/check/exam_function_exvector.cpp b/check/exam_function_exvector.cpp
new file mode 100644 (file)
index 0000000..b5b5d0d
--- /dev/null
@@ -0,0 +1,116 @@
+#ifdef IN_GINAC
+#include "ginac.h"
+#else
+#include "ginac/ginac.h"
+#endif
+
+#include <vector>
+#include <iostream>
+
+using namespace GiNaC;
+using namespace std;
+
+DECLARE_FUNCTION_2P(foobar);
+
+static bool eval_called = false;
+static exvector eval_called_with = {};
+static bool evalf_called = false;
+static exvector evalf_called_with = {};
+
+static void reset() {
+       eval_called_with.clear();
+       evalf_called_with.clear();
+       evalf_called = false;
+       eval_called = false;
+}
+
+static ex foobar_eval(const exvector& args) {
+       eval_called = true;
+       for (auto const& v: args)
+               eval_called_with.push_back(v);
+
+       return foobar(args[0], args[1]).hold();
+}
+
+static ex foobar_evalf(const exvector& args) {
+       evalf_called = true;
+       for (auto const& v: args)
+               evalf_called_with.push_back(v);
+       return foobar(args[0], args[1]).hold();
+}
+
+
+REGISTER_FUNCTION(foobar, eval_func(foobar_eval).
+                         evalf_func(foobar_evalf));
+
+static int check_exvector_eval() {
+       symbol x("x"), y("y");
+       int err = 1;
+
+       reset();
+       ex e = foobar(x, y);
+       if (!eval_called) {
+               clog << "*** Error: " << __func__ << ": foobar_eval hasn't been called" << endl;
+               err *= 2;
+       }
+       if (eval_called_with.size() != 2) {
+               clog << "*** Error: " << __func__ << ": fobar_eval: expected 2 arguments, got " <<
+                       eval_called_with.size() << endl;
+               err *= 3;
+       }
+       if (eval_called_with[0] != x) {
+               clog << "*** Error: " << __func__ << ": fobar_eval: wrong 1st argument, "
+                       "expected " << x << ", got " << eval_called_with[0] << endl;
+               err *= 5;
+       }
+       if (eval_called_with[1] != y) {
+               clog << "*** Error: " << __func__ << ": fobar_eval: wrong 1st argument, "
+                       "expected " << y << ", got " << eval_called_with[1] << endl;
+               err *= 7;
+       }
+       return err - 1;
+}
+
+static int check_exvector_evalf() {
+       int err = 1;
+
+       reset();
+       ex e = foobar(Pi, Euler);
+       e = e.evalf();
+
+       if (!evalf_called) {
+               clog << "*** Error: " << __func__ << ": foobar_evalf hasn't been called" << endl;
+               err *= 2;
+       }
+       if (evalf_called_with.size() != 2) {
+               clog << __func__ << ": foobar_evalf: expected 2 arguments, got " <<
+                       evalf_called_with.size() << endl;
+               err *= 3;
+       }
+       if (!is_a<numeric>(evalf_called_with[0])) {
+               clog << "*** Error: " << __func__ << ": wrong 1st argument of foobar_evalf: "
+                       "expected a real number, got " << evalf_called_with[0] << endl;
+               err *= 5;
+       }
+       if (!is_a<numeric>(evalf_called_with[1])) {
+               clog << "*** Error: " << __func__ << ": wrong 1st argument of foobar_evalf: "
+                       "expected a real number, got " << evalf_called_with[0] << endl;
+               err *= 7;
+       }
+       return err - 1;
+}
+
+int main(int argc, char** argv) {
+       int ret = 0;
+       auto err = check_exvector_evalf();
+       if (err) {
+               ret |= 1;
+               clog << "*** Error " << (err + 1) << " (check_exvector_evalf)" << endl;
+       }
+       err = check_exvector_eval();
+       if (err) { 
+               ret |= 2;
+               clog << "*** Error " << (err + 1) << " (check_exvector_evalf)" << endl;
+       }
+       return ret;
+}
index a7f51acd22a446a2d0a65718ab455a1b3059d1c7..57af323da3d081848e4172a26b70b0c102db8da4 100644 (file)
@@ -437,7 +437,7 @@ ex function::evalf() const
        }
        current_serial = serial;
        if (opt.evalf_use_exvector_args)
-               return ((evalf_funcp_exvector)(opt.evalf_f))(seq);
+               return ((evalf_funcp_exvector)(opt.evalf_f))(eseq);
        switch (opt.nparams) {
                // the following lines have been generated for max. @maxargs@ parameters
 +++ for N in range(1, maxargs + 1):