Browse Source

updated test generator

Konstantin Ladutenko 3 years ago
parent
commit
172b4601ab

+ 136 - 79
tests/mpmath_special_functions_test_generator.py

@@ -2,107 +2,164 @@
 import mpmath as mp
 import mpmath_riccati_bessel as mrb
 import mpmath_input_arguments as mia
+import os.path
 
-class test_data:
-    def __init__(self, list_to_parse):
-        self.evaluated_data = []
+
+class TestData:
+    def __init__(self, list_to_parse, filetype):
+        self.filetype = filetype
+        if self.filetype == 'c++':
+            self.cpp_parse(list_to_parse)
+        else:
+            raise NotImplementedError("Only C++ files *.hpp parsing was implemented")
+
+    def cpp_parse(self, list_to_parse):
         self.comment = list_to_parse[0]
+        print(self.comment)
         if self.comment[:2] != '//': raise ValueError('Not a comment')
+        self.typeline = list_to_parse[1]
+        if 'std::vector' not in self.typeline: raise ValueError('Unexpected C++ container')
+        self.testname = list_to_parse[2]
+        self.opening = list_to_parse[3]
+        if self.opening != '= {': raise ValueError('For C++ we expect opeing with = {');
         self.ending = list_to_parse[-1]
         if self.ending != '};': raise ValueError('For C++ we expect closing };')
-        self.list_to_parse = list_to_parse
+        self.evaluated_data = list_to_parse[4:-1]
+
+    def get_string(self):
+        out_sting = self.comment + '\n' + self.typeline + '\n' + self.testname + '\n' + self.opening + '\n'
+        for result in self.evaluated_data:
+            out_sting += result + '\n'
+        out_sting += self.ending + '\n'
+        return out_sting
 
 
-class update_special_functions_evaluations:
-    def __init__(self, filename='default_out.h', complex_arguments = []):
+class UpdateSpecialFunctionsEvaluations:
+    def __init__(self, filename='default_out.hpp', complex_arguments=[],
+                 output_dps=16, max_num_elements_of_nlist=51):
         self.evaluated_data = []
         self.test_setup = []
         self.filename = filename
+        self.read_evaluated_data()
         self.complex_arguments = complex_arguments
+        self.output_dps = output_dps
+        self.max_num_elements_of_nlist = max_num_elements_of_nlist
 
     def read_evaluated_data(self):
+        self.filetype = 'undefined'
+        if self.filename.endswith('.hpp'):
+            self.filetype = 'c++'
+        if self.filename.endswith('.f90'):
+            self.filetype = 'fortran'
+        if not os.path.exists(self.filename):
+            print("WARNING! Found no data file:", self.filename)
+            return
         with open(self.filename, 'r') as in_file:
             content = in_file.readlines()
         content = [x.strip() for x in content]
         while '' in content:
             record_end_index = content.index('')
             new_record = content[:record_end_index]
-            self.evaluated_data.append(test_data(new_record))
-            content = content[record_end_index+1:]
-        self.evaluated_data.append(test_data(new_record))
-
-
-def get_n_list(z, max_number_of_elements = 10):
-    nmax = mrb.LeRu_cutoff(z)
-    factor = nmax**(1/(max_number_of_elements-2))
-    n_list = [int(factor**i) for i in range(max_number_of_elements-1) ]
-    n_list.append(0)
-    n_set = set(n_list)
-    return sorted(n_set)
-
-
-def get_test_data_nlist(z_record, output_dps, n):
-    x = str(z_record[0])
-    mr = str(z_record[1][0])
-    mi = str(z_record[1][1])
-    z_str = ''
-    try:
-        z = mp.mpf(x)*mp.mpc(mr, mi)
-        D1nz = mrb.D1(n,z)
-        z_str=('{{'+
-                 mp.nstr(z.real, output_dps*2)+','+
-                 mp.nstr(z.imag, output_dps*2)+'},'+
-                 str(n)+',{'+
-                 mp.nstr(D1nz.real, output_dps)+','+
-                 mp.nstr(D1nz.imag, output_dps)+'},'+
-                 mp.nstr(mp.fabs(D1nz.real* 10**-output_dps),2)+',' +
-                 mp.nstr(mp.fabs(D1nz.imag* 10**-output_dps),2)+
-                 '},\n')
-    except:
-        pass
-    return z_str
-
-def get_test_data(Du_test, output_dps, max_num_elements_of_n_list):
-    output_str = ('// complex(z), n, complex(D1(n,z)), abs_err_real, abs_err_imag\n'+
-    'std::vector< std::tuple< std::complex<double>, int, std::complex<double>, double, double > >'+
-    'D1_test_'+str(output_dps)+'digits = {\n')
-    for z_record in Du_test:
+            content = content[record_end_index + 1:]
+            self.add_record(new_record)
+        self.add_record(content)
+
+    def add_record(self, new_record):
+        if len(new_record) == 0: return
+        if len(new_record) < 6: raise ValueError('Not enough lines in record:', new_record)
+        self.evaluated_data.append(TestData(new_record, self.filetype))
+
+
+    def get_file_content(self):
+        self.evaluated_data.sort(key=lambda x: x.testname)#, reverse=True)
+        out_string = ''
+        for record in self.evaluated_data:
+            out_string += record.get_string() + '\n'
+        return out_string[:-1]
+
+    def remove(self, testname):
+        for i, result in enumerate(self.evaluated_data):
+            if result.testname == testname:
+                del self.evaluated_data[i]
+
+    def get_n_list(self, z, max_number_of_elements=10):
+        nmax = mrb.LeRu_cutoff(z)
+        factor = nmax ** (1 / (max_number_of_elements - 2))
+        n_list = [int(factor ** i) for i in range(max_number_of_elements - 1)]
+        n_list.append(0)
+        n_set = set(n_list)
+        return sorted(n_set)
+
+    def get_test_data_nlist(self, z_record, output_dps, n, func):
         x = str(z_record[0])
         mr = str(z_record[1][0])
         mi = str(z_record[1][1])
-        mp.mp.dps = 20
-        z = mp.mpf(x)*mp.mpc(mr, mi)
-        n_list = get_n_list(z, max_num_elements_of_n_list)
-        print(z, n_list)
-        for n in n_list:
+        z_str = ''
+        try:
+            z = mp.mpf(x) * mp.mpc(mr, mi)
+            D1nz = func(n, z)
+            z_str = ('{{' +
+                     mp.nstr(z.real, output_dps * 2) + ',' +
+                     mp.nstr(z.imag, output_dps * 2) + '},' +
+                     str(n) + ',{' +
+                     mp.nstr(D1nz.real, output_dps) + ',' +
+                     mp.nstr(D1nz.imag, output_dps) + '},' +
+                     mp.nstr(mp.fabs(D1nz.real * 10 ** -output_dps), 2) + ',' +
+                     mp.nstr(mp.fabs(D1nz.imag * 10 ** -output_dps), 2) +
+                     '},')
+        except:
+            pass
+        return z_str
+
+    def get_test_data(self, Du_test, output_dps, max_num_elements_of_n_list, func, funcname):
+        output_list = ['// complex(z), n, complex(D1(n,z)), abs_err_real, abs_err_imag',
+        'std::vector< std::tuple< std::complex<double>, int, std::complex<double>, double, double > >',
+        str(funcname)+'_test_' + str(output_dps) + 'digits','= {']
+        for z_record in Du_test:
+            x = str(z_record[0])
+            mr = str(z_record[1][0])
+            mi = str(z_record[1][1])
             mp.mp.dps = 20
-            old_z_string = get_test_data_nlist(z_record, output_dps, n)
-            mp.mp.dps = 37
-            new_z_string = get_test_data_nlist(z_record, output_dps, n)
-            while old_z_string != new_z_string:
-                new_dps = int(mp.mp.dps * 1.41)
-                if new_dps > 300: break
-                mp.mp.dps = new_dps
-                print("New dps = ", mp.mp.dps)
-                old_z_string = new_z_string
-                new_z_string = get_test_data_nlist(z_record, output_dps, n)
-
-            output_str += new_z_string
-    output_str += '};\n'
-    return output_str
-
-
-def main ():
-    sf_evals = update_special_functions_evaluations(filename='test_spec_functions_data.hpp',
-                                                    complex_arguments = mia.complex_arguments)
-    sf_evals.read_evaluated_data()
-    print(sf_evals.evaluated_data[1].list_to_parse)
-    output_dps = 16
-    max_num_elements_of_nlist = 51
-
-    # out_filename = 'test_spec_functions_data.hpp'
-    # output_str = get_test_data(mia.complex_arguments, output_dps, max_num_elements_of_nlist)
-    # with open(out_filename, 'w') as out_file:
-    #     out_file.write(output_str)
+            z = mp.mpf(x) * mp.mpc(mr, mi)
+            n_list = self.get_n_list(z, max_num_elements_of_n_list)
+            print(z, n_list)
+            for n in n_list:
+                mp.mp.dps = 20
+                old_z_string = self.get_test_data_nlist(z_record, output_dps, n, func)
+                mp.mp.dps = 37
+                new_z_string = self.get_test_data_nlist(z_record, output_dps, n, func)
+                while old_z_string != new_z_string:
+                    new_dps = int(mp.mp.dps * 1.41)
+                    if new_dps > 300: break
+                    mp.mp.dps = new_dps
+                    print("New dps = ", mp.mp.dps, 'n =', n, ' (max ',n_list[-1],') for z =', z, '     ', end='')
+                    old_z_string = new_z_string
+                    new_z_string = self.get_test_data_nlist(z_record, output_dps, n, func)
+
+                if new_z_string != '':
+                    output_list.append(new_z_string)
+                else:
+                    break
+        output_list.append('};')
+        return output_list
+
+    def run_test(self, func, funcname):
+        out_list_result = self.get_test_data(mia.complex_arguments, self.output_dps,
+                                             self.max_num_elements_of_nlist,
+                                             func, funcname)
+        testname = str(funcname)+'_test_' + str(self.output_dps) + 'digits'
+        self.remove(testname)
+        self.add_record(out_list_result)
+
+
+def main():
+    sf_evals = UpdateSpecialFunctionsEvaluations(filename='test_spec_functions_data.hpp',
+                                                 complex_arguments=mia.complex_arguments,
+                                                 output_dps=16, max_num_elements_of_nlist=51)
+                                                 # output_dps=3, max_num_elements_of_nlist=3)
+    # sf_evals.run_test(mrb.D1, 'D1')
+    with open(sf_evals.filename, 'w') as out_file:
+        out_file.write(sf_evals.get_file_content())
+
 
 main()

+ 1 - 1
tests/test_Riccati_Bessel_logarithmic_derivative.cc

@@ -1,6 +1,6 @@
 #include "gtest/gtest.h"
 #include "../src/nmie-impl.hpp"
-#include "test_spec_functions_data.h"
+#include "test_spec_functions_data.hpp"
 // From W. Yang APPLIED OPTICS Vol. 42, No. 9,  20 March 2003
 // Dtest refractive index is m={1.05,1}, the size parameter is x = 80
 std::vector<int> Dtest_n({0,1,30,50,60,70,75,80,85,90,99,116,130});

+ 3 - 7
tests/test_spec_functions_data.hpp

@@ -1,5 +1,7 @@
 // complex(z), n, complex(D1(n,z)), abs_err_real, abs_err_imag
-std::vector< std::tuple< std::complex<double>, int, std::complex<double>, double, double > >D1_test_16digits = {
+std::vector< std::tuple< std::complex<double>, int, std::complex<double>, double, double > >
+D1_test_16digits
+= {
 {{0.07425,0.0},0,{13.44325436668153,0.0},1.3e-15,0.0},
 {{0.07425,0.0},1,{26.92117459633998,0.0},2.7e-15,0.0},
 {{0.07425,0.0},2,{40.39343233283062,0.0},4.0e-15,0.0},
@@ -563,9 +565,3 @@ std::vector< std::tuple< std::complex<double>, int, std::complex<double>, double
 {{3.141592653589793,0.0},18,{5.966831036716779,0.0},6.0e-16,0.0},
 {{3.141592653589793,0.0},20,{6.611070983143533,0.0},6.6e-16,0.0},
 };
-
-// complex(z), n, complex(D1(n,z)), abs_err_real, abs_err_imag
-std::vector< std::tuple< std::complex<double>, int, std::complex<double>, double, double > >D1_test_5digits = {
-    {{0.07425, 0.0}, 0, {13.443, 0.0}, 1.3e-3, 0.0},
-    {{7.5, 0.0}, 0, {0.36954, 0.0}, 3.7e-5, 0.0},
-};