Skip to content

Commit cb13547

Browse files
authored
managing Complex coefs as input in FZ_ROOTS() (#2153)
I hope the comments will be included too
1 parent 20e570c commit cb13547

File tree

10 files changed

+608
-279
lines changed

10 files changed

+608
-279
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# (at your option) any later version.
88
#
99

10-
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
10+
cmake_minimum_required(VERSION 3.13.3 FATAL_ERROR)
1111

1212
if (NOT EXISTS "${CMAKE_SOURCE_DIR}/src/whereami/.git" )
1313
message(FATAL_ERROR "The src/whereami git submodule is not initialised.\n Please run `git submodule update --init`")

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ plotting_windows.cpp
162162
plotting_xyouts.cpp
163163
plotting.cpp
164164
poly_2d.cpp
165+
polynomial_roots.cpp
165166
print.cpp
166167
print_tree.cpp
167168
prognode.cpp

src/gsl_fun.cpp

Lines changed: 20 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,9 @@
3232
#ifdef _MSC_VER
3333
#include "gtdhelper.hpp" //for gettimeofday()
3434
#else
35-
3635
#include <sys/time.h>
37-
3836
#endif
39-
// ms: must not be inlcuded here
40-
//#include "libinit_ac.cpp"
37+
4138

4239
#include <gsl/gsl_sys.h>
4340
#include <gsl/gsl_linalg.h>
@@ -136,6 +133,25 @@ namespace lib {
136133
gsl_set_error_handler(GDLGenericGSLErrorHandler);
137134
}
138135

136+
137+
// a simple error handler for GSL issuing GDL warning messages
138+
// an initial call (with file=NULL, line=-1 and gsl_errno=-1) sets a prefix to "reason: "
139+
// TODO: merge with the code of NEWTON/BROYDEN/IMSL_HYBRID
140+
void gsl_err_2_gdl_warn(const char *reason, const char *file, int line, int gsl_errno) {
141+
static string prefix;
142+
if (line == -1 && gsl_errno == -1 && file == NULL) prefix = string(reason) + ": ";
143+
else Warning(prefix + "GSL: " + reason);
144+
}
145+
146+
class gsl_err_2_gdl_warn_guard {
147+
gsl_error_handler_t *old_handler;
148+
public:
149+
gsl_err_2_gdl_warn_guard(gsl_error_handler_t *old_handler_) { old_handler = old_handler_; }
150+
151+
~gsl_err_2_gdl_warn_guard() { gsl_set_error_handler(old_handler); }
152+
};
153+
154+
139155
template<typename T1, typename T2>
140156
int cp2data2_template(BaseGDL *p0, T2 *data, SizeT nEl,
141157
SizeT offset, SizeT stride_in, SizeT stride_out) {
@@ -2712,59 +2728,6 @@ namespace lib {
27122728

27132729
}
27142730

2715-
2716-
//FZ_ROOT:compute polynomial roots
2717-
2718-
BaseGDL *fz_roots_fun(EnvT *e) {
2719-
2720-
static int doubleIx = e->KeywordIx("DOUBLE");
2721-
2722-
// Ascending coefficient array
2723-
BaseGDL *p0 = e->GetNumericArrayParDefined(0);
2724-
DDoubleGDL *coef = e->GetParAs<DDoubleGDL>(0);
2725-
2726-
// GSL function
2727-
2728-
if (ComplexType(p0->Type())) {
2729-
e->Throw("Polynomials with complex coefficients not supported yet (FIXME!)");
2730-
}
2731-
2732-
if (coef->N_Elements() < 2) {
2733-
e->Throw("Degree of the polynomial must be strictly greather than zero");
2734-
}
2735-
2736-
for (int i = 0; i < coef->N_Elements(); i++) {
2737-
if (!isfinite((*coef)[i])) e->Throw("Not a number and infinity are not supported");
2738-
}
2739-
2740-
gsl_poly_complex_workspace *w = gsl_poly_complex_workspace_alloc(coef->N_Elements());
2741-
GDLGuard<gsl_poly_complex_workspace> g1(w, gsl_poly_complex_workspace_free);
2742-
2743-
SizeT resultSize = coef->N_Elements() - 1;
2744-
vector<double> tmp(2 * resultSize);
2745-
2746-
gsl_poly_complex_solve(&(*coef)[0], coef->N_Elements(), w, &(tmp[0]));
2747-
2748-
// gsl_poly_complex_workspace_free (w);
2749-
2750-
int debug = 0;
2751-
if (debug) {
2752-
for (int i = 0; i < resultSize; i++) {
2753-
printf("z%d = %+.18f %+.18f\n", i, tmp[2 * i], tmp[2 * i + 1]);
2754-
}
2755-
}
2756-
DComplexDblGDL *result = new DComplexDblGDL(dimension(resultSize), BaseGDL::NOZERO);
2757-
for (SizeT i = 0; i < resultSize; ++i) {
2758-
(*result)[i] = complex<double>(tmp[2 * i], tmp[2 * i + 1]);
2759-
}
2760-
2761-
return result->Convert2(
2762-
e->KeywordSet(doubleIx) || p0->Type() == GDL_DOUBLE
2763-
? GDL_COMPLEXDBL
2764-
: GDL_COMPLEX,
2765-
BaseGDL::CONVERT);
2766-
}
2767-
27682731
//FX_ROOT
27692732

27702733
class fx_root_param {
@@ -3186,22 +3149,6 @@ namespace lib {
31863149
// gsl_wavelet_workspace_guard(gsl_wavelet_workspace* workspace_) { workspace = workspace_; }
31873150
// ~gsl_wavelet_workspace_guard() { gsl_wavelet_workspace_free(workspace); }
31883151
// };
3189-
// a simple error handler for GSL issuing GDL warning messages
3190-
// an initial call (with file=NULL, line=-1 and gsl_errno=-1) sets a prefix to "reason: "
3191-
// TODO: merge with the code of NEWTON/BROYDEN/IMSL_HYBRID
3192-
void gsl_err_2_gdl_warn(const char *reason, const char *file, int line, int gsl_errno) {
3193-
static string prefix;
3194-
if (line == -1 && gsl_errno == -1 && file == NULL) prefix = string(reason) + ": ";
3195-
else Warning(prefix + "GSL: " + reason);
3196-
}
3197-
3198-
class gsl_err_2_gdl_warn_guard {
3199-
gsl_error_handler_t *old_handler;
3200-
public:
3201-
gsl_err_2_gdl_warn_guard(gsl_error_handler_t *old_handler_) { old_handler = old_handler_; }
3202-
3203-
~gsl_err_2_gdl_warn_guard() { gsl_set_error_handler(old_handler); }
3204-
};
32053152

32063153
// SA: 1. Numerical Recipes, and hence IDL as well, calculate the transform until there are
32073154
// two smoothing coefficients left, while GSL leaves out just one, thus:
@@ -3346,60 +3293,6 @@ namespace lib {
33463293
}
33473294

33483295

3349-
// SA: helper class for zeropoly
3350-
// an auto_ptr-like class for guarding the poly_complex_workspace
3351-
// class gsl_poly_complex_workspace_guard
3352-
// {
3353-
// gsl_poly_complex_workspace* workspace;
3354-
// public:
3355-
// gsl_poly_complex_workspace_guard(gsl_poly_complex_workspace* workspace_) { workspace = workspace_; }
3356-
// ~gsl_poly_complex_workspace_guard() { gsl_poly_complex_workspace_free(workspace); }
3357-
// };
3358-
BaseGDL *zeropoly(EnvT *e) {
3359-
static int doubleIx = e->KeywordIx("DOUBLE");
3360-
static int jenkisTraubIx = e->KeywordIx("JENKINS_TRAUB");
3361-
3362-
// SizeT nParam = e->NParam(1);
3363-
if (e->KeywordSet(jenkisTraubIx))
3364-
e->Throw("Jenkins-Traub method not supported yet (FIXME!)");
3365-
3366-
BaseGDL *p0 = e->GetNumericArrayParDefined(0);
3367-
if (ComplexType(p0->Type()))
3368-
e->Throw("Polynomials with complex coefficients not supported yet (FIXME!)");
3369-
if (p0->Rank() != 1)
3370-
e->Throw("The first argument must be a column vector: " + e->GetParString(0));
3371-
DDoubleGDL *coef = e->GetParAs<DDoubleGDL>(0);
3372-
3373-
// GSL error handling
3374-
gsl_error_handler_t *old_handler = gsl_set_error_handler(&gsl_err_2_gdl_warn);
3375-
gsl_err_2_gdl_warn_guard old_handler_guard(old_handler);
3376-
gsl_err_2_gdl_warn(e->GetProName().c_str(), NULL, -1, -1);
3377-
3378-
// initializing complex polynomial workspace
3379-
gsl_poly_complex_workspace *w = gsl_poly_complex_workspace_alloc(coef->N_Elements());
3380-
GDLGuard<gsl_poly_complex_workspace> g1(w, gsl_poly_complex_workspace_free);
3381-
// gsl_poly_complex_workspace_guard w_guard(w);
3382-
3383-
SizeT resultSize = coef->N_Elements() - 1;
3384-
vector<double> tmp(2 * resultSize);
3385-
3386-
if (GSL_SUCCESS != gsl_poly_complex_solve(
3387-
&(*coef)[0], coef->N_Elements(), w, &(tmp[0]))
3388-
)
3389-
e->Throw("Failed to compute the roots of the polynomial");
3390-
3391-
DComplexDblGDL *result = new DComplexDblGDL(dimension(resultSize), BaseGDL::NOZERO);
3392-
for (SizeT i = 0; i < resultSize; ++i)
3393-
(*result)[i] = complex<double>(tmp[2 * i], tmp[2 * i + 1]);
3394-
3395-
return result->Convert2(
3396-
e->KeywordSet(doubleIx) || p0->Type() == GDL_DOUBLE
3397-
? GDL_COMPLEXDBL
3398-
: GDL_COMPLEX,
3399-
BaseGDL::CONVERT
3400-
);
3401-
}
3402-
34033296
// SA: GDL implementation of LEGENDRE uses gsl_sf_legendre_Plm, while SPHER_HARM implem.
34043297
// below uses gsl_sf_legendre_sphPlm which is intended for use with sph. harms
34053298
template<class T_theta, class T_phi, class T_res>

src/gsl_fun.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@
3535
namespace lib {
3636

3737
// BaseGDL* invert_fun( EnvT* e);
38-
// BaseGDL* fft_fun( EnvT* e);
38+
// BaseGDL* fft_fun( EnvT* e);
3939
BaseGDL* random_fun( EnvT* e);
40-
40+
4141
//GD: replaced la_trired from gsl by la_trired from eigen (if eigen is present) as it gives the same results as IDL's LA_TRIRED and is 5 times faster.
4242
#if !defined(USE_EIGEN)
4343
void la_trired_pro( EnvT* e);
@@ -55,10 +55,13 @@ namespace lib {
5555
void inplacemxradixfft(double a[], double b[],
5656
int ntot, int n, int nspan, int isn);
5757

58+
// AC 2025-12-15 : Moved in "polynomial_roots.cpp"
59+
// BaseGDL* fz_roots_fun(EnvT* e);
60+
// BaseGDL* zeropoly(EnvT* e);
61+
5862
// the following by AC
5963
BaseGDL* qromb_fun(EnvT* e);
6064
BaseGDL* qromo_fun(EnvT* e);
61-
BaseGDL* fz_roots_fun(EnvT* e);
6265
BaseGDL* fx_root_fun(EnvT* e);
6366

6467
// the following by SA
@@ -68,7 +71,6 @@ namespace lib {
6871
BaseGDL* constant(EnvT* e);
6972
BaseGDL* binomialcoef(EnvT* e);
7073
BaseGDL* wtn(EnvT* e);
71-
BaseGDL* zeropoly(EnvT* e);
7274
BaseGDL* spher_harm(EnvT* e);
7375
BaseGDL* gaussfit(EnvT* e);
7476
BaseGDL* random_fun_gsl(EnvT* e);

src/libinit.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "file.hpp"
4242

4343
#include "gsl_fun.hpp"
44+
#include "polynomial_roots.hpp"
4445

4546
#include "where.hpp"
4647
#include "convol.hpp"

src/libinit_ac.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
#include "smooth.hpp"
3131

32+
#include "polynomial_roots.hpp"
33+
3234
using namespace std;
3335

3436
void LibInit_ac()

0 commit comments

Comments
 (0)